1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear 2d5c65159SKalle Valo /* 3d5c65159SKalle Valo * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 4d5c65159SKalle Valo */ 5d5c65159SKalle Valo 6d5c65159SKalle Valo #include "core.h" 7d5c65159SKalle Valo #include "peer.h" 8d5c65159SKalle Valo #include "debug.h" 9d5c65159SKalle Valo 10d5c65159SKalle Valo struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id, 11d5c65159SKalle Valo const u8 *addr) 12d5c65159SKalle Valo { 13d5c65159SKalle Valo struct ath11k_peer *peer; 14d5c65159SKalle Valo 15d5c65159SKalle Valo lockdep_assert_held(&ab->base_lock); 16d5c65159SKalle Valo 17d5c65159SKalle Valo list_for_each_entry(peer, &ab->peers, list) { 18d5c65159SKalle Valo if (peer->vdev_id != vdev_id) 19d5c65159SKalle Valo continue; 20*1e744bf2SKarthikeyan Periyasamy if (!ether_addr_equal(peer->addr, addr)) 21*1e744bf2SKarthikeyan Periyasamy continue; 22*1e744bf2SKarthikeyan Periyasamy 23*1e744bf2SKarthikeyan Periyasamy return peer; 24*1e744bf2SKarthikeyan Periyasamy } 25*1e744bf2SKarthikeyan Periyasamy 26*1e744bf2SKarthikeyan Periyasamy return NULL; 27*1e744bf2SKarthikeyan Periyasamy } 28*1e744bf2SKarthikeyan Periyasamy 29*1e744bf2SKarthikeyan Periyasamy static struct ath11k_peer *ath11k_peer_find_by_pdev_idx(struct ath11k_base *ab, 30*1e744bf2SKarthikeyan Periyasamy u8 pdev_idx, const u8 *addr) 31*1e744bf2SKarthikeyan Periyasamy { 32*1e744bf2SKarthikeyan Periyasamy struct ath11k_peer *peer; 33*1e744bf2SKarthikeyan Periyasamy 34*1e744bf2SKarthikeyan Periyasamy lockdep_assert_held(&ab->base_lock); 35*1e744bf2SKarthikeyan Periyasamy 36*1e744bf2SKarthikeyan Periyasamy list_for_each_entry(peer, &ab->peers, list) { 37*1e744bf2SKarthikeyan Periyasamy if (peer->pdev_idx != pdev_idx) 38*1e744bf2SKarthikeyan Periyasamy continue; 39*1e744bf2SKarthikeyan Periyasamy if (!ether_addr_equal(peer->addr, addr)) 40d5c65159SKalle Valo continue; 41d5c65159SKalle Valo 42d5c65159SKalle Valo return peer; 43d5c65159SKalle Valo } 44d5c65159SKalle Valo 45d5c65159SKalle Valo return NULL; 46d5c65159SKalle Valo } 47d5c65159SKalle Valo 48d5c65159SKalle Valo struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab, 49d5c65159SKalle Valo const u8 *addr) 50d5c65159SKalle Valo { 51d5c65159SKalle Valo struct ath11k_peer *peer; 52d5c65159SKalle Valo 53d5c65159SKalle Valo lockdep_assert_held(&ab->base_lock); 54d5c65159SKalle Valo 55d5c65159SKalle Valo list_for_each_entry(peer, &ab->peers, list) { 56*1e744bf2SKarthikeyan Periyasamy if (!ether_addr_equal(peer->addr, addr)) 57d5c65159SKalle Valo continue; 58d5c65159SKalle Valo 59d5c65159SKalle Valo return peer; 60d5c65159SKalle Valo } 61d5c65159SKalle Valo 62d5c65159SKalle Valo return NULL; 63d5c65159SKalle Valo } 64d5c65159SKalle Valo 65d5c65159SKalle Valo struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, 66d5c65159SKalle Valo int peer_id) 67d5c65159SKalle Valo { 68d5c65159SKalle Valo struct ath11k_peer *peer; 69d5c65159SKalle Valo 70d5c65159SKalle Valo lockdep_assert_held(&ab->base_lock); 71d5c65159SKalle Valo 72d5c65159SKalle Valo list_for_each_entry(peer, &ab->peers, list) 73d5c65159SKalle Valo if (peer_id == peer->peer_id) 74d5c65159SKalle Valo return peer; 75d5c65159SKalle Valo 76d5c65159SKalle Valo return NULL; 77d5c65159SKalle Valo } 78d5c65159SKalle Valo 79d5c65159SKalle Valo void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id) 80d5c65159SKalle Valo { 81d5c65159SKalle Valo struct ath11k_peer *peer; 82d5c65159SKalle Valo 83d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 84d5c65159SKalle Valo 85d5c65159SKalle Valo peer = ath11k_peer_find_by_id(ab, peer_id); 86d5c65159SKalle Valo if (!peer) { 87d5c65159SKalle Valo ath11k_warn(ab, "peer-unmap-event: unknown peer id %d\n", 88d5c65159SKalle Valo peer_id); 89d5c65159SKalle Valo goto exit; 90d5c65159SKalle Valo } 91d5c65159SKalle Valo 92d5c65159SKalle Valo ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n", 93d5c65159SKalle Valo peer->vdev_id, peer->addr, peer_id); 94d5c65159SKalle Valo 95d5c65159SKalle Valo list_del(&peer->list); 96d5c65159SKalle Valo kfree(peer); 97d5c65159SKalle Valo wake_up(&ab->peer_mapping_wq); 98d5c65159SKalle Valo 99d5c65159SKalle Valo exit: 100d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 101d5c65159SKalle Valo } 102d5c65159SKalle Valo 103d5c65159SKalle Valo void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id, 104d5c65159SKalle Valo u8 *mac_addr, u16 ast_hash) 105d5c65159SKalle Valo { 106d5c65159SKalle Valo struct ath11k_peer *peer; 107d5c65159SKalle Valo 108d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 109d5c65159SKalle Valo peer = ath11k_peer_find(ab, vdev_id, mac_addr); 110d5c65159SKalle Valo if (!peer) { 111d5c65159SKalle Valo peer = kzalloc(sizeof(*peer), GFP_ATOMIC); 112d5c65159SKalle Valo if (!peer) 113d5c65159SKalle Valo goto exit; 114d5c65159SKalle Valo 115d5c65159SKalle Valo peer->vdev_id = vdev_id; 116d5c65159SKalle Valo peer->peer_id = peer_id; 117d5c65159SKalle Valo peer->ast_hash = ast_hash; 118d5c65159SKalle Valo ether_addr_copy(peer->addr, mac_addr); 119d5c65159SKalle Valo list_add(&peer->list, &ab->peers); 120d5c65159SKalle Valo wake_up(&ab->peer_mapping_wq); 121d5c65159SKalle Valo } 122d5c65159SKalle Valo 123d5c65159SKalle Valo ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n", 124d5c65159SKalle Valo vdev_id, mac_addr, peer_id); 125d5c65159SKalle Valo 126d5c65159SKalle Valo exit: 127d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 128d5c65159SKalle Valo } 129d5c65159SKalle Valo 130d5c65159SKalle Valo static int ath11k_wait_for_peer_common(struct ath11k_base *ab, int vdev_id, 131d5c65159SKalle Valo const u8 *addr, bool expect_mapped) 132d5c65159SKalle Valo { 133d5c65159SKalle Valo int ret; 134d5c65159SKalle Valo 135d5c65159SKalle Valo ret = wait_event_timeout(ab->peer_mapping_wq, ({ 136d5c65159SKalle Valo bool mapped; 137d5c65159SKalle Valo 138d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 139d5c65159SKalle Valo mapped = !!ath11k_peer_find(ab, vdev_id, addr); 140d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 141d5c65159SKalle Valo 142d5c65159SKalle Valo (mapped == expect_mapped || 143d5c65159SKalle Valo test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)); 144d5c65159SKalle Valo }), 3 * HZ); 145d5c65159SKalle Valo 146d5c65159SKalle Valo if (ret <= 0) 147d5c65159SKalle Valo return -ETIMEDOUT; 148d5c65159SKalle Valo 149d5c65159SKalle Valo return 0; 150d5c65159SKalle Valo } 151d5c65159SKalle Valo 152d5c65159SKalle Valo void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id) 153d5c65159SKalle Valo { 154d5c65159SKalle Valo struct ath11k_peer *peer, *tmp; 155d5c65159SKalle Valo struct ath11k_base *ab = ar->ab; 156d5c65159SKalle Valo 157d5c65159SKalle Valo lockdep_assert_held(&ar->conf_mutex); 158d5c65159SKalle Valo 159d5c65159SKalle Valo spin_lock_bh(&ab->base_lock); 160d5c65159SKalle Valo list_for_each_entry_safe(peer, tmp, &ab->peers, list) { 161d5c65159SKalle Valo if (peer->vdev_id != vdev_id) 162d5c65159SKalle Valo continue; 163d5c65159SKalle Valo 164d5c65159SKalle Valo ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n", 165d5c65159SKalle Valo peer->addr, vdev_id); 166d5c65159SKalle Valo 167d5c65159SKalle Valo list_del(&peer->list); 168d5c65159SKalle Valo kfree(peer); 169d5c65159SKalle Valo ar->num_peers--; 170d5c65159SKalle Valo } 171d5c65159SKalle Valo 172d5c65159SKalle Valo spin_unlock_bh(&ab->base_lock); 173d5c65159SKalle Valo } 174d5c65159SKalle Valo 175d5c65159SKalle Valo static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr) 176d5c65159SKalle Valo { 177d5c65159SKalle Valo return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false); 178d5c65159SKalle Valo } 179d5c65159SKalle Valo 180d5c65159SKalle Valo int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr) 181d5c65159SKalle Valo { 182d5c65159SKalle Valo int ret; 183d5c65159SKalle Valo 184d5c65159SKalle Valo lockdep_assert_held(&ar->conf_mutex); 185d5c65159SKalle Valo 186d5c65159SKalle Valo ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id); 187d5c65159SKalle Valo if (ret) { 188d5c65159SKalle Valo ath11k_warn(ar->ab, 189d5c65159SKalle Valo "failed to delete peer vdev_id %d addr %pM ret %d\n", 190d5c65159SKalle Valo vdev_id, addr, ret); 191d5c65159SKalle Valo return ret; 192d5c65159SKalle Valo } 193d5c65159SKalle Valo 194d5c65159SKalle Valo ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr); 195d5c65159SKalle Valo if (ret) 196d5c65159SKalle Valo return ret; 197d5c65159SKalle Valo 198d5c65159SKalle Valo ar->num_peers--; 199d5c65159SKalle Valo 200d5c65159SKalle Valo return 0; 201d5c65159SKalle Valo } 202d5c65159SKalle Valo 203d5c65159SKalle Valo static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8 *addr) 204d5c65159SKalle Valo { 205d5c65159SKalle Valo return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true); 206d5c65159SKalle Valo } 207d5c65159SKalle Valo 208d5c65159SKalle Valo int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, 209d5c65159SKalle Valo struct ieee80211_sta *sta, struct peer_create_params *param) 210d5c65159SKalle Valo { 211d5c65159SKalle Valo struct ath11k_peer *peer; 212d5c65159SKalle Valo int ret; 213d5c65159SKalle Valo 214d5c65159SKalle Valo lockdep_assert_held(&ar->conf_mutex); 215d5c65159SKalle Valo 216d5c65159SKalle Valo if (ar->num_peers > (ar->max_num_peers - 1)) { 217d5c65159SKalle Valo ath11k_warn(ar->ab, 218d5c65159SKalle Valo "failed to create peer due to insufficient peer entry resource in firmware\n"); 219d5c65159SKalle Valo return -ENOBUFS; 220d5c65159SKalle Valo } 221d5c65159SKalle Valo 222*1e744bf2SKarthikeyan Periyasamy spin_lock_bh(&ar->ab->base_lock); 223*1e744bf2SKarthikeyan Periyasamy peer = ath11k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, param->peer_addr); 224*1e744bf2SKarthikeyan Periyasamy if (peer) { 225*1e744bf2SKarthikeyan Periyasamy spin_unlock_bh(&ar->ab->base_lock); 226*1e744bf2SKarthikeyan Periyasamy return -EINVAL; 227*1e744bf2SKarthikeyan Periyasamy } 228*1e744bf2SKarthikeyan Periyasamy spin_unlock_bh(&ar->ab->base_lock); 229*1e744bf2SKarthikeyan Periyasamy 230d5c65159SKalle Valo ret = ath11k_wmi_send_peer_create_cmd(ar, param); 231d5c65159SKalle Valo if (ret) { 232d5c65159SKalle Valo ath11k_warn(ar->ab, 233d5c65159SKalle Valo "failed to send peer create vdev_id %d ret %d\n", 234d5c65159SKalle Valo param->vdev_id, ret); 235d5c65159SKalle Valo return ret; 236d5c65159SKalle Valo } 237d5c65159SKalle Valo 238d5c65159SKalle Valo ret = ath11k_wait_for_peer_created(ar, param->vdev_id, 239d5c65159SKalle Valo param->peer_addr); 240d5c65159SKalle Valo if (ret) 241d5c65159SKalle Valo return ret; 242d5c65159SKalle Valo 243d5c65159SKalle Valo spin_lock_bh(&ar->ab->base_lock); 244d5c65159SKalle Valo 245d5c65159SKalle Valo peer = ath11k_peer_find(ar->ab, param->vdev_id, param->peer_addr); 246d5c65159SKalle Valo if (!peer) { 247d5c65159SKalle Valo spin_unlock_bh(&ar->ab->base_lock); 248d5c65159SKalle Valo ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n", 249d5c65159SKalle Valo param->peer_addr, param->vdev_id); 250d5c65159SKalle Valo ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, 251d5c65159SKalle Valo param->vdev_id); 252d5c65159SKalle Valo return -ENOENT; 253d5c65159SKalle Valo } 254d5c65159SKalle Valo 255*1e744bf2SKarthikeyan Periyasamy peer->pdev_idx = ar->pdev_idx; 256d5c65159SKalle Valo peer->sta = sta; 257d5c65159SKalle Valo arvif->ast_hash = peer->ast_hash; 258d5c65159SKalle Valo 259acc79d98SSriram R peer->sec_type = HAL_ENCRYPT_TYPE_OPEN; 260acc79d98SSriram R peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN; 261acc79d98SSriram R 262d5c65159SKalle Valo ar->num_peers++; 263d5c65159SKalle Valo 264d5c65159SKalle Valo spin_unlock_bh(&ar->ab->base_lock); 265d5c65159SKalle Valo 266d5c65159SKalle Valo return 0; 267d5c65159SKalle Valo } 268