diff options
Diffstat (limited to 'net/batman-adv/bridge_loop_avoidance.c')
| -rw-r--r-- | net/batman-adv/bridge_loop_avoidance.c | 145 | 
1 files changed, 117 insertions, 28 deletions
| diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 8500f56cbd10..c350ab63cd54 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -25,6 +25,7 @@  #include <linux/lockdep.h>  #include <linux/netdevice.h>  #include <linux/netlink.h> +#include <linux/preempt.h>  #include <linux/rculist.h>  #include <linux/rcupdate.h>  #include <linux/seq_file.h> @@ -83,11 +84,12 @@ static inline u32 batadv_choose_claim(const void *data, u32 size)   */  static inline u32 batadv_choose_backbone_gw(const void *data, u32 size)  { -	const struct batadv_bla_claim *claim = (struct batadv_bla_claim *)data; +	const struct batadv_bla_backbone_gw *gw;  	u32 hash = 0; -	hash = jhash(&claim->addr, sizeof(claim->addr), hash); -	hash = jhash(&claim->vid, sizeof(claim->vid), hash); +	gw = (struct batadv_bla_backbone_gw *)data; +	hash = jhash(&gw->orig, sizeof(gw->orig), hash); +	hash = jhash(&gw->vid, sizeof(gw->vid), hash);  	return hash % size;  } @@ -1579,13 +1581,16 @@ int batadv_bla_init(struct batadv_priv *bat_priv)  }  /** - * batadv_bla_check_bcast_duplist() - Check if a frame is in the broadcast dup. + * batadv_bla_check_duplist() - Check if a frame is in the broadcast dup.   * @bat_priv: the bat priv with all the soft interface information - * @skb: contains the bcast_packet to be checked + * @skb: contains the multicast packet to be checked + * @payload_ptr: pointer to position inside the head buffer of the skb + *  marking the start of the data to be CRC'ed + * @orig: originator mac address, NULL if unknown   * - * check if it is on our broadcast list. Another gateway might - * have sent the same packet because it is connected to the same backbone, - * so we have to remove this duplicate. + * Check if it is on our broadcast list. Another gateway might have sent the + * same packet because it is connected to the same backbone, so we have to + * remove this duplicate.   *   * This is performed by checking the CRC, which will tell us   * with a good chance that it is the same packet. If it is furthermore @@ -1594,19 +1599,17 @@ int batadv_bla_init(struct batadv_priv *bat_priv)   *   * Return: true if a packet is in the duplicate list, false otherwise.   */ -bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, -				    struct sk_buff *skb) +static bool batadv_bla_check_duplist(struct batadv_priv *bat_priv, +				     struct sk_buff *skb, u8 *payload_ptr, +				     const u8 *orig)  { -	int i, curr; -	__be32 crc; -	struct batadv_bcast_packet *bcast_packet;  	struct batadv_bcast_duplist_entry *entry;  	bool ret = false; - -	bcast_packet = (struct batadv_bcast_packet *)skb->data; +	int i, curr; +	__be32 crc;  	/* calculate the crc ... */ -	crc = batadv_skb_crc32(skb, (u8 *)(bcast_packet + 1)); +	crc = batadv_skb_crc32(skb, payload_ptr);  	spin_lock_bh(&bat_priv->bla.bcast_duplist_lock); @@ -1625,8 +1628,21 @@ bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,  		if (entry->crc != crc)  			continue; -		if (batadv_compare_eth(entry->orig, bcast_packet->orig)) -			continue; +		/* are the originators both known and not anonymous? */ +		if (orig && !is_zero_ether_addr(orig) && +		    !is_zero_ether_addr(entry->orig)) { +			/* If known, check if the new frame came from +			 * the same originator: +			 * We are safe to take identical frames from the +			 * same orig, if known, as multiplications in +			 * the mesh are detected via the (orig, seqno) pair. +			 * So we can be a bit more liberal here and allow +			 * identical frames from the same orig which the source +			 * host might have sent multiple times on purpose. +			 */ +			if (batadv_compare_eth(entry->orig, orig)) +				continue; +		}  		/* this entry seems to match: same crc, not too old,  		 * and from another gw. therefore return true to forbid it. @@ -1642,7 +1658,14 @@ bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,  	entry = &bat_priv->bla.bcast_duplist[curr];  	entry->crc = crc;  	entry->entrytime = jiffies; -	ether_addr_copy(entry->orig, bcast_packet->orig); + +	/* known originator */ +	if (orig) +		ether_addr_copy(entry->orig, orig); +	/* anonymous originator */ +	else +		eth_zero_addr(entry->orig); +  	bat_priv->bla.bcast_duplist_curr = curr;  out: @@ -1652,6 +1675,48 @@ out:  }  /** + * batadv_bla_check_ucast_duplist() - Check if a frame is in the broadcast dup. + * @bat_priv: the bat priv with all the soft interface information + * @skb: contains the multicast packet to be checked, decapsulated from a + *  unicast_packet + * + * Check if it is on our broadcast list. Another gateway might have sent the + * same packet because it is connected to the same backbone, so we have to + * remove this duplicate. + * + * Return: true if a packet is in the duplicate list, false otherwise. + */ +static bool batadv_bla_check_ucast_duplist(struct batadv_priv *bat_priv, +					   struct sk_buff *skb) +{ +	return batadv_bla_check_duplist(bat_priv, skb, (u8 *)skb->data, NULL); +} + +/** + * batadv_bla_check_bcast_duplist() - Check if a frame is in the broadcast dup. + * @bat_priv: the bat priv with all the soft interface information + * @skb: contains the bcast_packet to be checked + * + * Check if it is on our broadcast list. Another gateway might have sent the + * same packet because it is connected to the same backbone, so we have to + * remove this duplicate. + * + * Return: true if a packet is in the duplicate list, false otherwise. + */ +bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, +				    struct sk_buff *skb) +{ +	struct batadv_bcast_packet *bcast_packet; +	u8 *payload_ptr; + +	bcast_packet = (struct batadv_bcast_packet *)skb->data; +	payload_ptr = (u8 *)(bcast_packet + 1); + +	return batadv_bla_check_duplist(bat_priv, skb, payload_ptr, +					bcast_packet->orig); +} + +/**   * batadv_bla_is_backbone_gw_orig() - Check if the originator is a gateway for   *  the VLAN identified by vid.   * @bat_priv: the bat priv with all the soft interface information @@ -1812,7 +1877,7 @@ batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,   * @bat_priv: the bat priv with all the soft interface information   * @skb: the frame to be checked   * @vid: the VLAN ID of the frame - * @is_bcast: the packet came in a broadcast packet type. + * @packet_type: the batman packet type this frame came in   *   * batadv_bla_rx avoidance checks if:   *  * we have to race for a claim @@ -1824,7 +1889,7 @@ batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,   * further process the skb.   */  bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, -		   unsigned short vid, bool is_bcast) +		   unsigned short vid, int packet_type)  {  	struct batadv_bla_backbone_gw *backbone_gw;  	struct ethhdr *ethhdr; @@ -1846,9 +1911,32 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,  		goto handled;  	if (unlikely(atomic_read(&bat_priv->bla.num_requests))) -		/* don't allow broadcasts while requests are in flight */ -		if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast) -			goto handled; +		/* don't allow multicast packets while requests are in flight */ +		if (is_multicast_ether_addr(ethhdr->h_dest)) +			/* Both broadcast flooding or multicast-via-unicasts +			 * delivery might send to multiple backbone gateways +			 * sharing the same LAN and therefore need to coordinate +			 * which backbone gateway forwards into the LAN, +			 * by claiming the payload source address. +			 * +			 * Broadcast flooding and multicast-via-unicasts +			 * delivery use the following two batman packet types. +			 * Note: explicitly exclude BATADV_UNICAST_4ADDR, +			 * as the DHCP gateway feature will send explicitly +			 * to only one BLA gateway, so the claiming process +			 * should be avoided there. +			 */ +			if (packet_type == BATADV_BCAST || +			    packet_type == BATADV_UNICAST) +				goto handled; + +	/* potential duplicates from foreign BLA backbone gateways via +	 * multicast-in-unicast packets +	 */ +	if (is_multicast_ether_addr(ethhdr->h_dest) && +	    packet_type == BATADV_UNICAST && +	    batadv_bla_check_ucast_duplist(bat_priv, skb)) +		goto handled;  	ether_addr_copy(search_claim.addr, ethhdr->h_source);  	search_claim.vid = vid; @@ -1883,13 +1971,14 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,  		goto allow;  	} -	/* if it is a broadcast ... */ -	if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast) { +	/* if it is a multicast ... */ +	if (is_multicast_ether_addr(ethhdr->h_dest) && +	    (packet_type == BATADV_BCAST || packet_type == BATADV_UNICAST)) {  		/* ... drop it. the responsible gateway is in charge.  		 * -		 * We need to check is_bcast because with the gateway +		 * We need to check packet type because with the gateway  		 * feature, broadcasts (like DHCP requests) may be sent -		 * using a unicast packet type. +		 * using a unicast 4 address packet type. See comment above.  		 */  		goto handled;  	} else { |