@@ -1081,6 +1081,8 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
u8 *hw_src;
struct sk_buff *skb_new;
struct batadv_dat_entry *dat_entry = NULL;
+ struct batadv_unicast_4addr_packet *unicast_4addr_packet;
+ struct batadv_orig_node *orig_node = NULL;
bool ret = false;
unsigned short vid;
int err;
@@ -1104,8 +1106,35 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
- if (!dat_entry)
+ if (!dat_entry) {
+ /* Check if this is a 4addr unicast DAT_DHT_GET frame from
+ * another backbone gw of the same backbone. If yes, drop
+ * it as this leads to multiplication of arp requests in bla
+ * setups as long as there is no dat_entry fo this answer.
+ * In this case better drop the DHT_GET. Normal bla code
+ * doesn't take care of these packets as they are tunneled
+ * via unicast.
+ */
+ unicast_4addr_packet =
+ (struct batadv_unicast_4addr_packet *)skb->data;
+ orig_node =
+ batadv_orig_hash_find(bat_priv, unicast_4addr_packet->src);
+ if (orig_node) {
+ if ((unicast_4addr_packet->u.packet_type == BATADV_UNICAST_4ADDR) &&
+ (unicast_4addr_packet->subtype == BATADV_P_DAT_DHT_GET) &&
+ (batadv_bla_is_backbone_gw(skb, orig_node, hdr_size))) {
+ batadv_dbg(BATADV_DBG_DAT, bat_priv, "Doubled ARP request removed: "
+ "ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; originator: %pM\n",
+ hw_src, &ip_src,
+ batadv_arp_hw_dst(skb, hdr_size), &ip_dst,
+ unicast_4addr_packet->src);
+ ret = true;
+ }
+ batadv_orig_node_put(orig_node);
+ }
+
goto out;
+ }
skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src,
bat_priv->soft_iface, ip_dst, hw_src,
@@ -1204,6 +1233,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
__be32 ip_src, ip_dst;
u8 *hw_src, *hw_dst;
bool dropped = false;
+ struct batadv_dat_entry *dat_entry = NULL;
unsigned short vid;
if (!atomic_read(&bat_priv->distributed_arp_table))
@@ -1223,12 +1253,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. We have
+ * most probably received already a reply from someone else. 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_handle_local_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
*/
@@ -1241,6 +1300,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;
}