Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause-Clear
0002 /*
0003  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
0004  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
0005  */
0006 
0007 #include "core.h"
0008 #include "peer.h"
0009 #include "debug.h"
0010 
0011 static struct ath11k_peer *ath11k_peer_find_list_by_id(struct ath11k_base *ab,
0012                                int peer_id)
0013 {
0014     struct ath11k_peer *peer;
0015 
0016     lockdep_assert_held(&ab->base_lock);
0017 
0018     list_for_each_entry(peer, &ab->peers, list) {
0019         if (peer->peer_id != peer_id)
0020             continue;
0021 
0022         return peer;
0023     }
0024 
0025     return NULL;
0026 }
0027 
0028 struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
0029                      const u8 *addr)
0030 {
0031     struct ath11k_peer *peer;
0032 
0033     lockdep_assert_held(&ab->base_lock);
0034 
0035     list_for_each_entry(peer, &ab->peers, list) {
0036         if (peer->vdev_id != vdev_id)
0037             continue;
0038         if (!ether_addr_equal(peer->addr, addr))
0039             continue;
0040 
0041         return peer;
0042     }
0043 
0044     return NULL;
0045 }
0046 
0047 struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
0048                          const u8 *addr)
0049 {
0050     struct ath11k_peer *peer;
0051 
0052     lockdep_assert_held(&ab->base_lock);
0053 
0054     if (!ab->rhead_peer_addr)
0055         return NULL;
0056 
0057     peer = rhashtable_lookup_fast(ab->rhead_peer_addr, addr,
0058                       ab->rhash_peer_addr_param);
0059 
0060     return peer;
0061 }
0062 
0063 struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab,
0064                        int peer_id)
0065 {
0066     struct ath11k_peer *peer;
0067 
0068     lockdep_assert_held(&ab->base_lock);
0069 
0070     if (!ab->rhead_peer_id)
0071         return NULL;
0072 
0073     peer = rhashtable_lookup_fast(ab->rhead_peer_id, &peer_id,
0074                       ab->rhash_peer_id_param);
0075 
0076     return peer;
0077 }
0078 
0079 struct ath11k_peer *ath11k_peer_find_by_vdev_id(struct ath11k_base *ab,
0080                         int vdev_id)
0081 {
0082     struct ath11k_peer *peer;
0083 
0084     spin_lock_bh(&ab->base_lock);
0085 
0086     list_for_each_entry(peer, &ab->peers, list) {
0087         if (vdev_id == peer->vdev_id) {
0088             spin_unlock_bh(&ab->base_lock);
0089             return peer;
0090         }
0091     }
0092     spin_unlock_bh(&ab->base_lock);
0093     return NULL;
0094 }
0095 
0096 void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
0097 {
0098     struct ath11k_peer *peer;
0099 
0100     spin_lock_bh(&ab->base_lock);
0101 
0102     peer = ath11k_peer_find_list_by_id(ab, peer_id);
0103     if (!peer) {
0104         ath11k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
0105                 peer_id);
0106         goto exit;
0107     }
0108 
0109     ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
0110            peer->vdev_id, peer->addr, peer_id);
0111 
0112     list_del(&peer->list);
0113     kfree(peer);
0114     wake_up(&ab->peer_mapping_wq);
0115 
0116 exit:
0117     spin_unlock_bh(&ab->base_lock);
0118 }
0119 
0120 void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
0121                u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
0122 {
0123     struct ath11k_peer *peer;
0124 
0125     spin_lock_bh(&ab->base_lock);
0126     peer = ath11k_peer_find(ab, vdev_id, mac_addr);
0127     if (!peer) {
0128         peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
0129         if (!peer)
0130             goto exit;
0131 
0132         peer->vdev_id = vdev_id;
0133         peer->peer_id = peer_id;
0134         peer->ast_hash = ast_hash;
0135         peer->hw_peer_id = hw_peer_id;
0136         ether_addr_copy(peer->addr, mac_addr);
0137         list_add(&peer->list, &ab->peers);
0138         wake_up(&ab->peer_mapping_wq);
0139     }
0140 
0141     ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n",
0142            vdev_id, mac_addr, peer_id);
0143 
0144 exit:
0145     spin_unlock_bh(&ab->base_lock);
0146 }
0147 
0148 static int ath11k_wait_for_peer_common(struct ath11k_base *ab, int vdev_id,
0149                        const u8 *addr, bool expect_mapped)
0150 {
0151     int ret;
0152 
0153     ret = wait_event_timeout(ab->peer_mapping_wq, ({
0154                 bool mapped;
0155 
0156                 spin_lock_bh(&ab->base_lock);
0157                 mapped = !!ath11k_peer_find(ab, vdev_id, addr);
0158                 spin_unlock_bh(&ab->base_lock);
0159 
0160                 (mapped == expect_mapped ||
0161                  test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags));
0162                 }), 3 * HZ);
0163 
0164     if (ret <= 0)
0165         return -ETIMEDOUT;
0166 
0167     return 0;
0168 }
0169 
0170 static inline int ath11k_peer_rhash_insert(struct ath11k_base *ab,
0171                        struct rhashtable *rtbl,
0172                        struct rhash_head *rhead,
0173                        struct rhashtable_params *params,
0174                        void *key)
0175 {
0176     struct ath11k_peer *tmp;
0177 
0178     lockdep_assert_held(&ab->tbl_mtx_lock);
0179 
0180     tmp = rhashtable_lookup_get_insert_fast(rtbl, rhead, *params);
0181 
0182     if (!tmp)
0183         return 0;
0184     else if (IS_ERR(tmp))
0185         return PTR_ERR(tmp);
0186     else
0187         return -EEXIST;
0188 }
0189 
0190 static inline int ath11k_peer_rhash_remove(struct ath11k_base *ab,
0191                        struct rhashtable *rtbl,
0192                        struct rhash_head *rhead,
0193                        struct rhashtable_params *params)
0194 {
0195     int ret;
0196 
0197     lockdep_assert_held(&ab->tbl_mtx_lock);
0198 
0199     ret = rhashtable_remove_fast(rtbl, rhead, *params);
0200     if (ret && ret != -ENOENT)
0201         return ret;
0202 
0203     return 0;
0204 }
0205 
0206 static int ath11k_peer_rhash_add(struct ath11k_base *ab, struct ath11k_peer *peer)
0207 {
0208     int ret;
0209 
0210     lockdep_assert_held(&ab->base_lock);
0211     lockdep_assert_held(&ab->tbl_mtx_lock);
0212 
0213     if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
0214         return -EPERM;
0215 
0216     ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_id, &peer->rhash_id,
0217                        &ab->rhash_peer_id_param, &peer->peer_id);
0218     if (ret) {
0219         ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_id ret %d\n",
0220                 peer->addr, peer->peer_id, ret);
0221         return ret;
0222     }
0223 
0224     ret = ath11k_peer_rhash_insert(ab, ab->rhead_peer_addr, &peer->rhash_addr,
0225                        &ab->rhash_peer_addr_param, &peer->addr);
0226     if (ret) {
0227         ath11k_warn(ab, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
0228                 peer->addr, peer->peer_id, ret);
0229         goto err_clean;
0230     }
0231 
0232     return 0;
0233 
0234 err_clean:
0235     ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
0236                  &ab->rhash_peer_id_param);
0237     return ret;
0238 }
0239 
0240 void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id)
0241 {
0242     struct ath11k_peer *peer, *tmp;
0243     struct ath11k_base *ab = ar->ab;
0244 
0245     lockdep_assert_held(&ar->conf_mutex);
0246 
0247     mutex_lock(&ab->tbl_mtx_lock);
0248     spin_lock_bh(&ab->base_lock);
0249     list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
0250         if (peer->vdev_id != vdev_id)
0251             continue;
0252 
0253         ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
0254                 peer->addr, vdev_id);
0255 
0256         ath11k_peer_rhash_delete(ab, peer);
0257         list_del(&peer->list);
0258         kfree(peer);
0259         ar->num_peers--;
0260     }
0261 
0262     spin_unlock_bh(&ab->base_lock);
0263     mutex_unlock(&ab->tbl_mtx_lock);
0264 }
0265 
0266 static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
0267 {
0268     return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
0269 }
0270 
0271 int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
0272                      const u8 *addr)
0273 {
0274     int ret;
0275     unsigned long time_left;
0276 
0277     ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
0278     if (ret) {
0279         ath11k_warn(ar->ab, "failed wait for peer deleted");
0280         return ret;
0281     }
0282 
0283     time_left = wait_for_completion_timeout(&ar->peer_delete_done,
0284                         3 * HZ);
0285     if (time_left == 0) {
0286         ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
0287         return -ETIMEDOUT;
0288     }
0289 
0290     return 0;
0291 }
0292 
0293 static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr)
0294 {
0295     int ret;
0296     struct ath11k_peer *peer;
0297     struct ath11k_base *ab = ar->ab;
0298 
0299     lockdep_assert_held(&ar->conf_mutex);
0300 
0301     mutex_lock(&ab->tbl_mtx_lock);
0302     spin_lock_bh(&ab->base_lock);
0303 
0304     peer = ath11k_peer_find_by_addr(ab, addr);
0305     if (!peer) {
0306         spin_unlock_bh(&ab->base_lock);
0307         mutex_unlock(&ab->tbl_mtx_lock);
0308 
0309         ath11k_warn(ab,
0310                 "failed to find peer vdev_id %d addr %pM in delete\n",
0311                 vdev_id, addr);
0312         return -EINVAL;
0313     }
0314 
0315     ath11k_peer_rhash_delete(ab, peer);
0316 
0317     spin_unlock_bh(&ab->base_lock);
0318     mutex_unlock(&ab->tbl_mtx_lock);
0319 
0320     reinit_completion(&ar->peer_delete_done);
0321 
0322     ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
0323     if (ret) {
0324         ath11k_warn(ab,
0325                 "failed to delete peer vdev_id %d addr %pM ret %d\n",
0326                 vdev_id, addr, ret);
0327         return ret;
0328     }
0329 
0330     ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr);
0331     if (ret)
0332         return ret;
0333 
0334     return 0;
0335 }
0336 
0337 int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
0338 {
0339     int ret;
0340 
0341     lockdep_assert_held(&ar->conf_mutex);
0342 
0343     ret = __ath11k_peer_delete(ar, vdev_id, addr);
0344     if (ret)
0345         return ret;
0346 
0347     ar->num_peers--;
0348 
0349     return 0;
0350 }
0351 
0352 static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8 *addr)
0353 {
0354     return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
0355 }
0356 
0357 int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
0358                struct ieee80211_sta *sta, struct peer_create_params *param)
0359 {
0360     struct ath11k_peer *peer;
0361     struct ath11k_sta *arsta;
0362     int ret, fbret;
0363 
0364     lockdep_assert_held(&ar->conf_mutex);
0365 
0366     if (ar->num_peers > (ar->max_num_peers - 1)) {
0367         ath11k_warn(ar->ab,
0368                 "failed to create peer due to insufficient peer entry resource in firmware\n");
0369         return -ENOBUFS;
0370     }
0371 
0372     spin_lock_bh(&ar->ab->base_lock);
0373     peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr);
0374     if (peer) {
0375         spin_unlock_bh(&ar->ab->base_lock);
0376         return -EINVAL;
0377     }
0378     spin_unlock_bh(&ar->ab->base_lock);
0379 
0380     ret = ath11k_wmi_send_peer_create_cmd(ar, param);
0381     if (ret) {
0382         ath11k_warn(ar->ab,
0383                 "failed to send peer create vdev_id %d ret %d\n",
0384                 param->vdev_id, ret);
0385         return ret;
0386     }
0387 
0388     ret = ath11k_wait_for_peer_created(ar, param->vdev_id,
0389                        param->peer_addr);
0390     if (ret)
0391         return ret;
0392 
0393     mutex_lock(&ar->ab->tbl_mtx_lock);
0394     spin_lock_bh(&ar->ab->base_lock);
0395 
0396     peer = ath11k_peer_find(ar->ab, param->vdev_id, param->peer_addr);
0397     if (!peer) {
0398         spin_unlock_bh(&ar->ab->base_lock);
0399         mutex_unlock(&ar->ab->tbl_mtx_lock);
0400         ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
0401                 param->peer_addr, param->vdev_id);
0402 
0403         ret = -ENOENT;
0404         goto cleanup;
0405     }
0406 
0407     ret = ath11k_peer_rhash_add(ar->ab, peer);
0408     if (ret) {
0409         spin_unlock_bh(&ar->ab->base_lock);
0410         mutex_unlock(&ar->ab->tbl_mtx_lock);
0411         goto cleanup;
0412     }
0413 
0414     peer->pdev_idx = ar->pdev_idx;
0415     peer->sta = sta;
0416 
0417     if (arvif->vif->type == NL80211_IFTYPE_STATION) {
0418         arvif->ast_hash = peer->ast_hash;
0419         arvif->ast_idx = peer->hw_peer_id;
0420     }
0421 
0422     peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
0423     peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
0424 
0425     if (sta) {
0426         arsta = (struct ath11k_sta *)sta->drv_priv;
0427         arsta->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 0) |
0428                        FIELD_PREP(HTT_TCL_META_DATA_PEER_ID,
0429                           peer->peer_id);
0430 
0431         /* set HTT extension valid bit to 0 by default */
0432         arsta->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT;
0433     }
0434 
0435     ar->num_peers++;
0436 
0437     spin_unlock_bh(&ar->ab->base_lock);
0438     mutex_unlock(&ar->ab->tbl_mtx_lock);
0439 
0440     return 0;
0441 
0442 cleanup:
0443     fbret = __ath11k_peer_delete(ar, param->vdev_id, param->peer_addr);
0444     if (fbret)
0445         ath11k_warn(ar->ab, "failed peer %pM delete vdev_id %d fallback ret %d\n",
0446                 param->peer_addr, param->vdev_id, fbret);
0447 
0448     return ret;
0449 }
0450 
0451 int ath11k_peer_rhash_delete(struct ath11k_base *ab, struct ath11k_peer *peer)
0452 {
0453     int ret;
0454 
0455     lockdep_assert_held(&ab->base_lock);
0456     lockdep_assert_held(&ab->tbl_mtx_lock);
0457 
0458     if (!ab->rhead_peer_id || !ab->rhead_peer_addr)
0459         return -EPERM;
0460 
0461     ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_addr, &peer->rhash_addr,
0462                        &ab->rhash_peer_addr_param);
0463     if (ret) {
0464         ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_addr ret %d\n",
0465                 peer->addr, peer->peer_id, ret);
0466         return ret;
0467     }
0468 
0469     ret = ath11k_peer_rhash_remove(ab, ab->rhead_peer_id, &peer->rhash_id,
0470                        &ab->rhash_peer_id_param);
0471     if (ret) {
0472         ath11k_warn(ab, "failed to remove peer %pM id %d in rhash_id ret %d\n",
0473                 peer->addr, peer->peer_id, ret);
0474         return ret;
0475     }
0476 
0477     return 0;
0478 }
0479 
0480 static int ath11k_peer_rhash_id_tbl_init(struct ath11k_base *ab)
0481 {
0482     struct rhashtable_params *param;
0483     struct rhashtable *rhash_id_tbl;
0484     int ret;
0485     size_t size;
0486 
0487     lockdep_assert_held(&ab->tbl_mtx_lock);
0488 
0489     if (ab->rhead_peer_id)
0490         return 0;
0491 
0492     size = sizeof(*ab->rhead_peer_id);
0493     rhash_id_tbl = kzalloc(size, GFP_KERNEL);
0494     if (!rhash_id_tbl) {
0495         ath11k_warn(ab, "failed to init rhash id table due to no mem (size %zu)\n",
0496                 size);
0497         return -ENOMEM;
0498     }
0499 
0500     param = &ab->rhash_peer_id_param;
0501 
0502     param->key_offset = offsetof(struct ath11k_peer, peer_id);
0503     param->head_offset = offsetof(struct ath11k_peer, rhash_id);
0504     param->key_len = sizeof_field(struct ath11k_peer, peer_id);
0505     param->automatic_shrinking = true;
0506     param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
0507 
0508     ret = rhashtable_init(rhash_id_tbl, param);
0509     if (ret) {
0510         ath11k_warn(ab, "failed to init peer id rhash table %d\n", ret);
0511         goto err_free;
0512     }
0513 
0514     spin_lock_bh(&ab->base_lock);
0515 
0516     if (!ab->rhead_peer_id) {
0517         ab->rhead_peer_id = rhash_id_tbl;
0518     } else {
0519         spin_unlock_bh(&ab->base_lock);
0520         goto cleanup_tbl;
0521     }
0522 
0523     spin_unlock_bh(&ab->base_lock);
0524 
0525     return 0;
0526 
0527 cleanup_tbl:
0528     rhashtable_destroy(rhash_id_tbl);
0529 err_free:
0530     kfree(rhash_id_tbl);
0531 
0532     return ret;
0533 }
0534 
0535 static int ath11k_peer_rhash_addr_tbl_init(struct ath11k_base *ab)
0536 {
0537     struct rhashtable_params *param;
0538     struct rhashtable *rhash_addr_tbl;
0539     int ret;
0540     size_t size;
0541 
0542     lockdep_assert_held(&ab->tbl_mtx_lock);
0543 
0544     if (ab->rhead_peer_addr)
0545         return 0;
0546 
0547     size = sizeof(*ab->rhead_peer_addr);
0548     rhash_addr_tbl = kzalloc(size, GFP_KERNEL);
0549     if (!rhash_addr_tbl) {
0550         ath11k_warn(ab, "failed to init rhash addr table due to no mem (size %zu)\n",
0551                 size);
0552         return -ENOMEM;
0553     }
0554 
0555     param = &ab->rhash_peer_addr_param;
0556 
0557     param->key_offset = offsetof(struct ath11k_peer, addr);
0558     param->head_offset = offsetof(struct ath11k_peer, rhash_addr);
0559     param->key_len = sizeof_field(struct ath11k_peer, addr);
0560     param->automatic_shrinking = true;
0561     param->nelem_hint = ab->num_radios * TARGET_NUM_PEERS_PDEV(ab);
0562 
0563     ret = rhashtable_init(rhash_addr_tbl, param);
0564     if (ret) {
0565         ath11k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
0566         goto err_free;
0567     }
0568 
0569     spin_lock_bh(&ab->base_lock);
0570 
0571     if (!ab->rhead_peer_addr) {
0572         ab->rhead_peer_addr = rhash_addr_tbl;
0573     } else {
0574         spin_unlock_bh(&ab->base_lock);
0575         goto cleanup_tbl;
0576     }
0577 
0578     spin_unlock_bh(&ab->base_lock);
0579 
0580     return 0;
0581 
0582 cleanup_tbl:
0583     rhashtable_destroy(rhash_addr_tbl);
0584 err_free:
0585     kfree(rhash_addr_tbl);
0586 
0587     return ret;
0588 }
0589 
0590 static inline void ath11k_peer_rhash_id_tbl_destroy(struct ath11k_base *ab)
0591 {
0592     lockdep_assert_held(&ab->tbl_mtx_lock);
0593 
0594     if (!ab->rhead_peer_id)
0595         return;
0596 
0597     rhashtable_destroy(ab->rhead_peer_id);
0598     kfree(ab->rhead_peer_id);
0599     ab->rhead_peer_id = NULL;
0600 }
0601 
0602 static inline void ath11k_peer_rhash_addr_tbl_destroy(struct ath11k_base *ab)
0603 {
0604     lockdep_assert_held(&ab->tbl_mtx_lock);
0605 
0606     if (!ab->rhead_peer_addr)
0607         return;
0608 
0609     rhashtable_destroy(ab->rhead_peer_addr);
0610     kfree(ab->rhead_peer_addr);
0611     ab->rhead_peer_addr = NULL;
0612 }
0613 
0614 int ath11k_peer_rhash_tbl_init(struct ath11k_base *ab)
0615 {
0616     int ret;
0617 
0618     mutex_lock(&ab->tbl_mtx_lock);
0619 
0620     ret = ath11k_peer_rhash_id_tbl_init(ab);
0621     if (ret)
0622         goto out;
0623 
0624     ret = ath11k_peer_rhash_addr_tbl_init(ab);
0625     if (ret)
0626         goto cleanup_tbl;
0627 
0628     mutex_unlock(&ab->tbl_mtx_lock);
0629 
0630     return 0;
0631 
0632 cleanup_tbl:
0633     ath11k_peer_rhash_id_tbl_destroy(ab);
0634 out:
0635     mutex_unlock(&ab->tbl_mtx_lock);
0636     return ret;
0637 }
0638 
0639 void ath11k_peer_rhash_tbl_destroy(struct ath11k_base *ab)
0640 {
0641     mutex_lock(&ab->tbl_mtx_lock);
0642 
0643     ath11k_peer_rhash_addr_tbl_destroy(ab);
0644     ath11k_peer_rhash_id_tbl_destroy(ab);
0645 
0646     mutex_unlock(&ab->tbl_mtx_lock);
0647 }