linux/net/batman-adv/soft-interface.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
   3 *
   4 * Marek Lindner, Simon Wunderlich
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of version 2 of the GNU General Public
   8 * License as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13 * General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18 * 02110-1301, USA
  19 *
  20 */
  21
  22#include "main.h"
  23#include "soft-interface.h"
  24#include "hard-interface.h"
  25#include "routing.h"
  26#include "send.h"
  27#include "bat_debugfs.h"
  28#include "translation-table.h"
  29#include "hash.h"
  30#include "gateway_common.h"
  31#include "gateway_client.h"
  32#include "bat_sysfs.h"
  33#include "originator.h"
  34#include <linux/slab.h>
  35#include <linux/ethtool.h>
  36#include <linux/etherdevice.h>
  37#include <linux/if_vlan.h>
  38#include "unicast.h"
  39
  40
  41static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
  42static void bat_get_drvinfo(struct net_device *dev,
  43                            struct ethtool_drvinfo *info);
  44static u32 bat_get_msglevel(struct net_device *dev);
  45static void bat_set_msglevel(struct net_device *dev, u32 value);
  46static u32 bat_get_link(struct net_device *dev);
  47
  48static const struct ethtool_ops bat_ethtool_ops = {
  49        .get_settings = bat_get_settings,
  50        .get_drvinfo = bat_get_drvinfo,
  51        .get_msglevel = bat_get_msglevel,
  52        .set_msglevel = bat_set_msglevel,
  53        .get_link = bat_get_link,
  54};
  55
  56int my_skb_head_push(struct sk_buff *skb, unsigned int len)
  57{
  58        int result;
  59
  60        /**
  61         * TODO: We must check if we can release all references to non-payload
  62         * data using skb_header_release in our skbs to allow skb_cow_header to
  63         * work optimally. This means that those skbs are not allowed to read
  64         * or write any data which is before the current position of skb->data
  65         * after that call and thus allow other skbs with the same data buffer
  66         * to write freely in that area.
  67         */
  68        result = skb_cow_head(skb, len);
  69        if (result < 0)
  70                return result;
  71
  72        skb_push(skb, len);
  73        return 0;
  74}
  75
  76static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
  77{
  78        if (atomic_dec_and_test(&softif_neigh->refcount))
  79                kfree_rcu(softif_neigh, rcu);
  80}
  81
  82static void softif_neigh_vid_free_rcu(struct rcu_head *rcu)
  83{
  84        struct softif_neigh_vid *softif_neigh_vid;
  85        struct softif_neigh *softif_neigh;
  86        struct hlist_node *node, *node_tmp;
  87        struct bat_priv *bat_priv;
  88
  89        softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu);
  90        bat_priv = softif_neigh_vid->bat_priv;
  91
  92        spin_lock_bh(&bat_priv->softif_neigh_lock);
  93        hlist_for_each_entry_safe(softif_neigh, node, node_tmp,
  94                                  &softif_neigh_vid->softif_neigh_list, list) {
  95                hlist_del_rcu(&softif_neigh->list);
  96                softif_neigh_free_ref(softif_neigh);
  97        }
  98        spin_unlock_bh(&bat_priv->softif_neigh_lock);
  99
 100        kfree(softif_neigh_vid);
 101}
 102
 103static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid)
 104{
 105        if (atomic_dec_and_test(&softif_neigh_vid->refcount))
 106                call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu);
 107}
 108
 109static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv,
 110                                                     short vid)
 111{
 112        struct softif_neigh_vid *softif_neigh_vid;
 113        struct hlist_node *node;
 114
 115        rcu_read_lock();
 116        hlist_for_each_entry_rcu(softif_neigh_vid, node,
 117                                 &bat_priv->softif_neigh_vids, list) {
 118                if (softif_neigh_vid->vid != vid)
 119                        continue;
 120
 121                if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
 122                        continue;
 123
 124                goto out;
 125        }
 126
 127        softif_neigh_vid = kzalloc(sizeof(*softif_neigh_vid), GFP_ATOMIC);
 128        if (!softif_neigh_vid)
 129                goto out;
 130
 131        softif_neigh_vid->vid = vid;
 132        softif_neigh_vid->bat_priv = bat_priv;
 133
 134        /* initialize with 2 - caller decrements counter by one */
 135        atomic_set(&softif_neigh_vid->refcount, 2);
 136        INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list);
 137        INIT_HLIST_NODE(&softif_neigh_vid->list);
 138        spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
 139        hlist_add_head_rcu(&softif_neigh_vid->list,
 140                           &bat_priv->softif_neigh_vids);
 141        spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
 142
 143out:
 144        rcu_read_unlock();
 145        return softif_neigh_vid;
 146}
 147
 148static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
 149                                             const uint8_t *addr, short vid)
 150{
 151        struct softif_neigh_vid *softif_neigh_vid;
 152        struct softif_neigh *softif_neigh = NULL;
 153        struct hlist_node *node;
 154
 155        softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
 156        if (!softif_neigh_vid)
 157                goto out;
 158
 159        rcu_read_lock();
 160        hlist_for_each_entry_rcu(softif_neigh, node,
 161                                 &softif_neigh_vid->softif_neigh_list,
 162                                 list) {
 163                if (!compare_eth(softif_neigh->addr, addr))
 164                        continue;
 165
 166                if (!atomic_inc_not_zero(&softif_neigh->refcount))
 167                        continue;
 168
 169                softif_neigh->last_seen = jiffies;
 170                goto unlock;
 171        }
 172
 173        softif_neigh = kzalloc(sizeof(*softif_neigh), GFP_ATOMIC);
 174        if (!softif_neigh)
 175                goto unlock;
 176
 177        memcpy(softif_neigh->addr, addr, ETH_ALEN);
 178        softif_neigh->last_seen = jiffies;
 179        /* initialize with 2 - caller decrements counter by one */
 180        atomic_set(&softif_neigh->refcount, 2);
 181
 182        INIT_HLIST_NODE(&softif_neigh->list);
 183        spin_lock_bh(&bat_priv->softif_neigh_lock);
 184        hlist_add_head_rcu(&softif_neigh->list,
 185                           &softif_neigh_vid->softif_neigh_list);
 186        spin_unlock_bh(&bat_priv->softif_neigh_lock);
 187
 188unlock:
 189        rcu_read_unlock();
 190out:
 191        if (softif_neigh_vid)
 192                softif_neigh_vid_free_ref(softif_neigh_vid);
 193        return softif_neigh;
 194}
 195
 196static struct softif_neigh *softif_neigh_get_selected(
 197                                struct softif_neigh_vid *softif_neigh_vid)
 198{
 199        struct softif_neigh *softif_neigh;
 200
 201        rcu_read_lock();
 202        softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
 203
 204        if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount))
 205                softif_neigh = NULL;
 206
 207        rcu_read_unlock();
 208        return softif_neigh;
 209}
 210
 211static struct softif_neigh *softif_neigh_vid_get_selected(
 212                                                struct bat_priv *bat_priv,
 213                                                short vid)
 214{
 215        struct softif_neigh_vid *softif_neigh_vid;
 216        struct softif_neigh *softif_neigh = NULL;
 217
 218        softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
 219        if (!softif_neigh_vid)
 220                goto out;
 221
 222        softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
 223out:
 224        if (softif_neigh_vid)
 225                softif_neigh_vid_free_ref(softif_neigh_vid);
 226        return softif_neigh;
 227}
 228
 229static void softif_neigh_vid_select(struct bat_priv *bat_priv,
 230                                    struct softif_neigh *new_neigh,
 231                                    short vid)
 232{
 233        struct softif_neigh_vid *softif_neigh_vid;
 234        struct softif_neigh *curr_neigh;
 235
 236        softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid);
 237        if (!softif_neigh_vid)
 238                goto out;
 239
 240        spin_lock_bh(&bat_priv->softif_neigh_lock);
 241
 242        if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount))
 243                new_neigh = NULL;
 244
 245        curr_neigh = rcu_dereference_protected(softif_neigh_vid->softif_neigh,
 246                                               1);
 247        rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh);
 248
 249        if ((curr_neigh) && (!new_neigh))
 250                bat_dbg(DBG_ROUTES, bat_priv,
 251                        "Removing mesh exit point on vid: %d (prev: %pM).\n",
 252                        vid, curr_neigh->addr);
 253        else if ((curr_neigh) && (new_neigh))
 254                bat_dbg(DBG_ROUTES, bat_priv,
 255                        "Changing mesh exit point on vid: %d from %pM "
 256                        "to %pM.\n", vid, curr_neigh->addr, new_neigh->addr);
 257        else if ((!curr_neigh) && (new_neigh))
 258                bat_dbg(DBG_ROUTES, bat_priv,
 259                        "Setting mesh exit point on vid: %d to %pM.\n",
 260                        vid, new_neigh->addr);
 261
 262        if (curr_neigh)
 263                softif_neigh_free_ref(curr_neigh);
 264
 265        spin_unlock_bh(&bat_priv->softif_neigh_lock);
 266
 267out:
 268        if (softif_neigh_vid)
 269                softif_neigh_vid_free_ref(softif_neigh_vid);
 270}
 271
 272static void softif_neigh_vid_deselect(struct bat_priv *bat_priv,
 273                                      struct softif_neigh_vid *softif_neigh_vid)
 274{
 275        struct softif_neigh *curr_neigh;
 276        struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp;
 277        struct hard_iface *primary_if = NULL;
 278        struct hlist_node *node;
 279
 280        primary_if = primary_if_get_selected(bat_priv);
 281        if (!primary_if)
 282                goto out;
 283
 284        /* find new softif_neigh immediately to avoid temporary loops */
 285        rcu_read_lock();
 286        curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh);
 287
 288        hlist_for_each_entry_rcu(softif_neigh_tmp, node,
 289                                 &softif_neigh_vid->softif_neigh_list,
 290                                 list) {
 291                if (softif_neigh_tmp == curr_neigh)
 292                        continue;
 293
 294                /* we got a neighbor but its mac is 'bigger' than ours  */
 295                if (memcmp(primary_if->net_dev->dev_addr,
 296                           softif_neigh_tmp->addr, ETH_ALEN) < 0)
 297                        continue;
 298
 299                if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount))
 300                        continue;
 301
 302                softif_neigh = softif_neigh_tmp;
 303                goto unlock;
 304        }
 305
 306unlock:
 307        rcu_read_unlock();
 308out:
 309        softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid);
 310
 311        if (primary_if)
 312                hardif_free_ref(primary_if);
 313        if (softif_neigh)
 314                softif_neigh_free_ref(softif_neigh);
 315}
 316
 317int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
 318{
 319        struct net_device *net_dev = (struct net_device *)seq->private;
 320        struct bat_priv *bat_priv = netdev_priv(net_dev);
 321        struct softif_neigh_vid *softif_neigh_vid;
 322        struct softif_neigh *softif_neigh;
 323        struct hard_iface *primary_if;
 324        struct hlist_node *node, *node_tmp;
 325        struct softif_neigh *curr_softif_neigh;
 326        int ret = 0, last_seen_secs, last_seen_msecs;
 327
 328        primary_if = primary_if_get_selected(bat_priv);
 329        if (!primary_if) {
 330                ret = seq_printf(seq, "BATMAN mesh %s disabled - "
 331                                 "please specify interfaces to enable it\n",
 332                                 net_dev->name);
 333                goto out;
 334        }
 335
 336        if (primary_if->if_status != IF_ACTIVE) {
 337                ret = seq_printf(seq, "BATMAN mesh %s "
 338                                 "disabled - primary interface not active\n",
 339                                 net_dev->name);
 340                goto out;
 341        }
 342
 343        seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
 344
 345        rcu_read_lock();
 346        hlist_for_each_entry_rcu(softif_neigh_vid, node,
 347                                 &bat_priv->softif_neigh_vids, list) {
 348                seq_printf(seq, "     %-15s %s on vid: %d\n",
 349                           "Originator", "last-seen", softif_neigh_vid->vid);
 350
 351                curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
 352
 353                hlist_for_each_entry_rcu(softif_neigh, node_tmp,
 354                                         &softif_neigh_vid->softif_neigh_list,
 355                                         list) {
 356                        last_seen_secs = jiffies_to_msecs(jiffies -
 357                                                softif_neigh->last_seen) / 1000;
 358                        last_seen_msecs = jiffies_to_msecs(jiffies -
 359                                                softif_neigh->last_seen) % 1000;
 360                        seq_printf(seq, "%s %pM  %3i.%03is\n",
 361                                   curr_softif_neigh == softif_neigh
 362                                   ? "=>" : "  ", softif_neigh->addr,
 363                                   last_seen_secs, last_seen_msecs);
 364                }
 365
 366                if (curr_softif_neigh)
 367                        softif_neigh_free_ref(curr_softif_neigh);
 368
 369                seq_printf(seq, "\n");
 370        }
 371        rcu_read_unlock();
 372
 373out:
 374        if (primary_if)
 375                hardif_free_ref(primary_if);
 376        return ret;
 377}
 378
 379void softif_neigh_purge(struct bat_priv *bat_priv)
 380{
 381        struct softif_neigh *softif_neigh, *curr_softif_neigh;
 382        struct softif_neigh_vid *softif_neigh_vid;
 383        struct hlist_node *node, *node_tmp, *node_tmp2;
 384        int do_deselect;
 385
 386        rcu_read_lock();
 387        hlist_for_each_entry_rcu(softif_neigh_vid, node,
 388                                 &bat_priv->softif_neigh_vids, list) {
 389                if (!atomic_inc_not_zero(&softif_neigh_vid->refcount))
 390                        continue;
 391
 392                curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid);
 393                do_deselect = 0;
 394
 395                spin_lock_bh(&bat_priv->softif_neigh_lock);
 396                hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2,
 397                                          &softif_neigh_vid->softif_neigh_list,
 398                                          list) {
 399                        if ((!time_after(jiffies, softif_neigh->last_seen +
 400                                msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) &&
 401                            (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE))
 402                                continue;
 403
 404                        if (curr_softif_neigh == softif_neigh) {
 405                                bat_dbg(DBG_ROUTES, bat_priv,
 406                                        "Current mesh exit point on vid: %d "
 407                                        "'%pM' vanished.\n",
 408                                        softif_neigh_vid->vid,
 409                                        softif_neigh->addr);
 410                                do_deselect = 1;
 411                        }
 412
 413                        hlist_del_rcu(&softif_neigh->list);
 414                        softif_neigh_free_ref(softif_neigh);
 415                }
 416                spin_unlock_bh(&bat_priv->softif_neigh_lock);
 417
 418                /* soft_neigh_vid_deselect() needs to acquire the
 419                 * softif_neigh_lock */
 420                if (do_deselect)
 421                        softif_neigh_vid_deselect(bat_priv, softif_neigh_vid);
 422
 423                if (curr_softif_neigh)
 424                        softif_neigh_free_ref(curr_softif_neigh);
 425
 426                softif_neigh_vid_free_ref(softif_neigh_vid);
 427        }
 428        rcu_read_unlock();
 429
 430        spin_lock_bh(&bat_priv->softif_neigh_vid_lock);
 431        hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp,
 432                                  &bat_priv->softif_neigh_vids, list) {
 433                if (!hlist_empty(&softif_neigh_vid->softif_neigh_list))
 434                        continue;
 435
 436                hlist_del_rcu(&softif_neigh_vid->list);
 437                softif_neigh_vid_free_ref(softif_neigh_vid);
 438        }
 439        spin_unlock_bh(&bat_priv->softif_neigh_vid_lock);
 440
 441}
 442
 443static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
 444                               short vid)
 445{
 446        struct bat_priv *bat_priv = netdev_priv(dev);
 447        struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
 448        struct batman_ogm_packet *batman_ogm_packet;
 449        struct softif_neigh *softif_neigh = NULL;
 450        struct hard_iface *primary_if = NULL;
 451        struct softif_neigh *curr_softif_neigh = NULL;
 452
 453        if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
 454                batman_ogm_packet = (struct batman_ogm_packet *)
 455                                        (skb->data + ETH_HLEN + VLAN_HLEN);
 456        else
 457                batman_ogm_packet = (struct batman_ogm_packet *)
 458                                                        (skb->data + ETH_HLEN);
 459
 460        if (batman_ogm_packet->version != COMPAT_VERSION)
 461                goto out;
 462
 463        if (batman_ogm_packet->packet_type != BAT_OGM)
 464                goto out;
 465
 466        if (!(batman_ogm_packet->flags & PRIMARIES_FIRST_HOP))
 467                goto out;
 468
 469        if (is_my_mac(batman_ogm_packet->orig))
 470                goto out;
 471
 472        softif_neigh = softif_neigh_get(bat_priv, batman_ogm_packet->orig, vid);
 473        if (!softif_neigh)
 474                goto out;
 475
 476        curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
 477        if (curr_softif_neigh == softif_neigh)
 478                goto out;
 479
 480        primary_if = primary_if_get_selected(bat_priv);
 481        if (!primary_if)
 482                goto out;
 483
 484        /* we got a neighbor but its mac is 'bigger' than ours  */
 485        if (memcmp(primary_if->net_dev->dev_addr,
 486                   softif_neigh->addr, ETH_ALEN) < 0)
 487                goto out;
 488
 489        /* close own batX device and use softif_neigh as exit node */
 490        if (!curr_softif_neigh) {
 491                softif_neigh_vid_select(bat_priv, softif_neigh, vid);
 492                goto out;
 493        }
 494
 495        /* switch to new 'smallest neighbor' */
 496        if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0)
 497                softif_neigh_vid_select(bat_priv, softif_neigh, vid);
 498
 499out:
 500        kfree_skb(skb);
 501        if (softif_neigh)
 502                softif_neigh_free_ref(softif_neigh);
 503        if (curr_softif_neigh)
 504                softif_neigh_free_ref(curr_softif_neigh);
 505        if (primary_if)
 506                hardif_free_ref(primary_if);
 507        return;
 508}
 509
 510static int interface_open(struct net_device *dev)
 511{
 512        netif_start_queue(dev);
 513        return 0;
 514}
 515
 516static int interface_release(struct net_device *dev)
 517{
 518        netif_stop_queue(dev);
 519        return 0;
 520}
 521
 522static struct net_device_stats *interface_stats(struct net_device *dev)
 523{
 524        struct bat_priv *bat_priv = netdev_priv(dev);
 525        return &bat_priv->stats;
 526}
 527
 528static int interface_set_mac_addr(struct net_device *dev, void *p)
 529{
 530        struct bat_priv *bat_priv = netdev_priv(dev);
 531        struct sockaddr *addr = p;
 532
 533        if (!is_valid_ether_addr(addr->sa_data))
 534                return -EADDRNOTAVAIL;
 535
 536        /* only modify transtable if it has been initialized before */
 537        if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
 538                tt_local_remove(bat_priv, dev->dev_addr,
 539                                "mac address changed", false);
 540                tt_local_add(dev, addr->sa_data, NULL_IFINDEX);
 541        }
 542
 543        memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 544        return 0;
 545}
 546
 547static int interface_change_mtu(struct net_device *dev, int new_mtu)
 548{
 549        /* check ranges */
 550        if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev)))
 551                return -EINVAL;
 552
 553        dev->mtu = new_mtu;
 554
 555        return 0;
 556}
 557
 558static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 559{
 560        struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
 561        struct bat_priv *bat_priv = netdev_priv(soft_iface);
 562        struct hard_iface *primary_if = NULL;
 563        struct bcast_packet *bcast_packet;
 564        struct vlan_ethhdr *vhdr;
 565        struct softif_neigh *curr_softif_neigh = NULL;
 566        unsigned int header_len = 0;
 567        int data_len = skb->len, ret;
 568        short vid = -1;
 569        bool do_bcast = false;
 570
 571        if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
 572                goto dropped;
 573
 574        soft_iface->trans_start = jiffies;
 575
 576        switch (ntohs(ethhdr->h_proto)) {
 577        case ETH_P_8021Q:
 578                vhdr = (struct vlan_ethhdr *)skb->data;
 579                vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
 580
 581                if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN)
 582                        break;
 583
 584                /* fall through */
 585        case ETH_P_BATMAN:
 586                softif_batman_recv(skb, soft_iface, vid);
 587                goto end;
 588        }
 589
 590        /**
 591         * if we have a another chosen mesh exit node in range
 592         * it will transport the packets to the mesh
 593         */
 594        curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
 595        if (curr_softif_neigh)
 596                goto dropped;
 597
 598        /* Register the client MAC in the transtable */
 599        tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
 600
 601        if (is_multicast_ether_addr(ethhdr->h_dest)) {
 602                do_bcast = true;
 603
 604                switch (atomic_read(&bat_priv->gw_mode)) {
 605                case GW_MODE_SERVER:
 606                        /* gateway servers should not send dhcp
 607                         * requests into the mesh */
 608                        ret = gw_is_dhcp_target(skb, &header_len);
 609                        if (ret)
 610                                goto dropped;
 611                        break;
 612                case GW_MODE_CLIENT:
 613                        /* gateway clients should send dhcp requests
 614                         * via unicast to their gateway */
 615                        ret = gw_is_dhcp_target(skb, &header_len);
 616                        if (ret)
 617                                do_bcast = false;
 618                        break;
 619                case GW_MODE_OFF:
 620                default:
 621                        break;
 622                }
 623        }
 624
 625        /* ethernet packet should be broadcasted */
 626        if (do_bcast) {
 627                primary_if = primary_if_get_selected(bat_priv);
 628                if (!primary_if)
 629                        goto dropped;
 630
 631                if (my_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
 632                        goto dropped;
 633
 634                bcast_packet = (struct bcast_packet *)skb->data;
 635                bcast_packet->version = COMPAT_VERSION;
 636                bcast_packet->ttl = TTL;
 637
 638                /* batman packet type: broadcast */
 639                bcast_packet->packet_type = BAT_BCAST;
 640
 641                /* hw address of first interface is the orig mac because only
 642                 * this mac is known throughout the mesh */
 643                memcpy(bcast_packet->orig,
 644                       primary_if->net_dev->dev_addr, ETH_ALEN);
 645
 646                /* set broadcast sequence number */
 647                bcast_packet->seqno =
 648                        htonl(atomic_inc_return(&bat_priv->bcast_seqno));
 649
 650                add_bcast_packet_to_list(bat_priv, skb, 1);
 651
 652                /* a copy is stored in the bcast list, therefore removing
 653                 * the original skb. */
 654                kfree_skb(skb);
 655
 656        /* unicast packet */
 657        } else {
 658                if (atomic_read(&bat_priv->gw_mode) != GW_MODE_OFF) {
 659                        ret = gw_out_of_range(bat_priv, skb, ethhdr);
 660                        if (ret)
 661                                goto dropped;
 662                }
 663
 664                ret = unicast_send_skb(skb, bat_priv);
 665                if (ret != 0)
 666                        goto dropped_freed;
 667        }
 668
 669        bat_priv->stats.tx_packets++;
 670        bat_priv->stats.tx_bytes += data_len;
 671        goto end;
 672
 673dropped:
 674        kfree_skb(skb);
 675dropped_freed:
 676        bat_priv->stats.tx_dropped++;
 677end:
 678        if (curr_softif_neigh)
 679                softif_neigh_free_ref(curr_softif_neigh);
 680        if (primary_if)
 681                hardif_free_ref(primary_if);
 682        return NETDEV_TX_OK;
 683}
 684
 685void interface_rx(struct net_device *soft_iface,
 686                  struct sk_buff *skb, struct hard_iface *recv_if,
 687                  int hdr_size)
 688{
 689        struct bat_priv *bat_priv = netdev_priv(soft_iface);
 690        struct unicast_packet *unicast_packet;
 691        struct ethhdr *ethhdr;
 692        struct vlan_ethhdr *vhdr;
 693        struct softif_neigh *curr_softif_neigh = NULL;
 694        short vid = -1;
 695        int ret;
 696
 697        /* check if enough space is available for pulling, and pull */
 698        if (!pskb_may_pull(skb, hdr_size))
 699                goto dropped;
 700
 701        skb_pull_rcsum(skb, hdr_size);
 702        skb_reset_mac_header(skb);
 703
 704        ethhdr = (struct ethhdr *)skb_mac_header(skb);
 705
 706        switch (ntohs(ethhdr->h_proto)) {
 707        case ETH_P_8021Q:
 708                vhdr = (struct vlan_ethhdr *)skb->data;
 709                vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
 710
 711                if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN)
 712                        break;
 713
 714                /* fall through */
 715        case ETH_P_BATMAN:
 716                goto dropped;
 717        }
 718
 719        /**
 720         * if we have a another chosen mesh exit node in range
 721         * it will transport the packets to the non-mesh network
 722         */
 723        curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid);
 724        if (curr_softif_neigh) {
 725                skb_push(skb, hdr_size);
 726                unicast_packet = (struct unicast_packet *)skb->data;
 727
 728                if ((unicast_packet->packet_type != BAT_UNICAST) &&
 729                    (unicast_packet->packet_type != BAT_UNICAST_FRAG))
 730                        goto dropped;
 731
 732                skb_reset_mac_header(skb);
 733
 734                memcpy(unicast_packet->dest,
 735                       curr_softif_neigh->addr, ETH_ALEN);
 736                ret = route_unicast_packet(skb, recv_if);
 737                if (ret == NET_RX_DROP)
 738                        goto dropped;
 739
 740                goto out;
 741        }
 742
 743        /* skb->dev & skb->pkt_type are set here */
 744        if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
 745                goto dropped;
 746        skb->protocol = eth_type_trans(skb, soft_iface);
 747
 748        /* should not be necessary anymore as we use skb_pull_rcsum()
 749         * TODO: please verify this and remove this TODO
 750         * -- Dec 21st 2009, Simon Wunderlich */
 751
 752/*      skb->ip_summed = CHECKSUM_UNNECESSARY;*/
 753
 754        bat_priv->stats.rx_packets++;
 755        bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr);
 756
 757        soft_iface->last_rx = jiffies;
 758
 759        if (is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
 760                goto dropped;
 761
 762        netif_rx(skb);
 763        goto out;
 764
 765dropped:
 766        kfree_skb(skb);
 767out:
 768        if (curr_softif_neigh)
 769                softif_neigh_free_ref(curr_softif_neigh);
 770        return;
 771}
 772
 773static const struct net_device_ops bat_netdev_ops = {
 774        .ndo_open = interface_open,
 775        .ndo_stop = interface_release,
 776        .ndo_get_stats = interface_stats,
 777        .ndo_set_mac_address = interface_set_mac_addr,
 778        .ndo_change_mtu = interface_change_mtu,
 779        .ndo_start_xmit = interface_tx,
 780        .ndo_validate_addr = eth_validate_addr
 781};
 782
 783static void interface_setup(struct net_device *dev)
 784{
 785        struct bat_priv *priv = netdev_priv(dev);
 786        char dev_addr[ETH_ALEN];
 787
 788        ether_setup(dev);
 789
 790        dev->netdev_ops = &bat_netdev_ops;
 791        dev->destructor = free_netdev;
 792        dev->tx_queue_len = 0;
 793
 794        /**
 795         * can't call min_mtu, because the needed variables
 796         * have not been initialized yet
 797         */
 798        dev->mtu = ETH_DATA_LEN;
 799        /* reserve more space in the skbuff for our header */
 800        dev->hard_header_len = BAT_HEADER_LEN;
 801
 802        /* generate random address */
 803        random_ether_addr(dev_addr);
 804        memcpy(dev->dev_addr, dev_addr, ETH_ALEN);
 805
 806        SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
 807
 808        memset(priv, 0, sizeof(*priv));
 809}
 810
 811struct net_device *softif_create(const char *name)
 812{
 813        struct net_device *soft_iface;
 814        struct bat_priv *bat_priv;
 815        int ret;
 816
 817        soft_iface = alloc_netdev(sizeof(*bat_priv), name, interface_setup);
 818
 819        if (!soft_iface)
 820                goto out;
 821
 822        ret = register_netdevice(soft_iface);
 823        if (ret < 0) {
 824                pr_err("Unable to register the batman interface '%s': %i\n",
 825                       name, ret);
 826                goto free_soft_iface;
 827        }
 828
 829        bat_priv = netdev_priv(soft_iface);
 830
 831        atomic_set(&bat_priv->aggregated_ogms, 1);
 832        atomic_set(&bat_priv->bonding, 0);
 833        atomic_set(&bat_priv->ap_isolation, 0);
 834        atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
 835        atomic_set(&bat_priv->gw_mode, GW_MODE_OFF);
 836        atomic_set(&bat_priv->gw_sel_class, 20);
 837        atomic_set(&bat_priv->gw_bandwidth, 41);
 838        atomic_set(&bat_priv->orig_interval, 1000);
 839        atomic_set(&bat_priv->hop_penalty, 10);
 840        atomic_set(&bat_priv->log_level, 0);
 841        atomic_set(&bat_priv->fragmentation, 1);
 842        atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN);
 843        atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN);
 844
 845        atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
 846        atomic_set(&bat_priv->bcast_seqno, 1);
 847        atomic_set(&bat_priv->ttvn, 0);
 848        atomic_set(&bat_priv->tt_local_changes, 0);
 849        atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
 850
 851        bat_priv->tt_buff = NULL;
 852        bat_priv->tt_buff_len = 0;
 853        bat_priv->tt_poss_change = false;
 854
 855        bat_priv->primary_if = NULL;
 856        bat_priv->num_ifaces = 0;
 857
 858        ret = sysfs_add_meshif(soft_iface);
 859        if (ret < 0)
 860                goto unreg_soft_iface;
 861
 862        ret = debugfs_add_meshif(soft_iface);
 863        if (ret < 0)
 864                goto unreg_sysfs;
 865
 866        ret = mesh_init(soft_iface);
 867        if (ret < 0)
 868                goto unreg_debugfs;
 869
 870        return soft_iface;
 871
 872unreg_debugfs:
 873        debugfs_del_meshif(soft_iface);
 874unreg_sysfs:
 875        sysfs_del_meshif(soft_iface);
 876unreg_soft_iface:
 877        unregister_netdevice(soft_iface);
 878        return NULL;
 879
 880free_soft_iface:
 881        free_netdev(soft_iface);
 882out:
 883        return NULL;
 884}
 885
 886void softif_destroy(struct net_device *soft_iface)
 887{
 888        debugfs_del_meshif(soft_iface);
 889        sysfs_del_meshif(soft_iface);
 890        mesh_free(soft_iface);
 891        unregister_netdevice(soft_iface);
 892}
 893
 894int softif_is_valid(const struct net_device *net_dev)
 895{
 896        if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
 897                return 1;
 898
 899        return 0;
 900}
 901
 902/* ethtool */
 903static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 904{
 905        cmd->supported = 0;
 906        cmd->advertising = 0;
 907        ethtool_cmd_speed_set(cmd, SPEED_10);
 908        cmd->duplex = DUPLEX_FULL;
 909        cmd->port = PORT_TP;
 910        cmd->phy_address = 0;
 911        cmd->transceiver = XCVR_INTERNAL;
 912        cmd->autoneg = AUTONEG_DISABLE;
 913        cmd->maxtxpkt = 0;
 914        cmd->maxrxpkt = 0;
 915
 916        return 0;
 917}
 918
 919static void bat_get_drvinfo(struct net_device *dev,
 920                            struct ethtool_drvinfo *info)
 921{
 922        strcpy(info->driver, "B.A.T.M.A.N. advanced");
 923        strcpy(info->version, SOURCE_VERSION);
 924        strcpy(info->fw_version, "N/A");
 925        strcpy(info->bus_info, "batman");
 926}
 927
 928static u32 bat_get_msglevel(struct net_device *dev)
 929{
 930        return -EOPNOTSUPP;
 931}
 932
 933static void bat_set_msglevel(struct net_device *dev, u32 value)
 934{
 935}
 936
 937static u32 bat_get_link(struct net_device *dev)
 938{
 939        return 1;
 940}
 941
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.