Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / net / batman-adv / bridge_loop_avoidance.c
index 264de88db3208290b940cc27b09e44f79e1616c9..28eb5e6d0a02510a0a7b4e268f7dc34a26bc182a 100644 (file)
@@ -411,10 +411,10 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, uint8_t *orig,
                return NULL;
        }
 
-       /* this is a gateway now, remove any tt entries */
+       /* this is a gateway now, remove any TT entry on this VLAN */
        orig_node = batadv_orig_hash_find(bat_priv, orig);
        if (orig_node) {
-               batadv_tt_global_del_orig(bat_priv, orig_node,
+               batadv_tt_global_del_orig(bat_priv, orig_node, vid,
                                          "became a backbone gateway");
                batadv_orig_node_free_ref(orig_node);
        }
@@ -858,30 +858,28 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
                                    struct batadv_hard_iface *primary_if,
                                    struct sk_buff *skb)
 {
-       struct ethhdr *ethhdr;
+       struct batadv_bla_claim_dst *bla_dst;
+       uint8_t *hw_src, *hw_dst;
        struct vlan_ethhdr *vhdr;
+       struct ethhdr *ethhdr;
        struct arphdr *arphdr;
-       uint8_t *hw_src, *hw_dst;
-       struct batadv_bla_claim_dst *bla_dst;
-       uint16_t proto;
+       unsigned short vid;
+       __be16 proto;
        int headlen;
-       unsigned short vid = BATADV_NO_FLAGS;
        int ret;
 
+       vid = batadv_get_vid(skb, 0);
        ethhdr = eth_hdr(skb);
 
-       if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
+       proto = ethhdr->h_proto;
+       headlen = ETH_HLEN;
+       if (vid & BATADV_VLAN_HAS_TAG) {
                vhdr = (struct vlan_ethhdr *)ethhdr;
-               vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
-               vid |= BATADV_VLAN_HAS_TAG;
-               proto = ntohs(vhdr->h_vlan_encapsulated_proto);
-               headlen = sizeof(*vhdr);
-       } else {
-               proto = ntohs(ethhdr->h_proto);
-               headlen = ETH_HLEN;
+               proto = vhdr->h_vlan_encapsulated_proto;
+               headlen += VLAN_HLEN;
        }
 
-       if (proto != ETH_P_ARP)
+       if (proto != htons(ETH_P_ARP))
                return 0; /* not a claim frame */
 
        /* this must be a ARP frame. check if it is a claim. */
@@ -1317,12 +1315,14 @@ out:
 
 /* @bat_priv: the bat priv with all the soft interface information
  * @orig: originator mac address
+ * @vid: VLAN identifier
  *
- * check if the originator is a gateway for any VLAN ID.
+ * Check if the originator is a gateway for the VLAN identified by vid.
  *
- * returns 1 if it is found, 0 otherwise
+ * Returns true if orig is a backbone for this vid, false otherwise.
  */
-int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig)
+bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig,
+                                   unsigned short vid)
 {
        struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
        struct hlist_head *head;
@@ -1330,25 +1330,26 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig)
        int i;
 
        if (!atomic_read(&bat_priv->bridge_loop_avoidance))
-               return 0;
+               return false;
 
        if (!hash)
-               return 0;
+               return false;
 
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
 
                rcu_read_lock();
                hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
-                       if (batadv_compare_eth(backbone_gw->orig, orig)) {
+                       if (batadv_compare_eth(backbone_gw->orig, orig) &&
+                           backbone_gw->vid == vid) {
                                rcu_read_unlock();
-                               return 1;
+                               return true;
                        }
                }
                rcu_read_unlock();
        }
 
-       return 0;
+       return false;
 }
 
 
@@ -1365,10 +1366,8 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig)
 int batadv_bla_is_backbone_gw(struct sk_buff *skb,
                              struct batadv_orig_node *orig_node, int hdr_size)
 {
-       struct ethhdr *ethhdr;
-       struct vlan_ethhdr *vhdr;
        struct batadv_bla_backbone_gw *backbone_gw;
-       unsigned short vid = BATADV_NO_FLAGS;
+       unsigned short vid;
 
        if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))
                return 0;
@@ -1377,16 +1376,7 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb,
        if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
                return 0;
 
-       ethhdr = (struct ethhdr *)(((uint8_t *)skb->data) + hdr_size);
-
-       if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
-               if (!pskb_may_pull(skb, hdr_size + sizeof(struct vlan_ethhdr)))
-                       return 0;
-
-               vhdr = (struct vlan_ethhdr *)(skb->data + hdr_size);
-               vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
-               vid |= BATADV_VLAN_HAS_TAG;
-       }
+       vid = batadv_get_vid(skb, hdr_size);
 
        /* see if this originator is a backbone gw for this VLAN */
        backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,