linux/net/batman-adv/hard-interface.c
<<
>>
Prefs
   1/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
   2 *
   3 * Marek Lindner, Simon Wunderlich
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of version 2 of the GNU General Public
   7 * License as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but
  10 * WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12 * General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17 * 02110-1301, USA
  18 */
  19
  20#include "main.h"
  21#include "distributed-arp-table.h"
  22#include "hard-interface.h"
  23#include "soft-interface.h"
  24#include "send.h"
  25#include "translation-table.h"
  26#include "routing.h"
  27#include "sysfs.h"
  28#include "originator.h"
  29#include "hash.h"
  30#include "bridge_loop_avoidance.h"
  31
  32#include <linux/if_arp.h>
  33#include <linux/if_ether.h>
  34
  35void batadv_hardif_free_rcu(struct rcu_head *rcu)
  36{
  37        struct batadv_hard_iface *hard_iface;
  38
  39        hard_iface = container_of(rcu, struct batadv_hard_iface, rcu);
  40        dev_put(hard_iface->net_dev);
  41        kfree(hard_iface);
  42}
  43
  44struct batadv_hard_iface *
  45batadv_hardif_get_by_netdev(const struct net_device *net_dev)
  46{
  47        struct batadv_hard_iface *hard_iface;
  48
  49        rcu_read_lock();
  50        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
  51                if (hard_iface->net_dev == net_dev &&
  52                    atomic_inc_not_zero(&hard_iface->refcount))
  53                        goto out;
  54        }
  55
  56        hard_iface = NULL;
  57
  58out:
  59        rcu_read_unlock();
  60        return hard_iface;
  61}
  62
  63/**
  64 * batadv_is_on_batman_iface - check if a device is a batman iface descendant
  65 * @net_dev: the device to check
  66 *
  67 * If the user creates any virtual device on top of a batman-adv interface, it
  68 * is important to prevent this new interface to be used to create a new mesh
  69 * network (this behaviour would lead to a batman-over-batman configuration).
  70 * This function recursively checks all the fathers of the device passed as
  71 * argument looking for a batman-adv soft interface.
  72 *
  73 * Returns true if the device is descendant of a batman-adv mesh interface (or
  74 * if it is a batman-adv interface itself), false otherwise
  75 */
  76static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
  77{
  78        struct net_device *parent_dev;
  79        bool ret;
  80
  81        /* check if this is a batman-adv mesh interface */
  82        if (batadv_softif_is_valid(net_dev))
  83                return true;
  84
  85        /* no more parents..stop recursion */
  86        if (net_dev->iflink == net_dev->ifindex)
  87                return false;
  88
  89        /* recurse over the parent device */
  90        parent_dev = dev_get_by_index(&init_net, net_dev->iflink);
  91        /* if we got a NULL parent_dev there is something broken.. */
  92        if (WARN(!parent_dev, "Cannot find parent device"))
  93                return false;
  94
  95        ret = batadv_is_on_batman_iface(parent_dev);
  96
  97        if (parent_dev)
  98                dev_put(parent_dev);
  99        return ret;
 100}
 101
 102static int batadv_is_valid_iface(const struct net_device *net_dev)
 103{
 104        if (net_dev->flags & IFF_LOOPBACK)
 105                return 0;
 106
 107        if (net_dev->type != ARPHRD_ETHER)
 108                return 0;
 109
 110        if (net_dev->addr_len != ETH_ALEN)
 111                return 0;
 112
 113        /* no batman over batman */
 114        if (batadv_is_on_batman_iface(net_dev))
 115                return 0;
 116
 117        return 1;
 118}
 119
 120/**
 121 * batadv_is_wifi_netdev - check if the given net_device struct is a wifi
 122 *  interface
 123 * @net_device: the device to check
 124 *
 125 * Returns true if the net device is a 802.11 wireless device, false otherwise.
 126 */
 127static bool batadv_is_wifi_netdev(struct net_device *net_device)
 128{
 129#ifdef CONFIG_WIRELESS_EXT
 130        /* pre-cfg80211 drivers have to implement WEXT, so it is possible to
 131         * check for wireless_handlers != NULL
 132         */
 133        if (net_device->wireless_handlers)
 134                return true;
 135#endif
 136
 137        /* cfg80211 drivers have to set ieee80211_ptr */
 138        if (net_device->ieee80211_ptr)
 139                return true;
 140
 141        return false;
 142}
 143
 144/**
 145 * batadv_is_wifi_iface - check if the given interface represented by ifindex
 146 *  is a wifi interface
 147 * @ifindex: interface index to check
 148 *
 149 * Returns true if the interface represented by ifindex is a 802.11 wireless
 150 * device, false otherwise.
 151 */
 152bool batadv_is_wifi_iface(int ifindex)
 153{
 154        struct net_device *net_device = NULL;
 155        bool ret = false;
 156
 157        if (ifindex == BATADV_NULL_IFINDEX)
 158                goto out;
 159
 160        net_device = dev_get_by_index(&init_net, ifindex);
 161        if (!net_device)
 162                goto out;
 163
 164        ret = batadv_is_wifi_netdev(net_device);
 165
 166out:
 167        if (net_device)
 168                dev_put(net_device);
 169        return ret;
 170}
 171
 172static struct batadv_hard_iface *
 173batadv_hardif_get_active(const struct net_device *soft_iface)
 174{
 175        struct batadv_hard_iface *hard_iface;
 176
 177        rcu_read_lock();
 178        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 179                if (hard_iface->soft_iface != soft_iface)
 180                        continue;
 181
 182                if (hard_iface->if_status == BATADV_IF_ACTIVE &&
 183                    atomic_inc_not_zero(&hard_iface->refcount))
 184                        goto out;
 185        }
 186
 187        hard_iface = NULL;
 188
 189out:
 190        rcu_read_unlock();
 191        return hard_iface;
 192}
 193
 194static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv,
 195                                          struct batadv_hard_iface *oldif)
 196{
 197        struct batadv_vis_packet *vis_packet;
 198        struct batadv_hard_iface *primary_if;
 199        struct sk_buff *skb;
 200
 201        primary_if = batadv_primary_if_get_selected(bat_priv);
 202        if (!primary_if)
 203                goto out;
 204
 205        batadv_dat_init_own_addr(bat_priv, primary_if);
 206
 207        skb = bat_priv->vis.my_info->skb_packet;
 208        vis_packet = (struct batadv_vis_packet *)skb->data;
 209        memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
 210        memcpy(vis_packet->sender_orig,
 211               primary_if->net_dev->dev_addr, ETH_ALEN);
 212
 213        batadv_bla_update_orig_address(bat_priv, primary_if, oldif);
 214out:
 215        if (primary_if)
 216                batadv_hardif_free_ref(primary_if);
 217}
 218
 219static void batadv_primary_if_select(struct batadv_priv *bat_priv,
 220                                     struct batadv_hard_iface *new_hard_iface)
 221{
 222        struct batadv_hard_iface *curr_hard_iface;
 223
 224        ASSERT_RTNL();
 225
 226        if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
 227                new_hard_iface = NULL;
 228
 229        curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
 230        rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
 231
 232        if (!new_hard_iface)
 233                goto out;
 234
 235        bat_priv->bat_algo_ops->bat_primary_iface_set(new_hard_iface);
 236        batadv_primary_if_update_addr(bat_priv, curr_hard_iface);
 237
 238out:
 239        if (curr_hard_iface)
 240                batadv_hardif_free_ref(curr_hard_iface);
 241}
 242
 243static bool
 244batadv_hardif_is_iface_up(const struct batadv_hard_iface *hard_iface)
 245{
 246        if (hard_iface->net_dev->flags & IFF_UP)
 247                return true;
 248
 249        return false;
 250}
 251
 252static void batadv_check_known_mac_addr(const struct net_device *net_dev)
 253{
 254        const struct batadv_hard_iface *hard_iface;
 255
 256        rcu_read_lock();
 257        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 258                if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
 259                    (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
 260                        continue;
 261
 262                if (hard_iface->net_dev == net_dev)
 263                        continue;
 264
 265                if (!batadv_compare_eth(hard_iface->net_dev->dev_addr,
 266                                        net_dev->dev_addr))
 267                        continue;
 268
 269                pr_warn("The newly added mac address (%pM) already exists on: %s\n",
 270                        net_dev->dev_addr, hard_iface->net_dev->name);
 271                pr_warn("It is strongly recommended to keep mac addresses unique to avoid problems!\n");
 272        }
 273        rcu_read_unlock();
 274}
 275
 276int batadv_hardif_min_mtu(struct net_device *soft_iface)
 277{
 278        const struct batadv_priv *bat_priv = netdev_priv(soft_iface);
 279        const struct batadv_hard_iface *hard_iface;
 280        /* allow big frames if all devices are capable to do so
 281         * (have MTU > 1500 + BAT_HEADER_LEN)
 282         */
 283        int min_mtu = ETH_DATA_LEN;
 284
 285        if (atomic_read(&bat_priv->fragmentation))
 286                goto out;
 287
 288        rcu_read_lock();
 289        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 290                if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
 291                    (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
 292                        continue;
 293
 294                if (hard_iface->soft_iface != soft_iface)
 295                        continue;
 296
 297                min_mtu = min_t(int,
 298                                hard_iface->net_dev->mtu - BATADV_HEADER_LEN,
 299                                min_mtu);
 300        }
 301        rcu_read_unlock();
 302out:
 303        return min_mtu;
 304}
 305
 306/* adjusts the MTU if a new interface with a smaller MTU appeared. */
 307void batadv_update_min_mtu(struct net_device *soft_iface)
 308{
 309        int min_mtu;
 310
 311        min_mtu = batadv_hardif_min_mtu(soft_iface);
 312        if (soft_iface->mtu != min_mtu)
 313                soft_iface->mtu = min_mtu;
 314}
 315
 316static void
 317batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
 318{
 319        struct batadv_priv *bat_priv;
 320        struct batadv_hard_iface *primary_if = NULL;
 321
 322        if (hard_iface->if_status != BATADV_IF_INACTIVE)
 323                goto out;
 324
 325        bat_priv = netdev_priv(hard_iface->soft_iface);
 326
 327        bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
 328        hard_iface->if_status = BATADV_IF_TO_BE_ACTIVATED;
 329
 330        /* the first active interface becomes our primary interface or
 331         * the next active interface after the old primary interface was removed
 332         */
 333        primary_if = batadv_primary_if_get_selected(bat_priv);
 334        if (!primary_if)
 335                batadv_primary_if_select(bat_priv, hard_iface);
 336
 337        batadv_info(hard_iface->soft_iface, "Interface activated: %s\n",
 338                    hard_iface->net_dev->name);
 339
 340        batadv_update_min_mtu(hard_iface->soft_iface);
 341
 342out:
 343        if (primary_if)
 344                batadv_hardif_free_ref(primary_if);
 345}
 346
 347static void
 348batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
 349{
 350        if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
 351            (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
 352                return;
 353
 354        hard_iface->if_status = BATADV_IF_INACTIVE;
 355
 356        batadv_info(hard_iface->soft_iface, "Interface deactivated: %s\n",
 357                    hard_iface->net_dev->name);
 358
 359        batadv_update_min_mtu(hard_iface->soft_iface);
 360}
 361
 362/**
 363 * batadv_master_del_slave - remove hard_iface from the current master interface
 364 * @slave: the interface enslaved in another master
 365 * @master: the master from which slave has to be removed
 366 *
 367 * Invoke ndo_del_slave on master passing slave as argument. In this way slave
 368 * is free'd and master can correctly change its internal state.
 369 * Return 0 on success, a negative value representing the error otherwise
 370 */
 371static int batadv_master_del_slave(struct batadv_hard_iface *slave,
 372                                   struct net_device *master)
 373{
 374        int ret;
 375
 376        if (!master)
 377                return 0;
 378
 379        ret = -EBUSY;
 380        if (master->netdev_ops->ndo_del_slave)
 381                ret = master->netdev_ops->ndo_del_slave(master, slave->net_dev);
 382
 383        return ret;
 384}
 385
 386int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
 387                                   const char *iface_name)
 388{
 389        struct batadv_priv *bat_priv;
 390        struct net_device *soft_iface, *master;
 391        __be16 ethertype = __constant_htons(ETH_P_BATMAN);
 392        int ret;
 393
 394        if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
 395                goto out;
 396
 397        if (!atomic_inc_not_zero(&hard_iface->refcount))
 398                goto out;
 399
 400        soft_iface = dev_get_by_name(&init_net, iface_name);
 401
 402        if (!soft_iface) {
 403                soft_iface = batadv_softif_create(iface_name);
 404
 405                if (!soft_iface) {
 406                        ret = -ENOMEM;
 407                        goto err;
 408                }
 409
 410                /* dev_get_by_name() increases the reference counter for us */
 411                dev_hold(soft_iface);
 412        }
 413
 414        if (!batadv_softif_is_valid(soft_iface)) {
 415                pr_err("Can't create batman mesh interface %s: already exists as regular interface\n",
 416                       soft_iface->name);
 417                ret = -EINVAL;
 418                goto err_dev;
 419        }
 420
 421        /* check if the interface is enslaved in another virtual one and
 422         * in that case unlink it first
 423         */
 424        master = netdev_master_upper_dev_get(hard_iface->net_dev);
 425        ret = batadv_master_del_slave(hard_iface, master);
 426        if (ret)
 427                goto err_dev;
 428
 429        hard_iface->soft_iface = soft_iface;
 430        bat_priv = netdev_priv(hard_iface->soft_iface);
 431
 432        ret = netdev_master_upper_dev_link(hard_iface->net_dev, soft_iface);
 433        if (ret)
 434                goto err_dev;
 435
 436        ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
 437        if (ret < 0)
 438                goto err_upper;
 439
 440        hard_iface->if_num = bat_priv->num_ifaces;
 441        bat_priv->num_ifaces++;
 442        hard_iface->if_status = BATADV_IF_INACTIVE;
 443        ret = batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
 444        if (ret < 0) {
 445                bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
 446                bat_priv->num_ifaces--;
 447                hard_iface->if_status = BATADV_IF_NOT_IN_USE;
 448                goto err_upper;
 449        }
 450
 451        hard_iface->batman_adv_ptype.type = ethertype;
 452        hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
 453        hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
 454        dev_add_pack(&hard_iface->batman_adv_ptype);
 455
 456        atomic_set(&hard_iface->frag_seqno, 1);
 457        batadv_info(hard_iface->soft_iface, "Adding interface: %s\n",
 458                    hard_iface->net_dev->name);
 459
 460        if (atomic_read(&bat_priv->fragmentation) &&
 461            hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
 462                batadv_info(hard_iface->soft_iface,
 463                            "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %zi would solve the problem.\n",
 464                            hard_iface->net_dev->name, hard_iface->net_dev->mtu,
 465                            ETH_DATA_LEN + BATADV_HEADER_LEN);
 466
 467        if (!atomic_read(&bat_priv->fragmentation) &&
 468            hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
 469                batadv_info(hard_iface->soft_iface,
 470                            "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %zi.\n",
 471                            hard_iface->net_dev->name, hard_iface->net_dev->mtu,
 472                            ETH_DATA_LEN + BATADV_HEADER_LEN);
 473
 474        if (batadv_hardif_is_iface_up(hard_iface))
 475                batadv_hardif_activate_interface(hard_iface);
 476        else
 477                batadv_err(hard_iface->soft_iface,
 478                           "Not using interface %s (retrying later): interface not active\n",
 479                           hard_iface->net_dev->name);
 480
 481        /* begin scheduling originator messages on that interface */
 482        batadv_schedule_bat_ogm(hard_iface);
 483
 484out:
 485        return 0;
 486
 487err_upper:
 488        netdev_upper_dev_unlink(hard_iface->net_dev, soft_iface);
 489err_dev:
 490        hard_iface->soft_iface = NULL;
 491        dev_put(soft_iface);
 492err:
 493        batadv_hardif_free_ref(hard_iface);
 494        return ret;
 495}
 496
 497void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
 498                                     enum batadv_hard_if_cleanup autodel)
 499{
 500        struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 501        struct batadv_hard_iface *primary_if = NULL;
 502
 503        if (hard_iface->if_status == BATADV_IF_ACTIVE)
 504                batadv_hardif_deactivate_interface(hard_iface);
 505
 506        if (hard_iface->if_status != BATADV_IF_INACTIVE)
 507                goto out;
 508
 509        batadv_info(hard_iface->soft_iface, "Removing interface: %s\n",
 510                    hard_iface->net_dev->name);
 511        dev_remove_pack(&hard_iface->batman_adv_ptype);
 512
 513        bat_priv->num_ifaces--;
 514        batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
 515
 516        primary_if = batadv_primary_if_get_selected(bat_priv);
 517        if (hard_iface == primary_if) {
 518                struct batadv_hard_iface *new_if;
 519
 520                new_if = batadv_hardif_get_active(hard_iface->soft_iface);
 521                batadv_primary_if_select(bat_priv, new_if);
 522
 523                if (new_if)
 524                        batadv_hardif_free_ref(new_if);
 525        }
 526
 527        bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
 528        hard_iface->if_status = BATADV_IF_NOT_IN_USE;
 529
 530        /* delete all references to this hard_iface */
 531        batadv_purge_orig_ref(bat_priv);
 532        batadv_purge_outstanding_packets(bat_priv, hard_iface);
 533        dev_put(hard_iface->soft_iface);
 534
 535        /* nobody uses this interface anymore */
 536        if (!bat_priv->num_ifaces && autodel == BATADV_IF_CLEANUP_AUTO)
 537                batadv_softif_destroy_sysfs(hard_iface->soft_iface);
 538
 539        netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface);
 540        hard_iface->soft_iface = NULL;
 541        batadv_hardif_free_ref(hard_iface);
 542
 543out:
 544        if (primary_if)
 545                batadv_hardif_free_ref(primary_if);
 546}
 547
 548/**
 549 * batadv_hardif_remove_interface_finish - cleans up the remains of a hardif
 550 * @work: work queue item
 551 *
 552 * Free the parts of the hard interface which can not be removed under
 553 * rtnl lock (to prevent deadlock situations).
 554 */
 555static void batadv_hardif_remove_interface_finish(struct work_struct *work)
 556{
 557        struct batadv_hard_iface *hard_iface;
 558
 559        hard_iface = container_of(work, struct batadv_hard_iface,
 560                                  cleanup_work);
 561
 562        batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
 563        batadv_hardif_free_ref(hard_iface);
 564}
 565
 566static struct batadv_hard_iface *
 567batadv_hardif_add_interface(struct net_device *net_dev)
 568{
 569        struct batadv_hard_iface *hard_iface;
 570        int ret;
 571
 572        ASSERT_RTNL();
 573
 574        ret = batadv_is_valid_iface(net_dev);
 575        if (ret != 1)
 576                goto out;
 577
 578        dev_hold(net_dev);
 579
 580        hard_iface = kzalloc(sizeof(*hard_iface), GFP_ATOMIC);
 581        if (!hard_iface)
 582                goto release_dev;
 583
 584        ret = batadv_sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
 585        if (ret)
 586                goto free_if;
 587
 588        hard_iface->if_num = -1;
 589        hard_iface->net_dev = net_dev;
 590        hard_iface->soft_iface = NULL;
 591        hard_iface->if_status = BATADV_IF_NOT_IN_USE;
 592        INIT_LIST_HEAD(&hard_iface->list);
 593        INIT_WORK(&hard_iface->cleanup_work,
 594                  batadv_hardif_remove_interface_finish);
 595
 596        hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
 597        if (batadv_is_wifi_netdev(net_dev))
 598                hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
 599
 600        /* extra reference for return */
 601        atomic_set(&hard_iface->refcount, 2);
 602
 603        batadv_check_known_mac_addr(hard_iface->net_dev);
 604        list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
 605
 606        return hard_iface;
 607
 608free_if:
 609        kfree(hard_iface);
 610release_dev:
 611        dev_put(net_dev);
 612out:
 613        return NULL;
 614}
 615
 616static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
 617{
 618        ASSERT_RTNL();
 619
 620        /* first deactivate interface */
 621        if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
 622                batadv_hardif_disable_interface(hard_iface,
 623                                                BATADV_IF_CLEANUP_AUTO);
 624
 625        if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
 626                return;
 627
 628        hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
 629        queue_work(batadv_event_workqueue, &hard_iface->cleanup_work);
 630}
 631
 632void batadv_hardif_remove_interfaces(void)
 633{
 634        struct batadv_hard_iface *hard_iface, *hard_iface_tmp;
 635
 636        rtnl_lock();
 637        list_for_each_entry_safe(hard_iface, hard_iface_tmp,
 638                                 &batadv_hardif_list, list) {
 639                list_del_rcu(&hard_iface->list);
 640                batadv_hardif_remove_interface(hard_iface);
 641        }
 642        rtnl_unlock();
 643}
 644
 645static int batadv_hard_if_event(struct notifier_block *this,
 646                                unsigned long event, void *ptr)
 647{
 648        struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
 649        struct batadv_hard_iface *hard_iface;
 650        struct batadv_hard_iface *primary_if = NULL;
 651        struct batadv_priv *bat_priv;
 652
 653        if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) {
 654                batadv_sysfs_add_meshif(net_dev);
 655                return NOTIFY_DONE;
 656        }
 657
 658        hard_iface = batadv_hardif_get_by_netdev(net_dev);
 659        if (!hard_iface && event == NETDEV_REGISTER)
 660                hard_iface = batadv_hardif_add_interface(net_dev);
 661
 662        if (!hard_iface)
 663                goto out;
 664
 665        switch (event) {
 666        case NETDEV_UP:
 667                batadv_hardif_activate_interface(hard_iface);
 668                break;
 669        case NETDEV_GOING_DOWN:
 670        case NETDEV_DOWN:
 671                batadv_hardif_deactivate_interface(hard_iface);
 672                break;
 673        case NETDEV_UNREGISTER:
 674                list_del_rcu(&hard_iface->list);
 675
 676                batadv_hardif_remove_interface(hard_iface);
 677                break;
 678        case NETDEV_CHANGEMTU:
 679                if (hard_iface->soft_iface)
 680                        batadv_update_min_mtu(hard_iface->soft_iface);
 681                break;
 682        case NETDEV_CHANGEADDR:
 683                if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
 684                        goto hardif_put;
 685
 686                batadv_check_known_mac_addr(hard_iface->net_dev);
 687
 688                bat_priv = netdev_priv(hard_iface->soft_iface);
 689                bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
 690
 691                primary_if = batadv_primary_if_get_selected(bat_priv);
 692                if (!primary_if)
 693                        goto hardif_put;
 694
 695                if (hard_iface == primary_if)
 696                        batadv_primary_if_update_addr(bat_priv, NULL);
 697                break;
 698        default:
 699                break;
 700        }
 701
 702hardif_put:
 703        batadv_hardif_free_ref(hard_iface);
 704out:
 705        if (primary_if)
 706                batadv_hardif_free_ref(primary_if);
 707        return NOTIFY_DONE;
 708}
 709
 710struct notifier_block batadv_hard_if_notifier = {
 711        .notifier_call = batadv_hard_if_event,
 712};
 713