]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/batman-adv/hard-interface.c
Merge tag 'batadv-next-for-davem-20161108-v2' of git://git.open-mesh.org/linux-merge
[mirror_ubuntu-bionic-kernel.git] / net / batman-adv / hard-interface.c
index 08ce36147c4c3a76bba8d98004617f7a7f03a2e6..dc1816e9d53bca0c78f91772ec657bf4d95d979d 100644 (file)
@@ -228,6 +228,58 @@ bool batadv_is_wifi_netdev(struct net_device *net_device)
        return false;
 }
 
+/**
+ * batadv_hardif_no_broadcast - check whether (re)broadcast is necessary
+ * @if_outgoing: the outgoing interface checked and considered for (re)broadcast
+ * @orig_addr: the originator of this packet
+ * @orig_neigh: originator address of the forwarder we just got the packet from
+ *  (NULL if we originated)
+ *
+ * Checks whether a packet needs to be (re)broadcasted on the given interface.
+ *
+ * Return:
+ *     BATADV_HARDIF_BCAST_NORECIPIENT: No neighbor on interface
+ *     BATADV_HARDIF_BCAST_DUPFWD: Just one neighbor, but it is the forwarder
+ *     BATADV_HARDIF_BCAST_DUPORIG: Just one neighbor, but it is the originator
+ *     BATADV_HARDIF_BCAST_OK: Several neighbors, must broadcast
+ */
+int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing,
+                              u8 *orig_addr, u8 *orig_neigh)
+{
+       struct batadv_hardif_neigh_node *hardif_neigh;
+       struct hlist_node *first;
+       int ret = BATADV_HARDIF_BCAST_OK;
+
+       rcu_read_lock();
+
+       /* 0 neighbors -> no (re)broadcast */
+       first = rcu_dereference(hlist_first_rcu(&if_outgoing->neigh_list));
+       if (!first) {
+               ret = BATADV_HARDIF_BCAST_NORECIPIENT;
+               goto out;
+       }
+
+       /* >1 neighbors -> (re)brodcast */
+       if (rcu_dereference(hlist_next_rcu(first)))
+               goto out;
+
+       hardif_neigh = hlist_entry(first, struct batadv_hardif_neigh_node,
+                                  list);
+
+       /* 1 neighbor, is the originator -> no rebroadcast */
+       if (orig_addr && batadv_compare_eth(hardif_neigh->orig, orig_addr)) {
+               ret = BATADV_HARDIF_BCAST_DUPORIG;
+       /* 1 neighbor, is the one we received from -> no rebroadcast */
+       } else if (orig_neigh &&
+                  batadv_compare_eth(hardif_neigh->orig, orig_neigh)) {
+               ret = BATADV_HARDIF_BCAST_DUPFWD;
+       }
+
+out:
+       rcu_read_unlock();
+       return ret;
+}
+
 static struct batadv_hard_iface *
 batadv_hardif_get_active(const struct net_device *soft_iface)
 {
@@ -652,7 +704,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
                        batadv_softif_destroy_sysfs(hard_iface->soft_iface);
        }
 
-       hard_iface->soft_iface = NULL;
        batadv_hardif_put(hard_iface);
 
 out: