batman-adv: drop QinQ claim frames in bridge loop avoidance
authorSimon Wunderlich <simon@open-mesh.com>
Mon, 23 Jun 2014 13:55:36 +0000 (15:55 +0200)
committerAntonio Quartulli <antonio@meshcoding.com>
Mon, 21 Jul 2014 07:05:31 +0000 (09:05 +0200)
Since bridge loop avoidance only supports untagged or simple 802.1q
tagged VLAN claim frames, claim frames with stacked VLAN headers (QinQ)
should be detected and dropped. Transporting the over the mesh may cause
problems on the receivers, or create bogus entries in the local tt
tables.

Reported-by: Antonio Quartulli <antonio@open-mesh.com>
Signed-off-by: Simon Wunderlich <simon@open-mesh.com>
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
net/batman-adv/bridge_loop_avoidance.c

index 6f0d9ec3795059fdc5319574b65b24c08aaf2790..a957c8140721def2878b292c2e61e2dd37c36e5c 100644 (file)
@@ -800,11 +800,6 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv,
        bla_dst = (struct batadv_bla_claim_dst *)hw_dst;
        bla_dst_own = &bat_priv->bla.claim_dest;
 
-       /* check if it is a claim packet in general */
-       if (memcmp(bla_dst->magic, bla_dst_own->magic,
-                  sizeof(bla_dst->magic)) != 0)
-               return 0;
-
        /* if announcement packet, use the source,
         * otherwise assume it is in the hw_src
         */
@@ -866,12 +861,13 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
                                    struct batadv_hard_iface *primary_if,
                                    struct sk_buff *skb)
 {
-       struct batadv_bla_claim_dst *bla_dst;
+       struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;
        uint8_t *hw_src, *hw_dst;
-       struct vlan_ethhdr *vhdr;
+       struct vlan_hdr *vhdr, vhdr_buf;
        struct ethhdr *ethhdr;
        struct arphdr *arphdr;
        unsigned short vid;
+       int vlan_depth = 0;
        __be16 proto;
        int headlen;
        int ret;
@@ -882,9 +878,24 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
        proto = ethhdr->h_proto;
        headlen = ETH_HLEN;
        if (vid & BATADV_VLAN_HAS_TAG) {
-               vhdr = vlan_eth_hdr(skb);
-               proto = vhdr->h_vlan_encapsulated_proto;
-               headlen += VLAN_HLEN;
+               /* Traverse the VLAN/Ethertypes.
+                *
+                * At this point it is known that the first protocol is a VLAN
+                * header, so start checking at the encapsulated protocol.
+                *
+                * The depth of the VLAN headers is recorded to drop BLA claim
+                * frames encapsulated into multiple VLAN headers (QinQ).
+                */
+               do {
+                       vhdr = skb_header_pointer(skb, headlen, VLAN_HLEN,
+                                                 &vhdr_buf);
+                       if (!vhdr)
+                               return 0;
+
+                       proto = vhdr->h_vlan_encapsulated_proto;
+                       headlen += VLAN_HLEN;
+                       vlan_depth++;
+               } while (proto == htons(ETH_P_8021Q));
        }
 
        if (proto != htons(ETH_P_ARP))
@@ -914,6 +925,19 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
        hw_src = (uint8_t *)arphdr + sizeof(struct arphdr);
        hw_dst = hw_src + ETH_ALEN + 4;
        bla_dst = (struct batadv_bla_claim_dst *)hw_dst;
+       bla_dst_own = &bat_priv->bla.claim_dest;
+
+       /* check if it is a claim frame in general */
+       if (memcmp(bla_dst->magic, bla_dst_own->magic,
+                  sizeof(bla_dst->magic)) != 0)
+               return 0;
+
+       /* check if there is a claim frame encapsulated deeper in (QinQ) and
+        * drop that, as this is not supported by BLA but should also not be
+        * sent via the mesh.
+        */
+       if (vlan_depth > 1)
+               return 1;
 
        /* check if it is a claim frame. */
        ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst,