]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge
authorDavid S. Miller <davem@davemloft.net>
Wed, 16 Dec 2015 16:09:40 +0000 (11:09 -0500)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Dec 2015 16:09:40 +0000 (11:09 -0500)
Antonio Quartulli says:

====================
Included changes:
- change my email in MAINTAINERS and Doc files
- create and export list of single hop neighs per interface
- protect CRC in the BLA code by means of its own lock
- minor fixes and code cleanups
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
13 files changed:
Documentation/ABI/testing/sysfs-class-net-mesh
MAINTAINERS
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/debugfs.c
net/batman-adv/fragmentation.c
net/batman-adv/hard-interface.c
net/batman-adv/main.c
net/batman-adv/originator.c
net/batman-adv/originator.h
net/batman-adv/routing.c
net/batman-adv/translation-table.c
net/batman-adv/types.h

index c464062966317b71838454a5de532095f4027851..c2b956d44a9520d276b7f13ee3d2617991127a5a 100644 (file)
@@ -8,7 +8,7 @@ Description:
 
 What:           /sys/class/net/<mesh_iface>/mesh/<vlan_subdir>/ap_isolation
 Date:           May 2011
-Contact:        Antonio Quartulli <antonio@meshcoding.com>
+Contact:        Antonio Quartulli <a@unstable.cc>
 Description:
                 Indicates whether the data traffic going from a
                 wireless client to another wireless client will be
@@ -70,7 +70,7 @@ Description:
 
 What:          /sys/class/net/<mesh_iface>/mesh/isolation_mark
 Date:          Nov 2013
-Contact:       Antonio Quartulli <antonio@meshcoding.com>
+Contact:       Antonio Quartulli <a@unstable.cc>
 Description:
                Defines the isolation mark (and its bitmask) which
                is used to classify clients as "isolated" by the
index 04e8d181b44c55c78ef2f57f25ae268e33ebfa5b..2bd095be19d24c8d56aa2087fc4a0ccff8ee2503 100644 (file)
@@ -2111,7 +2111,7 @@ F:        include/linux/backlight.h
 BATMAN ADVANCED
 M:     Marek Lindner <mareklindner@neomailbox.ch>
 M:     Simon Wunderlich <sw@simonwunderlich.de>
-M:     Antonio Quartulli <antonio@meshcoding.com>
+M:     Antonio Quartulli <a@unstable.cc>
 L:     b.a.t.m.a.n@lists.open-mesh.org
 W:     http://www.open-mesh.org/
 S:     Maintained
index 912d9c36fb1c9e63d1358bd044f5a0218f2f4d77..5677169c1b98a235974f3eb7a0d0afe71e49ca08 100644 (file)
@@ -1379,6 +1379,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
                                struct batadv_hard_iface *if_outgoing)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+       struct batadv_hardif_neigh_node *hardif_neigh = NULL;
        struct batadv_neigh_node *router = NULL;
        struct batadv_neigh_node *router_router = NULL;
        struct batadv_orig_node *orig_neigh_node;
@@ -1423,6 +1424,13 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
                goto out;
        }
 
+       if (is_single_hop_neigh) {
+               hardif_neigh = batadv_hardif_neigh_get(if_incoming,
+                                                      ethhdr->h_source);
+               if (hardif_neigh)
+                       hardif_neigh->last_seen = jiffies;
+       }
+
        router = batadv_orig_router_get(orig_node, if_outgoing);
        if (router) {
                router_router = batadv_orig_router_get(router->orig_node,
@@ -1557,6 +1565,8 @@ out:
                batadv_neigh_node_free_ref(router_router);
        if (orig_neigh_router)
                batadv_neigh_node_free_ref(orig_neigh_router);
+       if (hardif_neigh)
+               batadv_hardif_neigh_free_ref(hardif_neigh);
 
        kfree_skb(skb_priv);
 }
@@ -1861,6 +1871,58 @@ next:
                seq_puts(seq, "No batman nodes in range ...\n");
 }
 
+/**
+ * batadv_iv_hardif_neigh_print - print a single hop neighbour node
+ * @seq: neighbour table seq_file struct
+ * @hardif_neigh: hardif neighbour information
+ */
+static void
+batadv_iv_hardif_neigh_print(struct seq_file *seq,
+                            struct batadv_hardif_neigh_node *hardif_neigh)
+{
+       int last_secs, last_msecs;
+
+       last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000;
+       last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000;
+
+       seq_printf(seq, "   %10s   %pM %4i.%03is\n",
+                  hardif_neigh->if_incoming->net_dev->name,
+                  hardif_neigh->addr, last_secs, last_msecs);
+}
+
+/**
+ * batadv_iv_ogm_neigh_print - print the single hop neighbour list
+ * @bat_priv: the bat priv with all the soft interface information
+ * @seq: neighbour table seq_file struct
+ */
+static void batadv_iv_neigh_print(struct batadv_priv *bat_priv,
+                                 struct seq_file *seq)
+{
+       struct net_device *net_dev = (struct net_device *)seq->private;
+       struct batadv_hardif_neigh_node *hardif_neigh;
+       struct batadv_hard_iface *hard_iface;
+       int batman_count = 0;
+
+       seq_printf(seq, "   %10s        %-13s %s\n",
+                  "IF", "Neighbor", "last-seen");
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+               if (hard_iface->soft_iface != net_dev)
+                       continue;
+
+               hlist_for_each_entry_rcu(hardif_neigh,
+                                        &hard_iface->neigh_list, list) {
+                       batadv_iv_hardif_neigh_print(seq, hardif_neigh);
+                       batman_count++;
+               }
+       }
+       rcu_read_unlock();
+
+       if (batman_count == 0)
+               seq_puts(seq, "No batman nodes in range ...\n");
+}
+
 /**
  * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors
  * @neigh1: the first neighbor object of the comparison
@@ -1902,8 +1964,8 @@ out:
 }
 
 /**
- * batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than
- *  neigh2 from the metric prospective
+ * batadv_iv_ogm_neigh_is_sob - check if neigh1 is similarly good or better
+ *  than neigh2 from the metric prospective
  * @neigh1: the first neighbor object of the comparison
  * @if_outgoing1: outgoing interface for the first neighbor
  * @neigh2: the second neighbor object of the comparison
@@ -1913,7 +1975,7 @@ out:
  * the metric via neigh2, false otherwise.
  */
 static bool
-batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
+batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
                           struct batadv_hard_iface *if_outgoing1,
                           struct batadv_neigh_node *neigh2,
                           struct batadv_hard_iface *if_outgoing2)
@@ -1953,7 +2015,8 @@ static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
        .bat_ogm_schedule = batadv_iv_ogm_schedule,
        .bat_ogm_emit = batadv_iv_ogm_emit,
        .bat_neigh_cmp = batadv_iv_ogm_neigh_cmp,
-       .bat_neigh_is_equiv_or_better = batadv_iv_ogm_neigh_is_eob,
+       .bat_neigh_is_similar_or_better = batadv_iv_ogm_neigh_is_sob,
+       .bat_neigh_print = batadv_iv_neigh_print,
        .bat_orig_print = batadv_iv_ogm_orig_print,
        .bat_orig_free = batadv_iv_ogm_orig_free,
        .bat_orig_add_if = batadv_iv_ogm_orig_add_if,
index 191a70290dca2ae15af2ec31845c3b4ed8dad37c..99dcae316ec89c01dc8342084ff48477139584bc 100644 (file)
@@ -260,7 +260,9 @@ batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw)
        }
 
        /* all claims gone, initialize CRC */
+       spin_lock_bh(&backbone_gw->crc_lock);
        backbone_gw->crc = BATADV_BLA_CRC_INIT;
+       spin_unlock_bh(&backbone_gw->crc_lock);
 }
 
 /**
@@ -408,6 +410,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, u8 *orig,
        entry->lasttime = jiffies;
        entry->crc = BATADV_BLA_CRC_INIT;
        entry->bat_priv = bat_priv;
+       spin_lock_init(&entry->crc_lock);
        atomic_set(&entry->request_sent, 0);
        atomic_set(&entry->wait_periods, 0);
        ether_addr_copy(entry->orig, orig);
@@ -557,7 +560,9 @@ static void batadv_bla_send_announce(struct batadv_priv *bat_priv,
        __be16 crc;
 
        memcpy(mac, batadv_announce_mac, 4);
+       spin_lock_bh(&backbone_gw->crc_lock);
        crc = htons(backbone_gw->crc);
+       spin_unlock_bh(&backbone_gw->crc_lock);
        memcpy(&mac[4], &crc, 2);
 
        batadv_bla_send_claim(bat_priv, mac, backbone_gw->vid,
@@ -618,14 +623,18 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
                           "bla_add_claim(): changing ownership for %pM, vid %d\n",
                           mac, BATADV_PRINT_VID(vid));
 
+               spin_lock_bh(&claim->backbone_gw->crc_lock);
                claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
+               spin_unlock_bh(&claim->backbone_gw->crc_lock);
                batadv_backbone_gw_free_ref(claim->backbone_gw);
        }
        /* set (new) backbone gw */
        atomic_inc(&backbone_gw->refcount);
        claim->backbone_gw = backbone_gw;
 
+       spin_lock_bh(&backbone_gw->crc_lock);
        backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
+       spin_unlock_bh(&backbone_gw->crc_lock);
        backbone_gw->lasttime = jiffies;
 
 claim_free_ref:
@@ -653,7 +662,9 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv,
                           batadv_choose_claim, claim);
        batadv_claim_free_ref(claim); /* reference from the hash is gone */
 
+       spin_lock_bh(&claim->backbone_gw->crc_lock);
        claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
+       spin_unlock_bh(&claim->backbone_gw->crc_lock);
 
        /* don't need the reference from hash_find() anymore */
        batadv_claim_free_ref(claim);
@@ -664,7 +675,7 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
                                  u8 *backbone_addr, unsigned short vid)
 {
        struct batadv_bla_backbone_gw *backbone_gw;
-       u16 crc;
+       u16 backbone_crc, crc;
 
        if (memcmp(an_addr, batadv_announce_mac, 4) != 0)
                return 0;
@@ -683,12 +694,16 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
                   "handle_announce(): ANNOUNCE vid %d (sent by %pM)... CRC = %#.4x\n",
                   BATADV_PRINT_VID(vid), backbone_gw->orig, crc);
 
-       if (backbone_gw->crc != crc) {
+       spin_lock_bh(&backbone_gw->crc_lock);
+       backbone_crc = backbone_gw->crc;
+       spin_unlock_bh(&backbone_gw->crc_lock);
+
+       if (backbone_crc != crc) {
                batadv_dbg(BATADV_DBG_BLA, backbone_gw->bat_priv,
                           "handle_announce(): CRC FAILED for %pM/%d (my = %#.4x, sent = %#.4x)\n",
                           backbone_gw->orig,
                           BATADV_PRINT_VID(backbone_gw->vid),
-                          backbone_gw->crc, crc);
+                          backbone_crc, crc);
 
                batadv_bla_send_request(backbone_gw);
        } else {
@@ -1647,6 +1662,7 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
        struct batadv_bla_claim *claim;
        struct batadv_hard_iface *primary_if;
        struct hlist_head *head;
+       u16 backbone_crc;
        u32 i;
        bool is_own;
        u8 *primary_addr;
@@ -1669,11 +1685,15 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
                hlist_for_each_entry_rcu(claim, head, hash_entry) {
                        is_own = batadv_compare_eth(claim->backbone_gw->orig,
                                                    primary_addr);
+
+                       spin_lock_bh(&claim->backbone_gw->crc_lock);
+                       backbone_crc = claim->backbone_gw->crc;
+                       spin_unlock_bh(&claim->backbone_gw->crc_lock);
                        seq_printf(seq, " * %pM on %5d by %pM [%c] (%#.4x)\n",
                                   claim->addr, BATADV_PRINT_VID(claim->vid),
                                   claim->backbone_gw->orig,
                                   (is_own ? 'x' : ' '),
-                                  claim->backbone_gw->crc);
+                                  backbone_crc);
                }
                rcu_read_unlock();
        }
@@ -1692,6 +1712,7 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset)
        struct batadv_hard_iface *primary_if;
        struct hlist_head *head;
        int secs, msecs;
+       u16 backbone_crc;
        u32 i;
        bool is_own;
        u8 *primary_addr;
@@ -1722,10 +1743,14 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset)
                        if (is_own)
                                continue;
 
+                       spin_lock_bh(&backbone_gw->crc_lock);
+                       backbone_crc = backbone_gw->crc;
+                       spin_unlock_bh(&backbone_gw->crc_lock);
+
                        seq_printf(seq, " * %pM on %5d %4i.%03is (%#.4x)\n",
                                   backbone_gw->orig,
                                   BATADV_PRINT_VID(backbone_gw->vid), secs,
-                                  msecs, backbone_gw->crc);
+                                  msecs, backbone_crc);
                }
                rcu_read_unlock();
        }
index c4c1e8030ba02f8837100da3b6affafded5d6744..037ad0a5f485e133a571aeea8d1d9534730612e9 100644 (file)
@@ -262,6 +262,13 @@ static int batadv_algorithms_open(struct inode *inode, struct file *file)
        return single_open(file, batadv_algo_seq_print_text, NULL);
 }
 
+static int neighbors_open(struct inode *inode, struct file *file)
+{
+       struct net_device *net_dev = (struct net_device *)inode->i_private;
+
+       return single_open(file, batadv_hardif_neigh_seq_print_text, net_dev);
+}
+
 static int batadv_originators_open(struct inode *inode, struct file *file)
 {
        struct net_device *net_dev = (struct net_device *)inode->i_private;
@@ -375,6 +382,7 @@ static struct batadv_debuginfo *batadv_general_debuginfos[] = {
 };
 
 /* The following attributes are per soft interface */
+static BATADV_DEBUGINFO(neighbors, S_IRUGO, neighbors_open);
 static BATADV_DEBUGINFO(originators, S_IRUGO, batadv_originators_open);
 static BATADV_DEBUGINFO(gateways, S_IRUGO, batadv_gateways_open);
 static BATADV_DEBUGINFO(transtable_global, S_IRUGO,
@@ -394,6 +402,7 @@ static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open);
 #endif
 
 static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
+       &batadv_debuginfo_neighbors,
        &batadv_debuginfo_originators,
        &batadv_debuginfo_gateways,
        &batadv_debuginfo_transtable_global,
index 700c96c82a15100fca157d9b14ba5157430d024b..20d9282f895b2d3115f056f09b81090b5d0956a0 100644 (file)
@@ -71,14 +71,14 @@ void batadv_frag_purge_orig(struct batadv_orig_node *orig_node,
 
        for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) {
                chain = &orig_node->fragments[i];
-               spin_lock_bh(&orig_node->fragments[i].lock);
+               spin_lock_bh(&chain->lock);
 
                if (!check_cb || check_cb(chain)) {
-                       batadv_frag_clear_chain(&orig_node->fragments[i].head);
-                       orig_node->fragments[i].size = 0;
+                       batadv_frag_clear_chain(&chain->head);
+                       chain->size = 0;
                }
 
-               spin_unlock_bh(&orig_node->fragments[i].lock);
+               spin_unlock_bh(&chain->lock);
        }
 }
 
index a58184fdf5fdc496d33527eb99396376c737bc2e..01acccc4d2185806ae6dd37b2f0f091d9a0b92a0 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/rculist.h>
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <net/net_namespace.h>
 
@@ -639,9 +640,12 @@ batadv_hardif_add_interface(struct net_device *net_dev)
                goto free_sysfs;
 
        INIT_LIST_HEAD(&hard_iface->list);
+       INIT_HLIST_HEAD(&hard_iface->neigh_list);
        INIT_WORK(&hard_iface->cleanup_work,
                  batadv_hardif_remove_interface_finish);
 
+       spin_lock_init(&hard_iface->neigh_list_lock);
+
        hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
        if (batadv_is_wifi_netdev(net_dev))
                hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
index d7f17c1aa4a4bd75014c27443175cc9afc92f8df..5dbcb2e2b497ce7eb47821aa7ddea3ebb64060f3 100644 (file)
@@ -552,7 +552,7 @@ int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops)
            !bat_algo_ops->bat_ogm_schedule ||
            !bat_algo_ops->bat_ogm_emit ||
            !bat_algo_ops->bat_neigh_cmp ||
-           !bat_algo_ops->bat_neigh_is_equiv_or_better) {
+           !bat_algo_ops->bat_neigh_is_similar_or_better) {
                pr_info("Routing algo '%s' does not implement required ops\n",
                        bat_algo_ops->name);
                return -EINVAL;
@@ -908,7 +908,7 @@ end:
  *  appropriate handlers
  * @bat_priv: the bat priv with all the soft interface information
  * @tvlv_handler: tvlv callback function handling the tvlv content
- * @ogm_source: flag indicating wether the tvlv is an ogm or a unicast packet
+ * @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet
  * @orig_node: orig node emitting the ogm packet
  * @src: source mac address of the unicast packet
  * @dst: destination mac address of the unicast packet
@@ -961,7 +961,7 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
  * batadv_tvlv_containers_process - parse the given tvlv buffer to call the
  *  appropriate handlers
  * @bat_priv: the bat priv with all the soft interface information
- * @ogm_source: flag indicating wether the tvlv is an ogm or a unicast packet
+ * @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet
  * @orig_node: orig node emitting the ogm packet
  * @src: source mac address of the unicast packet
  * @dst: destination mac address of the unicast packet
index 7486df9ed48dbcaaf7ab039767ad38777584cd28..3c782a33bdac58cdb52c7e381b1a37c71e77a67b 100644 (file)
@@ -201,6 +201,47 @@ void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo)
                call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu);
 }
 
+/**
+ * batadv_hardif_neigh_free_rcu - free the hardif neigh_node
+ * @rcu: rcu pointer of the neigh_node
+ */
+static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu)
+{
+       struct batadv_hardif_neigh_node *hardif_neigh;
+
+       hardif_neigh = container_of(rcu, struct batadv_hardif_neigh_node, rcu);
+
+       spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
+       hlist_del_init_rcu(&hardif_neigh->list);
+       spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
+
+       batadv_hardif_free_ref_now(hardif_neigh->if_incoming);
+       kfree(hardif_neigh);
+}
+
+/**
+ * batadv_hardif_neigh_free_now - decrement the hardif neighbors refcounter
+ *  and possibly free it (without rcu callback)
+ * @hardif_neigh: hardif neigh neighbor to free
+ */
+static void
+batadv_hardif_neigh_free_now(struct batadv_hardif_neigh_node *hardif_neigh)
+{
+       if (atomic_dec_and_test(&hardif_neigh->refcount))
+               batadv_hardif_neigh_free_rcu(&hardif_neigh->rcu);
+}
+
+/**
+ * batadv_hardif_neigh_free_ref - decrement the hardif neighbors refcounter
+ *  and possibly free it
+ * @hardif_neigh: hardif neigh neighbor to free
+ */
+void batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh)
+{
+       if (atomic_dec_and_test(&hardif_neigh->refcount))
+               call_rcu(&hardif_neigh->rcu, batadv_hardif_neigh_free_rcu);
+}
+
 /**
  * batadv_neigh_node_free_rcu - free the neigh_node
  * @rcu: rcu pointer of the neigh_node
@@ -209,6 +250,7 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
 {
        struct hlist_node *node_tmp;
        struct batadv_neigh_node *neigh_node;
+       struct batadv_hardif_neigh_node *hardif_neigh;
        struct batadv_neigh_ifinfo *neigh_ifinfo;
        struct batadv_algo_ops *bao;
 
@@ -220,6 +262,14 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
                batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
        }
 
+       hardif_neigh = batadv_hardif_neigh_get(neigh_node->if_incoming,
+                                              neigh_node->addr);
+       if (hardif_neigh) {
+               /* batadv_hardif_neigh_get() increases refcount too */
+               batadv_hardif_neigh_free_now(hardif_neigh);
+               batadv_hardif_neigh_free_now(hardif_neigh);
+       }
+
        if (bao->bat_neigh_free)
                bao->bat_neigh_free(neigh_node);
 
@@ -478,6 +528,106 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
        return res;
 }
 
+/**
+ * batadv_hardif_neigh_create - create a hardif neighbour node
+ * @hard_iface: the interface this neighbour is connected to
+ * @neigh_addr: the interface address of the neighbour to retrieve
+ *
+ * Returns the hardif neighbour node if found or created or NULL otherwise.
+ */
+static struct batadv_hardif_neigh_node *
+batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
+                          const u8 *neigh_addr)
+{
+       struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+       struct batadv_hardif_neigh_node *hardif_neigh = NULL;
+
+       spin_lock_bh(&hard_iface->neigh_list_lock);
+
+       /* check if neighbor hasn't been added in the meantime */
+       hardif_neigh = batadv_hardif_neigh_get(hard_iface, neigh_addr);
+       if (hardif_neigh)
+               goto out;
+
+       if (!atomic_inc_not_zero(&hard_iface->refcount))
+               goto out;
+
+       hardif_neigh = kzalloc(sizeof(*hardif_neigh), GFP_ATOMIC);
+       if (!hardif_neigh) {
+               batadv_hardif_free_ref(hard_iface);
+               goto out;
+       }
+
+       INIT_HLIST_NODE(&hardif_neigh->list);
+       ether_addr_copy(hardif_neigh->addr, neigh_addr);
+       hardif_neigh->if_incoming = hard_iface;
+       hardif_neigh->last_seen = jiffies;
+
+       atomic_set(&hardif_neigh->refcount, 1);
+
+       if (bat_priv->bat_algo_ops->bat_hardif_neigh_init)
+               bat_priv->bat_algo_ops->bat_hardif_neigh_init(hardif_neigh);
+
+       hlist_add_head(&hardif_neigh->list, &hard_iface->neigh_list);
+
+out:
+       spin_unlock_bh(&hard_iface->neigh_list_lock);
+       return hardif_neigh;
+}
+
+/**
+ * batadv_hardif_neigh_get_or_create - retrieve or create a hardif neighbour
+ *  node
+ * @hard_iface: the interface this neighbour is connected to
+ * @neigh_addr: the interface address of the neighbour to retrieve
+ *
+ * Returns the hardif neighbour node if found or created or NULL otherwise.
+ */
+static struct batadv_hardif_neigh_node *
+batadv_hardif_neigh_get_or_create(struct batadv_hard_iface *hard_iface,
+                                 const u8 *neigh_addr)
+{
+       struct batadv_hardif_neigh_node *hardif_neigh = NULL;
+
+       /* first check without locking to avoid the overhead */
+       hardif_neigh = batadv_hardif_neigh_get(hard_iface, neigh_addr);
+       if (hardif_neigh)
+               return hardif_neigh;
+
+       return batadv_hardif_neigh_create(hard_iface, neigh_addr);
+}
+
+/**
+ * batadv_hardif_neigh_get - retrieve a hardif neighbour from the list
+ * @hard_iface: the interface where this neighbour is connected to
+ * @neigh_addr: the address of the neighbour
+ *
+ * Looks for and possibly returns a neighbour belonging to this hard interface.
+ * Returns NULL if the neighbour is not found.
+ */
+struct batadv_hardif_neigh_node *
+batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface,
+                       const u8 *neigh_addr)
+{
+       struct batadv_hardif_neigh_node *tmp_hardif_neigh, *hardif_neigh = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp_hardif_neigh,
+                                &hard_iface->neigh_list, list) {
+               if (!batadv_compare_eth(tmp_hardif_neigh->addr, neigh_addr))
+                       continue;
+
+               if (!atomic_inc_not_zero(&tmp_hardif_neigh->refcount))
+                       continue;
+
+               hardif_neigh = tmp_hardif_neigh;
+               break;
+       }
+       rcu_read_unlock();
+
+       return hardif_neigh;
+}
+
 /**
  * batadv_neigh_node_new - create and init a new neigh_node object
  * @orig_node: originator object representing the neighbour
@@ -493,11 +643,17 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
                      const u8 *neigh_addr)
 {
        struct batadv_neigh_node *neigh_node;
+       struct batadv_hardif_neigh_node *hardif_neigh = NULL;
 
        neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
        if (neigh_node)
                goto out;
 
+       hardif_neigh = batadv_hardif_neigh_get_or_create(hard_iface,
+                                                        neigh_addr);
+       if (!hardif_neigh)
+               goto out;
+
        neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
        if (!neigh_node)
                goto out;
@@ -523,14 +679,53 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
        hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
        spin_unlock_bh(&orig_node->neigh_list_lock);
 
+       /* increment unique neighbor refcount */
+       atomic_inc(&hardif_neigh->refcount);
+
        batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv,
                   "Creating new neighbor %pM for orig_node %pM on interface %s\n",
                   neigh_addr, orig_node->orig, hard_iface->net_dev->name);
 
 out:
+       if (hardif_neigh)
+               batadv_hardif_neigh_free_ref(hardif_neigh);
        return neigh_node;
 }
 
+/**
+ * batadv_hardif_neigh_seq_print_text - print the single hop neighbour list
+ * @seq: neighbour table seq_file struct
+ * @offset: not used
+ *
+ * Always returns 0.
+ */
+int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset)
+{
+       struct net_device *net_dev = (struct net_device *)seq->private;
+       struct batadv_priv *bat_priv = netdev_priv(net_dev);
+       struct batadv_hard_iface *primary_if;
+
+       primary_if = batadv_seq_print_text_primary_if_get(seq);
+       if (!primary_if)
+               return 0;
+
+       seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s %s)]\n",
+                  BATADV_SOURCE_VERSION, primary_if->net_dev->name,
+                  primary_if->net_dev->dev_addr, net_dev->name,
+                  bat_priv->bat_algo_ops->name);
+
+       batadv_hardif_free_ref(primary_if);
+
+       if (!bat_priv->bat_algo_ops->bat_neigh_print) {
+               seq_puts(seq,
+                        "No printing function for this routing protocol\n");
+               return 0;
+       }
+
+       bat_priv->bat_algo_ops->bat_neigh_print(bat_priv, seq);
+       return 0;
+}
+
 /**
  * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
  * @rcu: rcu pointer of the orig_ifinfo object
index fa18f9bf266b05db90a937a30c67c5aab2e1f11a..29557753d552d644d683863d48a674b45ea9cb37 100644 (file)
@@ -41,6 +41,11 @@ void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node);
 void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node);
 struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
                                              const u8 *addr);
+struct batadv_hardif_neigh_node *
+batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface,
+                       const u8 *neigh_addr);
+void
+batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh);
 struct batadv_neigh_node *
 batadv_neigh_node_new(struct batadv_orig_node *orig_node,
                      struct batadv_hard_iface *hard_iface,
@@ -57,6 +62,8 @@ batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
                        struct batadv_hard_iface *if_outgoing);
 void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo);
 
+int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset);
+
 struct batadv_orig_ifinfo *
 batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
                       struct batadv_hard_iface *if_outgoing);
index 8d990b070a2e87db6a6e71f9e3eaad93dbf4a59e..a43f02e2d4231a6050a4c603ad724bcbc6ba8620 100644 (file)
@@ -497,9 +497,9 @@ batadv_find_router(struct batadv_priv *bat_priv,
                /* alternative candidate should be good enough to be
                 * considered
                 */
-               if (!bao->bat_neigh_is_equiv_or_better(cand_router,
-                                                      cand->if_outgoing,
-                                                      router, recv_if))
+               if (!bao->bat_neigh_is_similar_or_better(cand_router,
+                                                        cand->if_outgoing,
+                                                        router, recv_if))
                        goto next;
 
                /* don't use the same router twice */
index 4228b10c47ead06db9284997afc1899e181d6505..5cf431177f344ef90525d158d6d4309e199c9c95 100644 (file)
@@ -1435,7 +1435,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
                 * TT_CLIENT_WIFI, therefore they have to be copied in the
                 * client entry
                 */
-               tt_global_entry->common.flags |= flags;
+               common->flags |= flags;
 
                /* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
                 * one originator left in the list and we previously received a
@@ -2411,8 +2411,8 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
 {
        struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
        struct batadv_orig_node_vlan *vlan;
+       int i, orig_num_vlan;
        u32 crc;
-       int i;
 
        /* check if each received CRC matches the locally stored one */
        for (i = 0; i < num_vlan; i++) {
@@ -2438,6 +2438,18 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
                        return false;
        }
 
+       /* check if any excess VLANs exist locally for the originator
+        * which are not mentioned in the TVLV from the originator.
+        */
+       rcu_read_lock();
+       orig_num_vlan = 0;
+       hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list)
+               orig_num_vlan++;
+       rcu_read_unlock();
+
+       if (orig_num_vlan > num_vlan)
+               return false;
+
        return true;
 }
 
index d260efd70499bd62ceb7b86b57684f45a96612e9..7c386dbb75f017bce18598517f51488601c5ad34 100644 (file)
@@ -100,6 +100,8 @@ struct batadv_hard_iface_bat_iv {
  * @bat_iv: BATMAN IV specific per hard interface data
  * @cleanup_work: work queue callback item for hard interface deinit
  * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
+ * @neigh_list: list of unique single hop neighbors via this interface
+ * @neigh_list_lock: lock protecting neigh_list
  */
 struct batadv_hard_iface {
        struct list_head list;
@@ -115,6 +117,9 @@ struct batadv_hard_iface {
        struct batadv_hard_iface_bat_iv bat_iv;
        struct work_struct cleanup_work;
        struct dentry *debug_dir;
+       struct hlist_head neigh_list;
+       /* neigh_list_lock protects: neigh_list */
+       spinlock_t neigh_list_lock;
 };
 
 /**
@@ -340,6 +345,23 @@ struct batadv_gw_node {
        struct rcu_head rcu;
 };
 
+/**
+ * batadv_hardif_neigh_node - unique neighbor per hard interface
+ * @list: list node for batadv_hard_iface::neigh_list
+ * @addr: the MAC address of the neighboring interface
+ * @if_incoming: pointer to incoming hard interface
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in a RCU-safe manner
+ */
+struct batadv_hardif_neigh_node {
+       struct hlist_node list;
+       u8 addr[ETH_ALEN];
+       struct batadv_hard_iface *if_incoming;
+       unsigned long last_seen;
+       atomic_t refcount;
+       struct rcu_head rcu;
+};
+
 /**
  * struct batadv_neigh_node - structure for single hops neighbors
  * @list: list node for batadv_orig_node::neigh_list
@@ -884,6 +906,7 @@ struct batadv_socket_packet {
  *  backbone gateway - no bcast traffic is formwared until the situation was
  *  resolved
  * @crc: crc16 checksum over all claims
+ * @crc_lock: lock protecting crc
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in an RCU-safe manner
  */
@@ -897,6 +920,7 @@ struct batadv_bla_backbone_gw {
        atomic_t wait_periods;
        atomic_t request_sent;
        u16 crc;
+       spinlock_t crc_lock; /* protects crc */
        atomic_t refcount;
        struct rcu_head rcu;
 };
@@ -1131,11 +1155,13 @@ struct batadv_forw_packet {
  * @bat_primary_iface_set: called when primary interface is selected / changed
  * @bat_ogm_schedule: prepare a new outgoing OGM for the send queue
  * @bat_ogm_emit: send scheduled OGM
+ * @bat_hardif_neigh_init: called on creation of single hop entry
  * @bat_neigh_cmp: compare the metrics of two neighbors for their respective
  *  outgoing interfaces
- * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better
- *  than neigh2 for their respective outgoing interface from the metric
+ * @bat_neigh_is_similar_or_better: check if neigh1 is equally similar or
+ *  better than neigh2 for their respective outgoing interface from the metric
  *  prospective
+ * @bat_neigh_print: print the single hop neighbor list (optional)
  * @bat_neigh_free: free the resources allocated by the routing algorithm for a
  *  neigh_node object
  * @bat_orig_print: print the originator table (optional)
@@ -1156,15 +1182,17 @@ struct batadv_algo_ops {
        void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface);
        void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet);
        /* neigh_node handling API */
+       void (*bat_hardif_neigh_init)(struct batadv_hardif_neigh_node *neigh);
        int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1,
                             struct batadv_hard_iface *if_outgoing1,
                             struct batadv_neigh_node *neigh2,
                             struct batadv_hard_iface *if_outgoing2);
-       bool (*bat_neigh_is_equiv_or_better)
+       bool (*bat_neigh_is_similar_or_better)
                (struct batadv_neigh_node *neigh1,
                 struct batadv_hard_iface *if_outgoing1,
                 struct batadv_neigh_node *neigh2,
                 struct batadv_hard_iface *if_outgoing2);
+       void (*bat_neigh_print)(struct batadv_priv *priv, struct seq_file *seq);
        void (*bat_neigh_free)(struct batadv_neigh_node *neigh);
        /* orig_node handling API */
        void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq,