ath11k: fix duplication peer create on same radio
authorKarthikeyan Periyasamy <periyasa@codeaurora.org>
Wed, 8 Apr 2020 11:03:15 +0000 (16:33 +0530)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 14 Apr 2020 08:07:48 +0000 (11:07 +0300)
Add the pdev index information in the peer object to validate
the peer creation. Ignore the peer creation request, if the given
MAC address is already present in the peer list with same radio.
If we allow the peer creation in above scenario, FW assert will happen.
Above scenario occurred in two cases, where Multiple AP VAP created in
the same radio.

1. when testing tool sends association request to two AP with same
   MAC address
2. when a station do roaming from one AP VAP to another AP VAP.

Signed-off-by: Karthikeyan Periyasamy <periyasa@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1586343795-21422-1-git-send-email-periyasa@codeaurora.org
drivers/net/wireless/ath/ath11k/peer.c
drivers/net/wireless/ath/ath11k/peer.h

index f43deacc01bd6d466370bf48eea27638eed30a4b..297172538620d70e442e013d61022a881e567c2f 100644 (file)
@@ -17,7 +17,26 @@ struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
        list_for_each_entry(peer, &ab->peers, list) {
                if (peer->vdev_id != vdev_id)
                        continue;
-               if (memcmp(peer->addr, addr, ETH_ALEN))
+               if (!ether_addr_equal(peer->addr, addr))
+                       continue;
+
+               return peer;
+       }
+
+       return NULL;
+}
+
+static struct ath11k_peer *ath11k_peer_find_by_pdev_idx(struct ath11k_base *ab,
+                                                       u8 pdev_idx, const u8 *addr)
+{
+       struct ath11k_peer *peer;
+
+       lockdep_assert_held(&ab->base_lock);
+
+       list_for_each_entry(peer, &ab->peers, list) {
+               if (peer->pdev_idx != pdev_idx)
+                       continue;
+               if (!ether_addr_equal(peer->addr, addr))
                        continue;
 
                return peer;
@@ -34,7 +53,7 @@ struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
        lockdep_assert_held(&ab->base_lock);
 
        list_for_each_entry(peer, &ab->peers, list) {
-               if (memcmp(peer->addr, addr, ETH_ALEN))
+               if (!ether_addr_equal(peer->addr, addr))
                        continue;
 
                return peer;
@@ -200,6 +219,17 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
                return -ENOBUFS;
        }
 
+       spin_lock_bh(&ar->ab->base_lock);
+       peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr);
+       if (peer) {
+               spin_unlock_bh(&ar->ab->base_lock);
+               ath11k_info(ar->ab,
+                           "ignoring the peer %pM creation on same pdev idx %d\n",
+                           param->peer_addr, ar->pdev_idx);
+               return -EINVAL;
+       }
+       spin_unlock_bh(&ar->ab->base_lock);
+
        ret = ath11k_wmi_send_peer_create_cmd(ar, param);
        if (ret) {
                ath11k_warn(ar->ab,
@@ -225,6 +255,7 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
                return -ENOENT;
        }
 
+       peer->pdev_idx = ar->pdev_idx;
        peer->sta = sta;
        arvif->ast_hash = peer->ast_hash;
 
index ccca1523a6ea055e7229421e338358bf7b7812d7..5d125ce8984e3b495784dd214ae6e8ec749f871e 100644 (file)
@@ -13,6 +13,7 @@ struct ath11k_peer {
        u8 addr[ETH_ALEN];
        int peer_id;
        u16 ast_hash;
+       u8 pdev_idx;
 
        /* protected by ab->data_lock */
        struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];