Skip to content

Commit 850717e

Browse files
committed
Merge tag 'batman-adv-fix-for-davem' of git://git.open-mesh.org/linux-merge
Antonio Quartulli says: ==================== pull request [net]: batman-adv 20140721 here you have two fixes that we have been testing for quite some time (this is why they arrived a bit late in the rc cycle). Patch 1) ensures that BLA packets get dropped and not forwarded to the mesh even if they reach batman-adv within QinQ frames. Forwarding them into the mesh means messing up with the TT database of other nodes which can generate all kind of unexpected behaviours during route computation. Patch 2) avoids a couple of race conditions triggered upon fast VLAN deletion-addition. Such race conditions are pretty dangerous because they not only create inconsistencies in the TT database of the nodes in the network, but such scenario is also unrecoverable (unless nodes are rebooted). ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 10ec947 + 35df3b2 commit 850717e

File tree

4 files changed

+108
-24
lines changed

4 files changed

+108
-24
lines changed

net/batman-adv/bridge_loop_avoidance.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -800,11 +800,6 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv,
800800
bla_dst = (struct batadv_bla_claim_dst *)hw_dst;
801801
bla_dst_own = &bat_priv->bla.claim_dest;
802802

803-
/* check if it is a claim packet in general */
804-
if (memcmp(bla_dst->magic, bla_dst_own->magic,
805-
sizeof(bla_dst->magic)) != 0)
806-
return 0;
807-
808803
/* if announcement packet, use the source,
809804
* otherwise assume it is in the hw_src
810805
*/
@@ -866,12 +861,13 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
866861
struct batadv_hard_iface *primary_if,
867862
struct sk_buff *skb)
868863
{
869-
struct batadv_bla_claim_dst *bla_dst;
864+
struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;
870865
uint8_t *hw_src, *hw_dst;
871-
struct vlan_ethhdr *vhdr;
866+
struct vlan_hdr *vhdr, vhdr_buf;
872867
struct ethhdr *ethhdr;
873868
struct arphdr *arphdr;
874869
unsigned short vid;
870+
int vlan_depth = 0;
875871
__be16 proto;
876872
int headlen;
877873
int ret;
@@ -882,9 +878,24 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
882878
proto = ethhdr->h_proto;
883879
headlen = ETH_HLEN;
884880
if (vid & BATADV_VLAN_HAS_TAG) {
885-
vhdr = vlan_eth_hdr(skb);
886-
proto = vhdr->h_vlan_encapsulated_proto;
887-
headlen += VLAN_HLEN;
881+
/* Traverse the VLAN/Ethertypes.
882+
*
883+
* At this point it is known that the first protocol is a VLAN
884+
* header, so start checking at the encapsulated protocol.
885+
*
886+
* The depth of the VLAN headers is recorded to drop BLA claim
887+
* frames encapsulated into multiple VLAN headers (QinQ).
888+
*/
889+
do {
890+
vhdr = skb_header_pointer(skb, headlen, VLAN_HLEN,
891+
&vhdr_buf);
892+
if (!vhdr)
893+
return 0;
894+
895+
proto = vhdr->h_vlan_encapsulated_proto;
896+
headlen += VLAN_HLEN;
897+
vlan_depth++;
898+
} while (proto == htons(ETH_P_8021Q));
888899
}
889900

890901
if (proto != htons(ETH_P_ARP))
@@ -914,6 +925,19 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
914925
hw_src = (uint8_t *)arphdr + sizeof(struct arphdr);
915926
hw_dst = hw_src + ETH_ALEN + 4;
916927
bla_dst = (struct batadv_bla_claim_dst *)hw_dst;
928+
bla_dst_own = &bat_priv->bla.claim_dest;
929+
930+
/* check if it is a claim frame in general */
931+
if (memcmp(bla_dst->magic, bla_dst_own->magic,
932+
sizeof(bla_dst->magic)) != 0)
933+
return 0;
934+
935+
/* check if there is a claim frame encapsulated deeper in (QinQ) and
936+
* drop that, as this is not supported by BLA but should also not be
937+
* sent via the mesh.
938+
*/
939+
if (vlan_depth > 1)
940+
return 1;
917941

918942
/* check if it is a claim frame. */
919943
ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst,

net/batman-adv/soft-interface.c

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,15 @@ void batadv_interface_rx(struct net_device *soft_iface,
448448
* possibly free it
449449
* @softif_vlan: the vlan object to release
450450
*/
451-
void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan)
451+
void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan)
452452
{
453-
if (atomic_dec_and_test(&softif_vlan->refcount))
454-
kfree_rcu(softif_vlan, rcu);
453+
if (atomic_dec_and_test(&vlan->refcount)) {
454+
spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock);
455+
hlist_del_rcu(&vlan->list);
456+
spin_unlock_bh(&vlan->bat_priv->softif_vlan_list_lock);
457+
458+
kfree_rcu(vlan, rcu);
459+
}
455460
}
456461

457462
/**
@@ -505,6 +510,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
505510
if (!vlan)
506511
return -ENOMEM;
507512

513+
vlan->bat_priv = bat_priv;
508514
vlan->vid = vid;
509515
atomic_set(&vlan->refcount, 1);
510516

@@ -516,17 +522,17 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
516522
return err;
517523
}
518524

525+
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
526+
hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
527+
spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
528+
519529
/* add a new TT local entry. This one will be marked with the NOPURGE
520530
* flag
521531
*/
522532
batadv_tt_local_add(bat_priv->soft_iface,
523533
bat_priv->soft_iface->dev_addr, vid,
524534
BATADV_NULL_IFINDEX, BATADV_NO_MARK);
525535

526-
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
527-
hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
528-
spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
529-
530536
return 0;
531537
}
532538

@@ -538,18 +544,13 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
538544
static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
539545
struct batadv_softif_vlan *vlan)
540546
{
541-
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
542-
hlist_del_rcu(&vlan->list);
543-
spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
544-
545-
batadv_sysfs_del_vlan(bat_priv, vlan);
546-
547547
/* explicitly remove the associated TT local entry because it is marked
548548
* with the NOPURGE flag
549549
*/
550550
batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr,
551551
vlan->vid, "vlan interface destroyed", false);
552552

553+
batadv_sysfs_del_vlan(bat_priv, vlan);
553554
batadv_softif_vlan_free_ref(vlan);
554555
}
555556

@@ -567,6 +568,8 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
567568
unsigned short vid)
568569
{
569570
struct batadv_priv *bat_priv = netdev_priv(dev);
571+
struct batadv_softif_vlan *vlan;
572+
int ret;
570573

571574
/* only 802.1Q vlans are supported.
572575
* batman-adv does not know how to handle other types
@@ -576,7 +579,36 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
576579

577580
vid |= BATADV_VLAN_HAS_TAG;
578581

579-
return batadv_softif_create_vlan(bat_priv, vid);
582+
/* if a new vlan is getting created and it already exists, it means that
583+
* it was not deleted yet. batadv_softif_vlan_get() increases the
584+
* refcount in order to revive the object.
585+
*
586+
* if it does not exist then create it.
587+
*/
588+
vlan = batadv_softif_vlan_get(bat_priv, vid);
589+
if (!vlan)
590+
return batadv_softif_create_vlan(bat_priv, vid);
591+
592+
/* recreate the sysfs object if it was already destroyed (and it should
593+
* be since we received a kill_vid() for this vlan
594+
*/
595+
if (!vlan->kobj) {
596+
ret = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan);
597+
if (ret) {
598+
batadv_softif_vlan_free_ref(vlan);
599+
return ret;
600+
}
601+
}
602+
603+
/* add a new TT local entry. This one will be marked with the NOPURGE
604+
* flag. This must be added again, even if the vlan object already
605+
* exists, because the entry was deleted by kill_vid()
606+
*/
607+
batadv_tt_local_add(bat_priv->soft_iface,
608+
bat_priv->soft_iface->dev_addr, vid,
609+
BATADV_NULL_IFINDEX, BATADV_NO_MARK);
610+
611+
return 0;
580612
}
581613

582614
/**

net/batman-adv/translation-table.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
511511
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
512512
struct batadv_tt_local_entry *tt_local;
513513
struct batadv_tt_global_entry *tt_global = NULL;
514+
struct batadv_softif_vlan *vlan;
514515
struct net_device *in_dev = NULL;
515516
struct hlist_head *head;
516517
struct batadv_tt_orig_list_entry *orig_entry;
@@ -572,6 +573,9 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
572573
if (!tt_local)
573574
goto out;
574575

576+
/* increase the refcounter of the related vlan */
577+
vlan = batadv_softif_vlan_get(bat_priv, vid);
578+
575579
batadv_dbg(BATADV_DBG_TT, bat_priv,
576580
"Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
577581
addr, BATADV_PRINT_VID(vid),
@@ -604,6 +608,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
604608
if (unlikely(hash_added != 0)) {
605609
/* remove the reference for the hash */
606610
batadv_tt_local_entry_free_ref(tt_local);
611+
batadv_softif_vlan_free_ref(vlan);
607612
goto out;
608613
}
609614

@@ -1009,6 +1014,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
10091014
{
10101015
struct batadv_tt_local_entry *tt_local_entry;
10111016
uint16_t flags, curr_flags = BATADV_NO_FLAGS;
1017+
struct batadv_softif_vlan *vlan;
10121018

10131019
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
10141020
if (!tt_local_entry)
@@ -1039,6 +1045,11 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
10391045
hlist_del_rcu(&tt_local_entry->common.hash_entry);
10401046
batadv_tt_local_entry_free_ref(tt_local_entry);
10411047

1048+
/* decrease the reference held for this vlan */
1049+
vlan = batadv_softif_vlan_get(bat_priv, vid);
1050+
batadv_softif_vlan_free_ref(vlan);
1051+
batadv_softif_vlan_free_ref(vlan);
1052+
10421053
out:
10431054
if (tt_local_entry)
10441055
batadv_tt_local_entry_free_ref(tt_local_entry);
@@ -1111,6 +1122,7 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
11111122
spinlock_t *list_lock; /* protects write access to the hash lists */
11121123
struct batadv_tt_common_entry *tt_common_entry;
11131124
struct batadv_tt_local_entry *tt_local;
1125+
struct batadv_softif_vlan *vlan;
11141126
struct hlist_node *node_tmp;
11151127
struct hlist_head *head;
11161128
uint32_t i;
@@ -1131,6 +1143,13 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
11311143
tt_local = container_of(tt_common_entry,
11321144
struct batadv_tt_local_entry,
11331145
common);
1146+
1147+
/* decrease the reference held for this vlan */
1148+
vlan = batadv_softif_vlan_get(bat_priv,
1149+
tt_common_entry->vid);
1150+
batadv_softif_vlan_free_ref(vlan);
1151+
batadv_softif_vlan_free_ref(vlan);
1152+
11341153
batadv_tt_local_entry_free_ref(tt_local);
11351154
}
11361155
spin_unlock_bh(list_lock);
@@ -3139,6 +3158,7 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
31393158
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
31403159
struct batadv_tt_common_entry *tt_common;
31413160
struct batadv_tt_local_entry *tt_local;
3161+
struct batadv_softif_vlan *vlan;
31423162
struct hlist_node *node_tmp;
31433163
struct hlist_head *head;
31443164
spinlock_t *list_lock; /* protects write access to the hash lists */
@@ -3167,6 +3187,12 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
31673187
tt_local = container_of(tt_common,
31683188
struct batadv_tt_local_entry,
31693189
common);
3190+
3191+
/* decrease the reference held for this vlan */
3192+
vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
3193+
batadv_softif_vlan_free_ref(vlan);
3194+
batadv_softif_vlan_free_ref(vlan);
3195+
31703196
batadv_tt_local_entry_free_ref(tt_local);
31713197
}
31723198
spin_unlock_bh(list_lock);

net/batman-adv/types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ struct batadv_priv_nc {
687687

688688
/**
689689
* struct batadv_softif_vlan - per VLAN attributes set
690+
* @bat_priv: pointer to the mesh object
690691
* @vid: VLAN identifier
691692
* @kobj: kobject for sysfs vlan subdirectory
692693
* @ap_isolation: AP isolation state
@@ -696,6 +697,7 @@ struct batadv_priv_nc {
696697
* @rcu: struct used for freeing in a RCU-safe manner
697698
*/
698699
struct batadv_softif_vlan {
700+
struct batadv_priv *bat_priv;
699701
unsigned short vid;
700702
struct kobject *kobj;
701703
atomic_t ap_isolation; /* boolean */

0 commit comments

Comments
 (0)