diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 0a9084ad19a6..fd8d5afec0dd 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -1167,6 +1167,8 @@ int batadv_bla_init(struct batadv_priv *bat_priv) uint16_t crc; unsigned long entrytime; + spin_lock_init(&bat_priv->bla.bcast_duplist_lock); + batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hash registering\n"); /* setting claim destination address */ @@ -1210,8 +1212,8 @@ int batadv_bla_init(struct batadv_priv *bat_priv) /** * batadv_bla_check_bcast_duplist * @bat_priv: the bat priv with all the soft interface information - * @bcast_packet: originator mac address - * @hdr_size: maximum length of the frame + * @bcast_packet: encapsulated broadcast frame plus batman header + * @bcast_packet_len: length of encapsulated broadcast frame plus batman header * * check if it is on our broadcast list. Another gateway might * have sent the same packet because it is connected to the same backbone, @@ -1224,20 +1226,22 @@ int batadv_bla_init(struct batadv_priv *bat_priv) */ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, struct batadv_bcast_packet *bcast_packet, - int hdr_size) + int bcast_packet_len) { - int i, length, curr; + int i, length, curr, ret = 0; uint8_t *content; uint16_t crc; struct batadv_bcast_duplist_entry *entry; - length = hdr_size - sizeof(*bcast_packet); + length = bcast_packet_len - sizeof(*bcast_packet); content = (uint8_t *)bcast_packet; content += sizeof(*bcast_packet); /* calculate the crc ... */ crc = crc16(0, content, length); + spin_lock_bh(&bat_priv->bla.bcast_duplist_lock); + for (i = 0; i < BATADV_DUPLIST_SIZE; i++) { curr = (bat_priv->bla.bcast_duplist_curr + i); curr %= BATADV_DUPLIST_SIZE; @@ -1259,9 +1263,12 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, /* this entry seems to match: same crc, not too old, * and from another gw. therefore return 1 to forbid it. */ - return 1; + ret = 1; + goto out; } - /* not found, add a new entry (overwrite the oldest entry) */ + /* not found, add a new entry (overwrite the oldest entry) + * and allow it, its the first occurence. + */ curr = (bat_priv->bla.bcast_duplist_curr + BATADV_DUPLIST_SIZE - 1); curr %= BATADV_DUPLIST_SIZE; entry = &bat_priv->bla.bcast_duplist[curr]; @@ -1270,8 +1277,10 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, memcpy(entry->orig, bcast_packet->orig, ETH_ALEN); bat_priv->bla.bcast_duplist_curr = curr; - /* allow it, its the first occurence. */ - return 0; +out: + spin_unlock_bh(&bat_priv->bla.bcast_duplist_lock); + + return ret; } diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 939fc01371df..376b4cc6ca82 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -1124,8 +1124,14 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, spin_unlock_bh(&orig_node->bcast_seqno_lock); + /* keep skb linear for crc calculation */ + if (skb_linearize(skb) < 0) + goto out; + + bcast_packet = (struct batadv_bcast_packet *)skb->data; + /* check whether this has been sent by another originator before */ - if (batadv_bla_check_bcast_duplist(bat_priv, bcast_packet, hdr_size)) + if (batadv_bla_check_bcast_duplist(bat_priv, bcast_packet, skb->len)) goto out; /* rebroadcast packet */ diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 2ed82caacdca..ac1e07a80454 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -205,6 +205,8 @@ struct batadv_priv_bla { struct batadv_hashtable *backbone_hash; struct batadv_bcast_duplist_entry bcast_duplist[BATADV_DUPLIST_SIZE]; int bcast_duplist_curr; + /* protects bcast_duplist and bcast_duplist_curr */ + spinlock_t bcast_duplist_lock; struct batadv_bla_claim_dst claim_dest; struct delayed_work work; };