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