diff options
| -rw-r--r-- | net/batman-adv/bridge_loop_avoidance.c | 44 | ||||
| -rw-r--r-- | net/batman-adv/soft-interface.c | 60 | ||||
| -rw-r--r-- | net/batman-adv/translation-table.c | 26 | ||||
| -rw-r--r-- | net/batman-adv/types.h | 2 |
4 files changed, 108 insertions, 24 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, | |||
| 800 | bla_dst = (struct batadv_bla_claim_dst *)hw_dst; | 800 | bla_dst = (struct batadv_bla_claim_dst *)hw_dst; |
| 801 | bla_dst_own = &bat_priv->bla.claim_dest; | 801 | bla_dst_own = &bat_priv->bla.claim_dest; |
| 802 | 802 | ||
| 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 | |||
| 808 | /* if announcement packet, use the source, | 803 | /* if announcement packet, use the source, |
| 809 | * otherwise assume it is in the hw_src | 804 | * otherwise assume it is in the hw_src |
| 810 | */ | 805 | */ |
| @@ -866,12 +861,13 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, | |||
| 866 | struct batadv_hard_iface *primary_if, | 861 | struct batadv_hard_iface *primary_if, |
| 867 | struct sk_buff *skb) | 862 | struct sk_buff *skb) |
| 868 | { | 863 | { |
| 869 | struct batadv_bla_claim_dst *bla_dst; | 864 | struct batadv_bla_claim_dst *bla_dst, *bla_dst_own; |
| 870 | uint8_t *hw_src, *hw_dst; | 865 | uint8_t *hw_src, *hw_dst; |
| 871 | struct vlan_ethhdr *vhdr; | 866 | struct vlan_hdr *vhdr, vhdr_buf; |
| 872 | struct ethhdr *ethhdr; | 867 | struct ethhdr *ethhdr; |
| 873 | struct arphdr *arphdr; | 868 | struct arphdr *arphdr; |
| 874 | unsigned short vid; | 869 | unsigned short vid; |
| 870 | int vlan_depth = 0; | ||
| 875 | __be16 proto; | 871 | __be16 proto; |
| 876 | int headlen; | 872 | int headlen; |
| 877 | int ret; | 873 | int ret; |
| @@ -882,9 +878,24 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, | |||
| 882 | proto = ethhdr->h_proto; | 878 | proto = ethhdr->h_proto; |
| 883 | headlen = ETH_HLEN; | 879 | headlen = ETH_HLEN; |
| 884 | if (vid & BATADV_VLAN_HAS_TAG) { | 880 | if (vid & BATADV_VLAN_HAS_TAG) { |
| 885 | vhdr = vlan_eth_hdr(skb); | 881 | /* Traverse the VLAN/Ethertypes. |
| 886 | proto = vhdr->h_vlan_encapsulated_proto; | 882 | * |
| 887 | headlen += VLAN_HLEN; | 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)); | ||
| 888 | } | 899 | } |
| 889 | 900 | ||
| 890 | if (proto != htons(ETH_P_ARP)) | 901 | if (proto != htons(ETH_P_ARP)) |
| @@ -914,6 +925,19 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, | |||
| 914 | hw_src = (uint8_t *)arphdr + sizeof(struct arphdr); | 925 | hw_src = (uint8_t *)arphdr + sizeof(struct arphdr); |
| 915 | hw_dst = hw_src + ETH_ALEN + 4; | 926 | hw_dst = hw_src + ETH_ALEN + 4; |
| 916 | bla_dst = (struct batadv_bla_claim_dst *)hw_dst; | 927 | 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; | ||
| 917 | 941 | ||
| 918 | /* check if it is a claim frame. */ | 942 | /* check if it is a claim frame. */ |
| 919 | ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst, | 943 | ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst, |
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index e7ee65dc20bf..cbd677f48c00 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
| @@ -448,10 +448,15 @@ out: | |||
| 448 | * possibly free it | 448 | * possibly free it |
| 449 | * @softif_vlan: the vlan object to release | 449 | * @softif_vlan: the vlan object to release |
| 450 | */ | 450 | */ |
| 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) |
| 452 | { | 452 | { |
| 453 | if (atomic_dec_and_test(&softif_vlan->refcount)) | 453 | if (atomic_dec_and_test(&vlan->refcount)) { |
| 454 | kfree_rcu(softif_vlan, rcu); | 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 | } | ||
| 455 | } | 460 | } |
| 456 | 461 | ||
| 457 | /** | 462 | /** |
| @@ -505,6 +510,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
| 505 | if (!vlan) | 510 | if (!vlan) |
| 506 | return -ENOMEM; | 511 | return -ENOMEM; |
| 507 | 512 | ||
| 513 | vlan->bat_priv = bat_priv; | ||
| 508 | vlan->vid = vid; | 514 | vlan->vid = vid; |
| 509 | atomic_set(&vlan->refcount, 1); | 515 | atomic_set(&vlan->refcount, 1); |
| 510 | 516 | ||
| @@ -516,6 +522,10 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
| 516 | return err; | 522 | return err; |
| 517 | } | 523 | } |
| 518 | 524 | ||
| 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 | |||
| 519 | /* add a new TT local entry. This one will be marked with the NOPURGE | 529 | /* add a new TT local entry. This one will be marked with the NOPURGE |
| 520 | * flag | 530 | * flag |
| 521 | */ | 531 | */ |
| @@ -523,10 +533,6 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
| 523 | bat_priv->soft_iface->dev_addr, vid, | 533 | bat_priv->soft_iface->dev_addr, vid, |
| 524 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); | 534 | BATADV_NULL_IFINDEX, BATADV_NO_MARK); |
| 525 | 535 | ||
| 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 | |||
| 530 | return 0; | 536 | return 0; |
| 531 | } | 537 | } |
| 532 | 538 | ||
| @@ -538,18 +544,13 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | |||
| 538 | static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv, | 544 | static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv, |
| 539 | struct batadv_softif_vlan *vlan) | 545 | struct batadv_softif_vlan *vlan) |
| 540 | { | 546 | { |
| 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 | |||
| 547 | /* explicitly remove the associated TT local entry because it is marked | 547 | /* explicitly remove the associated TT local entry because it is marked |
| 548 | * with the NOPURGE flag | 548 | * with the NOPURGE flag |
| 549 | */ | 549 | */ |
| 550 | batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr, | 550 | batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr, |
| 551 | vlan->vid, "vlan interface destroyed", false); | 551 | vlan->vid, "vlan interface destroyed", false); |
| 552 | 552 | ||
| 553 | batadv_sysfs_del_vlan(bat_priv, vlan); | ||
| 553 | batadv_softif_vlan_free_ref(vlan); | 554 | batadv_softif_vlan_free_ref(vlan); |
| 554 | } | 555 | } |
| 555 | 556 | ||
| @@ -567,6 +568,8 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto, | |||
| 567 | unsigned short vid) | 568 | unsigned short vid) |
| 568 | { | 569 | { |
| 569 | struct batadv_priv *bat_priv = netdev_priv(dev); | 570 | struct batadv_priv *bat_priv = netdev_priv(dev); |
| 571 | struct batadv_softif_vlan *vlan; | ||
| 572 | int ret; | ||
| 570 | 573 | ||
| 571 | /* only 802.1Q vlans are supported. | 574 | /* only 802.1Q vlans are supported. |
| 572 | * batman-adv does not know how to handle other types | 575 | * 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, | |||
| 576 | 579 | ||
| 577 | vid |= BATADV_VLAN_HAS_TAG; | 580 | vid |= BATADV_VLAN_HAS_TAG; |
| 578 | 581 | ||
| 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; | ||
| 580 | } | 612 | } |
| 581 | 613 | ||
| 582 | /** | 614 | /** |
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index d636bde72c9a..5f59e7f899a0 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
| @@ -511,6 +511,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
| 511 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 511 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
| 512 | struct batadv_tt_local_entry *tt_local; | 512 | struct batadv_tt_local_entry *tt_local; |
| 513 | struct batadv_tt_global_entry *tt_global = NULL; | 513 | struct batadv_tt_global_entry *tt_global = NULL; |
| 514 | struct batadv_softif_vlan *vlan; | ||
| 514 | struct net_device *in_dev = NULL; | 515 | struct net_device *in_dev = NULL; |
| 515 | struct hlist_head *head; | 516 | struct hlist_head *head; |
| 516 | struct batadv_tt_orig_list_entry *orig_entry; | 517 | 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, | |||
| 572 | if (!tt_local) | 573 | if (!tt_local) |
| 573 | goto out; | 574 | goto out; |
| 574 | 575 | ||
| 576 | /* increase the refcounter of the related vlan */ | ||
| 577 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
| 578 | |||
| 575 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 579 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
| 576 | "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", | 580 | "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", |
| 577 | addr, BATADV_PRINT_VID(vid), | 581 | addr, BATADV_PRINT_VID(vid), |
| @@ -604,6 +608,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
| 604 | if (unlikely(hash_added != 0)) { | 608 | if (unlikely(hash_added != 0)) { |
| 605 | /* remove the reference for the hash */ | 609 | /* remove the reference for the hash */ |
| 606 | batadv_tt_local_entry_free_ref(tt_local); | 610 | batadv_tt_local_entry_free_ref(tt_local); |
| 611 | batadv_softif_vlan_free_ref(vlan); | ||
| 607 | goto out; | 612 | goto out; |
| 608 | } | 613 | } |
| 609 | 614 | ||
| @@ -1009,6 +1014,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | |||
| 1009 | { | 1014 | { |
| 1010 | struct batadv_tt_local_entry *tt_local_entry; | 1015 | struct batadv_tt_local_entry *tt_local_entry; |
| 1011 | uint16_t flags, curr_flags = BATADV_NO_FLAGS; | 1016 | uint16_t flags, curr_flags = BATADV_NO_FLAGS; |
| 1017 | struct batadv_softif_vlan *vlan; | ||
| 1012 | 1018 | ||
| 1013 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); | 1019 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
| 1014 | if (!tt_local_entry) | 1020 | if (!tt_local_entry) |
| @@ -1039,6 +1045,11 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | |||
| 1039 | hlist_del_rcu(&tt_local_entry->common.hash_entry); | 1045 | hlist_del_rcu(&tt_local_entry->common.hash_entry); |
| 1040 | batadv_tt_local_entry_free_ref(tt_local_entry); | 1046 | batadv_tt_local_entry_free_ref(tt_local_entry); |
| 1041 | 1047 | ||
| 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 | |||
| 1042 | out: | 1053 | out: |
| 1043 | if (tt_local_entry) | 1054 | if (tt_local_entry) |
| 1044 | batadv_tt_local_entry_free_ref(tt_local_entry); | 1055 | 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) | |||
| 1111 | spinlock_t *list_lock; /* protects write access to the hash lists */ | 1122 | spinlock_t *list_lock; /* protects write access to the hash lists */ |
| 1112 | struct batadv_tt_common_entry *tt_common_entry; | 1123 | struct batadv_tt_common_entry *tt_common_entry; |
| 1113 | struct batadv_tt_local_entry *tt_local; | 1124 | struct batadv_tt_local_entry *tt_local; |
| 1125 | struct batadv_softif_vlan *vlan; | ||
| 1114 | struct hlist_node *node_tmp; | 1126 | struct hlist_node *node_tmp; |
| 1115 | struct hlist_head *head; | 1127 | struct hlist_head *head; |
| 1116 | uint32_t i; | 1128 | uint32_t i; |
| @@ -1131,6 +1143,13 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) | |||
| 1131 | tt_local = container_of(tt_common_entry, | 1143 | tt_local = container_of(tt_common_entry, |
| 1132 | struct batadv_tt_local_entry, | 1144 | struct batadv_tt_local_entry, |
| 1133 | common); | 1145 | 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 | |||
| 1134 | batadv_tt_local_entry_free_ref(tt_local); | 1153 | batadv_tt_local_entry_free_ref(tt_local); |
| 1135 | } | 1154 | } |
| 1136 | spin_unlock_bh(list_lock); | 1155 | spin_unlock_bh(list_lock); |
| @@ -3139,6 +3158,7 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) | |||
| 3139 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; | 3158 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
| 3140 | struct batadv_tt_common_entry *tt_common; | 3159 | struct batadv_tt_common_entry *tt_common; |
| 3141 | struct batadv_tt_local_entry *tt_local; | 3160 | struct batadv_tt_local_entry *tt_local; |
| 3161 | struct batadv_softif_vlan *vlan; | ||
| 3142 | struct hlist_node *node_tmp; | 3162 | struct hlist_node *node_tmp; |
| 3143 | struct hlist_head *head; | 3163 | struct hlist_head *head; |
| 3144 | spinlock_t *list_lock; /* protects write access to the hash lists */ | 3164 | 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) | |||
| 3167 | tt_local = container_of(tt_common, | 3187 | tt_local = container_of(tt_common, |
| 3168 | struct batadv_tt_local_entry, | 3188 | struct batadv_tt_local_entry, |
| 3169 | common); | 3189 | 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 | |||
| 3170 | batadv_tt_local_entry_free_ref(tt_local); | 3196 | batadv_tt_local_entry_free_ref(tt_local); |
| 3171 | } | 3197 | } |
| 3172 | spin_unlock_bh(list_lock); | 3198 | spin_unlock_bh(list_lock); |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 34891a56773f..8854c05622a9 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
| @@ -687,6 +687,7 @@ struct batadv_priv_nc { | |||
| 687 | 687 | ||
| 688 | /** | 688 | /** |
| 689 | * struct batadv_softif_vlan - per VLAN attributes set | 689 | * struct batadv_softif_vlan - per VLAN attributes set |
| 690 | * @bat_priv: pointer to the mesh object | ||
| 690 | * @vid: VLAN identifier | 691 | * @vid: VLAN identifier |
| 691 | * @kobj: kobject for sysfs vlan subdirectory | 692 | * @kobj: kobject for sysfs vlan subdirectory |
| 692 | * @ap_isolation: AP isolation state | 693 | * @ap_isolation: AP isolation state |
| @@ -696,6 +697,7 @@ struct batadv_priv_nc { | |||
| 696 | * @rcu: struct used for freeing in a RCU-safe manner | 697 | * @rcu: struct used for freeing in a RCU-safe manner |
| 697 | */ | 698 | */ |
| 698 | struct batadv_softif_vlan { | 699 | struct batadv_softif_vlan { |
| 700 | struct batadv_priv *bat_priv; | ||
| 699 | unsigned short vid; | 701 | unsigned short vid; |
| 700 | struct kobject *kobj; | 702 | struct kobject *kobj; |
| 701 | atomic_t ap_isolation; /* boolean */ | 703 | atomic_t ap_isolation; /* boolean */ |
