diff options
Diffstat (limited to 'net/batman-adv/bridge_loop_avoidance.c')
| -rw-r--r-- | net/batman-adv/bridge_loop_avoidance.c | 44 | 
1 files changed, 34 insertions, 10 deletions
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 6f0d9ec37950..a957c8140721 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -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,  |