linux/net/batman-adv/hard-interface.c
<<
>>
Prefs
   1/* Copyright (C) 2007-2012 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 "hard-interface.h"
  22#include "soft-interface.h"
  23#include "send.h"
  24#include "translation-table.h"
  25#include "routing.h"
  26#include "sysfs.h"
  27#include "originator.h"
  28#include "hash.h"
  29#include "bridge_loop_avoidance.h"
  30
  31#include <linux/if_arp.h>
  32
  33void batadv_hardif_free_rcu(struct rcu_head *rcu)
  34{
  35        struct batadv_hard_iface *hard_iface;
  36
  37        hard_iface = container_of(rcu, struct batadv_hard_iface, rcu);
  38        dev_put(hard_iface->net_dev);
  39        kfree(hard_iface);
  40}
  41
  42struct batadv_hard_iface *
  43batadv_hardif_get_by_netdev(const struct net_device *net_dev)
  44{
  45        struct batadv_hard_iface *hard_iface;
  46
  47        rcu_read_lock();
  48        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
  49                if (hard_iface->net_dev == net_dev &&
  50                    atomic_inc_not_zero(&hard_iface->refcount))
  51                        goto out;
  52        }
  53
  54        hard_iface = NULL;
  55
  56out:
  57        rcu_read_unlock();
  58        return hard_iface;
  59}
  60
  61static int batadv_is_valid_iface(const struct net_device *net_dev)
  62{
  63        if (net_dev->flags & IFF_LOOPBACK)
  64                return 0;
  65
  66        if (net_dev->type != ARPHRD_ETHER)
  67                return 0;
  68
  69        if (net_dev->addr_len != ETH_ALEN)
  70                return 0;
  71
  72        /* no batman over batman */
  73        if (batadv_softif_is_valid(net_dev))
  74                return 0;
  75
  76        return 1;
  77}
  78
  79static struct batadv_hard_iface *
  80batadv_hardif_get_active(const struct net_device *soft_iface)
  81{
  82        struct batadv_hard_iface *hard_iface;
  83
  84        rcu_read_lock();
  85        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
  86                if (hard_iface->soft_iface != soft_iface)
  87                        continue;
  88
  89                if (hard_iface->if_status == BATADV_IF_ACTIVE &&
  90                    atomic_inc_not_zero(&hard_iface->refcount))
  91                        goto out;
  92        }
  93
  94        hard_iface = NULL;
  95
  96out:
  97        rcu_read_unlock();
  98        return hard_iface;
  99}
 100
 101static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv,
 102                                          struct batadv_hard_iface *oldif)
 103{
 104        struct batadv_vis_packet *vis_packet;
 105        struct batadv_hard_iface *primary_if;
 106
 107        primary_if = batadv_primary_if_get_selected(bat_priv);
 108        if (!primary_if)
 109                goto out;
 110
 111        vis_packet = (struct batadv_vis_packet *)
 112                                bat_priv->my_vis_info->skb_packet->data;
 113        memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
 114        memcpy(vis_packet->sender_orig,
 115               primary_if->net_dev->dev_addr, ETH_ALEN);
 116
 117        batadv_bla_update_orig_address(bat_priv, primary_if, oldif);
 118out:
 119        if (primary_if)
 120                batadv_hardif_free_ref(primary_if);
 121}
 122
 123static void batadv_primary_if_select(struct batadv_priv *bat_priv,
 124                                     struct batadv_hard_iface *new_hard_iface)
 125{
 126        struct batadv_hard_iface *curr_hard_iface;
 127
 128        ASSERT_RTNL();
 129
 130        if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
 131                new_hard_iface = NULL;
 132
 133        curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
 134        rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
 135
 136        if (!new_hard_iface)
 137                goto out;
 138
 139        bat_priv->bat_algo_ops->bat_primary_iface_set(new_hard_iface);
 140        batadv_primary_if_update_addr(bat_priv, curr_hard_iface);
 141
 142out:
 143        if (curr_hard_iface)
 144                batadv_hardif_free_ref(curr_hard_iface);
 145}
 146
 147static bool
 148batadv_hardif_is_iface_up(const struct batadv_hard_iface *hard_iface)
 149{
 150        if (hard_iface->net_dev->flags & IFF_UP)
 151                return true;
 152
 153        return false;
 154}
 155
 156static void batadv_check_known_mac_addr(const struct net_device *net_dev)
 157{
 158        const struct batadv_hard_iface *hard_iface;
 159
 160        rcu_read_lock();
 161        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 162                if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
 163                    (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
 164                        continue;
 165
 166                if (hard_iface->net_dev == net_dev)
 167                        continue;
 168
 169                if (!batadv_compare_eth(hard_iface->net_dev->dev_addr,
 170                                        net_dev->dev_addr))
 171                        continue;
 172
 173                pr_warn("The newly added mac address (%pM) already exists on: %s\n",
 174                        net_dev->dev_addr, hard_iface->net_dev->name);
 175                pr_warn("It is strongly recommended to keep mac addresses unique to avoid problems!\n");
 176        }
 177        rcu_read_unlock();
 178}
 179
 180int batadv_hardif_min_mtu(struct net_device *soft_iface)
 181{
 182        const struct batadv_priv *bat_priv = netdev_priv(soft_iface);
 183        const struct batadv_hard_iface *hard_iface;
 184        /* allow big frames if all devices are capable to do so
 185         * (have MTU > 1500 + BAT_HEADER_LEN)
 186         */
 187        int min_mtu = ETH_DATA_LEN;
 188
 189        if (atomic_read(&bat_priv->fragmentation))
 190                goto out;
 191
 192        rcu_read_lock();
 193        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 194                if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
 195                    (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
 196                        continue;
 197
 198                if (hard_iface->soft_iface != soft_iface)
 199                        continue;
 200
 201                min_mtu = min_t(int,
 202                                hard_iface->net_dev->mtu - BATADV_HEADER_LEN,
 203                                min_mtu);
 204        }
 205        rcu_read_unlock();
 206out:
 207        return min_mtu;
 208}
 209
 210/* adjusts the MTU if a new interface with a smaller MTU appeared. */
 211void batadv_update_min_mtu(struct net_device *soft_iface)
 212{
 213        int min_mtu;
 214
 215        min_mtu = batadv_hardif_min_mtu(soft_iface);
 216        if (soft_iface->mtu != min_mtu)
 217                soft_iface->mtu = min_mtu;
 218}
 219
 220static void
 221batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
 222{
 223        struct batadv_priv *bat_priv;
 224        struct batadv_hard_iface *primary_if = NULL;
 225
 226        if (hard_iface->if_status != BATADV_IF_INACTIVE)
 227                goto out;
 228
 229        bat_priv = netdev_priv(hard_iface->soft_iface);
 230
 231        bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
 232        hard_iface->if_status = BATADV_IF_TO_BE_ACTIVATED;
 233
 234        /* the first active interface becomes our primary interface or
 235         * the next active interface after the old primary interface was removed
 236         */
 237        primary_if = batadv_primary_if_get_selected(bat_priv);
 238        if (!primary_if)
 239                batadv_primary_if_select(bat_priv, hard_iface);
 240
 241        batadv_info(hard_iface->soft_iface, "Interface activated: %s\n",
 242                    hard_iface->net_dev->name);
 243
 244        batadv_update_min_mtu(hard_iface->soft_iface);
 245
 246out:
 247        if (primary_if)
 248                batadv_hardif_free_ref(primary_if);
 249}
 250
 251static void
 252batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
 253{
 254        if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
 255            (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
 256                return;
 257
 258        hard_iface->if_status = BATADV_IF_INACTIVE;
 259
 260        batadv_info(hard_iface->soft_iface, "Interface deactivated: %s\n",
 261                    hard_iface->net_dev->name);
 262
 263        batadv_update_min_mtu(hard_iface->soft_iface);
 264}
 265
 266int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
 267                                   const char *iface_name)
 268{
 269        struct batadv_priv *bat_priv;
 270        struct net_device *soft_iface;
 271        __be16 ethertype = __constant_htons(BATADV_ETH_P_BATMAN);
 272        int ret;
 273
 274        if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
 275                goto out;
 276
 277        if (!atomic_inc_not_zero(&hard_iface->refcount))
 278                goto out;
 279
 280        /* hard-interface is part of a bridge */
 281        if (hard_iface->net_dev->priv_flags & IFF_BRIDGE_PORT)
 282                pr_err("You are about to enable batman-adv on '%s' which already is part of a bridge. Unless you know exactly what you are doing this is probably wrong and won't work the way you think it would.\n",
 283                       hard_iface->net_dev->name);
 284
 285        soft_iface = dev_get_by_name(&init_net, iface_name);
 286
 287        if (!soft_iface) {
 288                soft_iface = batadv_softif_create(iface_name);
 289
 290                if (!soft_iface) {
 291                        ret = -ENOMEM;
 292                        goto err;
 293                }
 294
 295                /* dev_get_by_name() increases the reference counter for us */
 296                dev_hold(soft_iface);
 297        }
 298
 299        if (!batadv_softif_is_valid(soft_iface)) {
 300                pr_err("Can't create batman mesh interface %s: already exists as regular interface\n",
 301                       soft_iface->name);
 302                ret = -EINVAL;
 303                goto err_dev;
 304        }
 305
 306        hard_iface->soft_iface = soft_iface;
 307        bat_priv = netdev_priv(hard_iface->soft_iface);
 308
 309        ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
 310        if (ret < 0)
 311                goto err_dev;
 312
 313        hard_iface->if_num = bat_priv->num_ifaces;
 314        bat_priv->num_ifaces++;
 315        hard_iface->if_status = BATADV_IF_INACTIVE;
 316        batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
 317
 318        hard_iface->batman_adv_ptype.type = ethertype;
 319        hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
 320        hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
 321        dev_add_pack(&hard_iface->batman_adv_ptype);
 322
 323        atomic_set(&hard_iface->frag_seqno, 1);
 324        batadv_info(hard_iface->soft_iface, "Adding interface: %s\n",
 325                    hard_iface->net_dev->name);
 326
 327        if (atomic_read(&bat_priv->fragmentation) &&
 328            hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
 329                batadv_info(hard_iface->soft_iface,
 330                            "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",
 331                            hard_iface->net_dev->name, hard_iface->net_dev->mtu,
 332                            ETH_DATA_LEN + BATADV_HEADER_LEN);
 333
 334        if (!atomic_read(&bat_priv->fragmentation) &&
 335            hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
 336                batadv_info(hard_iface->soft_iface,
 337                            "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",
 338                            hard_iface->net_dev->name, hard_iface->net_dev->mtu,
 339                            ETH_DATA_LEN + BATADV_HEADER_LEN);
 340
 341        if (batadv_hardif_is_iface_up(hard_iface))
 342                batadv_hardif_activate_interface(hard_iface);
 343        else
 344                batadv_err(hard_iface->soft_iface,
 345                           "Not using interface %s (retrying later): interface not active\n",
 346                           hard_iface->net_dev->name);
 347
 348        /* begin scheduling originator messages on that interface */
 349        batadv_schedule_bat_ogm(hard_iface);
 350
 351out:
 352        return 0;
 353
 354err_dev:
 355        dev_put(soft_iface);
 356err:
 357        batadv_hardif_free_ref(hard_iface);
 358        return ret;
 359}
 360
 361void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
 362{
 363        struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 364        struct batadv_hard_iface *primary_if = NULL;
 365
 366        if (hard_iface->if_status == BATADV_IF_ACTIVE)
 367                batadv_hardif_deactivate_interface(hard_iface);
 368
 369        if (hard_iface->if_status != BATADV_IF_INACTIVE)
 370                goto out;
 371
 372        batadv_info(hard_iface->soft_iface, "Removing interface: %s\n",
 373                    hard_iface->net_dev->name);
 374        dev_remove_pack(&hard_iface->batman_adv_ptype);
 375
 376        bat_priv->num_ifaces--;
 377        batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
 378
 379        primary_if = batadv_primary_if_get_selected(bat_priv);
 380        if (hard_iface == primary_if) {
 381                struct batadv_hard_iface *new_if;
 382
 383                new_if = batadv_hardif_get_active(hard_iface->soft_iface);
 384                batadv_primary_if_select(bat_priv, new_if);
 385
 386                if (new_if)
 387                        batadv_hardif_free_ref(new_if);
 388        }
 389
 390        bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
 391        hard_iface->if_status = BATADV_IF_NOT_IN_USE;
 392
 393        /* delete all references to this hard_iface */
 394        batadv_purge_orig_ref(bat_priv);
 395        batadv_purge_outstanding_packets(bat_priv, hard_iface);
 396        dev_put(hard_iface->soft_iface);
 397
 398        /* nobody uses this interface anymore */
 399        if (!bat_priv->num_ifaces)
 400                batadv_softif_destroy(hard_iface->soft_iface);
 401
 402        hard_iface->soft_iface = NULL;
 403        batadv_hardif_free_ref(hard_iface);
 404
 405out:
 406        if (primary_if)
 407                batadv_hardif_free_ref(primary_if);
 408}
 409
 410static struct batadv_hard_iface *
 411batadv_hardif_add_interface(struct net_device *net_dev)
 412{
 413        struct batadv_hard_iface *hard_iface;
 414        int ret;
 415
 416        ASSERT_RTNL();
 417
 418        ret = batadv_is_valid_iface(net_dev);
 419        if (ret != 1)
 420                goto out;
 421
 422        dev_hold(net_dev);
 423
 424        hard_iface = kmalloc(sizeof(*hard_iface), GFP_ATOMIC);
 425        if (!hard_iface)
 426                goto release_dev;
 427
 428        ret = batadv_sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
 429        if (ret)
 430                goto free_if;
 431
 432        hard_iface->if_num = -1;
 433        hard_iface->net_dev = net_dev;
 434        hard_iface->soft_iface = NULL;
 435        hard_iface->if_status = BATADV_IF_NOT_IN_USE;
 436        INIT_LIST_HEAD(&hard_iface->list);
 437        /* extra reference for return */
 438        atomic_set(&hard_iface->refcount, 2);
 439
 440        batadv_check_known_mac_addr(hard_iface->net_dev);
 441        list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
 442
 443        /* This can't be called via a bat_priv callback because
 444         * we have no bat_priv yet.
 445         */
 446        atomic_set(&hard_iface->seqno, 1);
 447        hard_iface->packet_buff = NULL;
 448
 449        return hard_iface;
 450
 451free_if:
 452        kfree(hard_iface);
 453release_dev:
 454        dev_put(net_dev);
 455out:
 456        return NULL;
 457}
 458
 459static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
 460{
 461        ASSERT_RTNL();
 462
 463        /* first deactivate interface */
 464        if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
 465                batadv_hardif_disable_interface(hard_iface);
 466
 467        if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
 468                return;
 469
 470        hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
 471        batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
 472        batadv_hardif_free_ref(hard_iface);
 473}
 474
 475void batadv_hardif_remove_interfaces(void)
 476{
 477        struct batadv_hard_iface *hard_iface, *hard_iface_tmp;
 478
 479        rtnl_lock();
 480        list_for_each_entry_safe(hard_iface, hard_iface_tmp,
 481                                 &batadv_hardif_list, list) {
 482                list_del_rcu(&hard_iface->list);
 483                batadv_hardif_remove_interface(hard_iface);
 484        }
 485        rtnl_unlock();
 486}
 487
 488static int batadv_hard_if_event(struct notifier_block *this,
 489                                unsigned long event, void *ptr)
 490{
 491        struct net_device *net_dev = ptr;
 492        struct batadv_hard_iface *hard_iface;
 493        struct batadv_hard_iface *primary_if = NULL;
 494        struct batadv_priv *bat_priv;
 495
 496        hard_iface = batadv_hardif_get_by_netdev(net_dev);
 497        if (!hard_iface && event == NETDEV_REGISTER)
 498                hard_iface = batadv_hardif_add_interface(net_dev);
 499
 500        if (!hard_iface)
 501                goto out;
 502
 503        switch (event) {
 504        case NETDEV_UP:
 505                batadv_hardif_activate_interface(hard_iface);
 506                break;
 507        case NETDEV_GOING_DOWN:
 508        case NETDEV_DOWN:
 509                batadv_hardif_deactivate_interface(hard_iface);
 510                break;
 511        case NETDEV_UNREGISTER:
 512                list_del_rcu(&hard_iface->list);
 513
 514                batadv_hardif_remove_interface(hard_iface);
 515                break;
 516        case NETDEV_CHANGEMTU:
 517                if (hard_iface->soft_iface)
 518                        batadv_update_min_mtu(hard_iface->soft_iface);
 519                break;
 520        case NETDEV_CHANGEADDR:
 521                if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
 522                        goto hardif_put;
 523
 524                batadv_check_known_mac_addr(hard_iface->net_dev);
 525
 526                bat_priv = netdev_priv(hard_iface->soft_iface);
 527                bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
 528
 529                primary_if = batadv_primary_if_get_selected(bat_priv);
 530                if (!primary_if)
 531                        goto hardif_put;
 532
 533                if (hard_iface == primary_if)
 534                        batadv_primary_if_update_addr(bat_priv, NULL);
 535                break;
 536        default:
 537                break;
 538        }
 539
 540hardif_put:
 541        batadv_hardif_free_ref(hard_iface);
 542out:
 543        if (primary_if)
 544                batadv_hardif_free_ref(primary_if);
 545        return NOTIFY_DONE;
 546}
 547
 548/* This function returns true if the interface represented by ifindex is a
 549 * 802.11 wireless device
 550 */
 551bool batadv_is_wifi_iface(int ifindex)
 552{
 553        struct net_device *net_device = NULL;
 554        bool ret = false;
 555
 556        if (ifindex == BATADV_NULL_IFINDEX)
 557                goto out;
 558
 559        net_device = dev_get_by_index(&init_net, ifindex);
 560        if (!net_device)
 561                goto out;
 562
 563#ifdef CONFIG_WIRELESS_EXT
 564        /* pre-cfg80211 drivers have to implement WEXT, so it is possible to
 565         * check for wireless_handlers != NULL
 566         */
 567        if (net_device->wireless_handlers)
 568                ret = true;
 569        else
 570#endif
 571                /* cfg80211 drivers have to set ieee80211_ptr */
 572                if (net_device->ieee80211_ptr)
 573                        ret = true;
 574out:
 575        if (net_device)
 576                dev_put(net_device);
 577        return ret;
 578}
 579
 580struct notifier_block batadv_hard_if_notifier = {
 581        .notifier_call = batadv_hard_if_event,
 582};
 583
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.