]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/batman-adv/distributed-arp-table.c
Merge tag 'xfs-4.12-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[karo-tx-linux.git] / net / batman-adv / distributed-arp-table.c
index 1bfd1dbc2feba7bf6c16004ea8ca85ed6066c929..000ca2f113ab857b4969a95b8fe1134806b05f15 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/workqueue.h>
 #include <net/arp.h>
 
+#include "bridge_loop_avoidance.h"
 #include "hard-interface.h"
 #include "hash.h"
 #include "log.h"
@@ -330,7 +331,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
                batadv_dbg(BATADV_DBG_DAT, bat_priv,
                           "Entry updated: %pI4 %pM (vid: %d)\n",
                           &dat_entry->ip, dat_entry->mac_addr,
-                          BATADV_PRINT_VID(vid));
+                          batadv_print_vid(vid));
                goto out;
        }
 
@@ -356,7 +357,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
        }
 
        batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n",
-                  &dat_entry->ip, dat_entry->mac_addr, BATADV_PRINT_VID(vid));
+                  &dat_entry->ip, dat_entry->mac_addr, batadv_print_vid(vid));
 
 out:
        if (dat_entry)
@@ -835,7 +836,7 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
 
                        seq_printf(seq, " * %15pI4 %14pM %4i %6i:%02i\n",
                                   &dat_entry->ip, dat_entry->mac_addr,
-                                  BATADV_PRINT_VID(dat_entry->vid),
+                                  batadv_print_vid(dat_entry->vid),
                                   last_seen_mins, last_seen_secs);
                }
                rcu_read_unlock();
@@ -1002,6 +1003,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
        bool ret = false;
        struct batadv_dat_entry *dat_entry = NULL;
        struct sk_buff *skb_new;
+       struct net_device *soft_iface = bat_priv->soft_iface;
        int hdr_size = 0;
        unsigned short vid;
 
@@ -1040,16 +1042,31 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
                        goto out;
                }
 
+               /* If BLA is enabled, only send ARP replies if we have claimed
+                * the destination for the ARP request or if no one else of
+                * the backbone gws belonging to our backbone has claimed the
+                * destination.
+                */
+               if (!batadv_bla_check_claim(bat_priv,
+                                           dat_entry->mac_addr, vid)) {
+                       batadv_dbg(BATADV_DBG_DAT, bat_priv,
+                                  "Device %pM claimed by another backbone gw. Don't send ARP reply!",
+                                  dat_entry->mac_addr);
+                       ret = true;
+                       goto out;
+               }
+
                skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
                                                      dat_entry->mac_addr,
                                                      hw_src, vid);
                if (!skb_new)
                        goto out;
 
-               skb_new->protocol = eth_type_trans(skb_new,
-                                                  bat_priv->soft_iface);
-               bat_priv->stats.rx_packets++;
-               bat_priv->stats.rx_bytes += skb->len + ETH_HLEN + hdr_size;
+               skb_new->protocol = eth_type_trans(skb_new, soft_iface);
+
+               batadv_inc_counter(bat_priv, BATADV_CNT_RX);
+               batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
+                                  skb->len + ETH_HLEN + hdr_size);
 
                netif_rx(skb_new);
                batadv_dbg(BATADV_DBG_DAT, bat_priv, "ARP request replied locally\n");
@@ -1188,6 +1205,7 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
 bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
                                         struct sk_buff *skb, int hdr_size)
 {
+       struct batadv_dat_entry *dat_entry = NULL;
        u16 type;
        __be32 ip_src, ip_dst;
        u8 *hw_src, *hw_dst;
@@ -1210,12 +1228,41 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
        hw_dst = batadv_arp_hw_dst(skb, hdr_size);
        ip_dst = batadv_arp_ip_dst(skb, hdr_size);
 
+       /* If ip_dst is already in cache and has the right mac address,
+        * drop this frame if this ARP reply is destined for us because it's
+        * most probably an ARP reply generated by another node of the DHT.
+        * We have most probably received already a reply earlier. Delivering
+        * this frame would lead to doubled receive of an ARP reply.
+        */
+       dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_src, vid);
+       if (dat_entry && batadv_compare_eth(hw_src, dat_entry->mac_addr)) {
+               batadv_dbg(BATADV_DBG_DAT, bat_priv, "Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n",
+                          hw_src, &ip_src, hw_dst, &ip_dst,
+                          dat_entry->mac_addr, &dat_entry->ip);
+               dropped = true;
+               goto out;
+       }
+
        /* Update our internal cache with both the IP addresses the node got
         * within the ARP reply
         */
        batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
        batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
 
+       /* If BLA is enabled, only forward ARP replies if we have claimed the
+        * source of the ARP reply or if no one else of the same backbone has
+        * already claimed that client. This prevents that different gateways
+        * to the same backbone all forward the ARP reply leading to multiple
+        * replies in the backbone.
+        */
+       if (!batadv_bla_check_claim(bat_priv, hw_src, vid)) {
+               batadv_dbg(BATADV_DBG_DAT, bat_priv,
+                          "Device %pM claimed by another backbone gw. Drop ARP reply.\n",
+                          hw_src);
+               dropped = true;
+               goto out;
+       }
+
        /* if this REPLY is directed to a client of mine, let's deliver the
         * packet to the interface
         */
@@ -1228,6 +1275,8 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
 out:
        if (dropped)
                kfree_skb(skb);
+       if (dat_entry)
+               batadv_dat_entry_put(dat_entry);
        /* if dropped == false -> deliver to the interface */
        return dropped;
 }
@@ -1256,7 +1305,7 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
        /* If this packet is an ARP_REQUEST and the node already has the
         * information that it is going to ask, then the packet can be dropped
         */
-       if (forw_packet->num_packets)
+       if (batadv_forw_packet_is_rebroadcast(forw_packet))
                goto out;
 
        vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size);