1 /* 2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #ifndef _DP_TXRX_WDS_H_ 21 #define _DP_TXRX_WDS_H_ 22 23 #ifdef WIFI_MONITOR_SUPPORT 24 #include "dp_htt.h" 25 #include "dp_mon.h" 26 #endif 27 28 /* host managed flag */ 29 #define DP_AST_FLAGS_HM 0x0020 30 31 /* WDS AST entry aging timer value */ 32 #define DP_WDS_AST_AGING_TIMER_DEFAULT_MS 120000 33 #define DP_WDS_AST_AGING_TIMER_CNT \ 34 ((DP_WDS_AST_AGING_TIMER_DEFAULT_MS / DP_AST_AGING_TIMER_DEFAULT_MS) - 1) 35 void dp_soc_wds_attach(struct dp_soc *soc); 36 void dp_soc_wds_detach(struct dp_soc *soc); 37 #ifdef QCA_PEER_MULTIQ_SUPPORT 38 int dp_peer_find_ast_index_by_flowq_id(struct cdp_soc_t *soc, 39 uint16_t vdev_id, uint8_t *peer_mac_addr, 40 uint8_t flow_id, uint8_t tid); 41 #endif 42 void 43 dp_rx_da_learn(struct dp_soc *soc, 44 uint8_t *rx_tlv_hdr, 45 struct dp_txrx_peer *ta_peer, 46 qdf_nbuf_t nbuf); 47 48 void dp_tx_mec_handler(struct dp_vdev *vdev, uint8_t *status); 49 #ifdef FEATURE_WDS 50 #ifdef FEATURE_MCL_REPEATER 51 static inline bool dp_tx_da_search_override(struct dp_vdev *vdev) 52 { 53 if (vdev->mec_enabled) 54 return true; 55 56 return false; 57 } 58 #else 59 static inline bool dp_tx_da_search_override(struct dp_vdev *vdev) 60 { 61 struct dp_soc *soc = vdev->pdev->soc; 62 63 /* 64 * If AST index override support is available (HKv2 etc), 65 * DA search flag be enabled always 66 * 67 * If AST index override support is not available (HKv1), 68 * DA search flag should be used for all modes except QWRAP 69 */ 70 if (soc->ast_override_support || !vdev->proxysta_vdev) 71 return true; 72 73 return false; 74 } 75 #endif /* FEATURE_MCL_REPEATER */ 76 #endif /* FEATURE_WDS */ 77 #ifdef WDS_VENDOR_EXTENSION 78 QDF_STATUS 79 dp_txrx_peer_wds_tx_policy_update(struct cdp_soc_t *cdp_soc, uint8_t vdev_id, 80 uint8_t *peer_mac, int wds_tx_ucast, 81 int wds_tx_mcast); 82 QDF_STATUS 83 dp_txrx_set_wds_rx_policy(struct cdp_soc_t *cdp_soc, uint8_t vdev_id, 84 u_int32_t val); 85 #endif 86 87 /** 88 * dp_hmwds_ast_add_notify() - schedules hmwds ast add status work 89 * @peer: DP peer 90 * @mac_addr: ast mac addr 91 * @type: ast type 92 * @err: QDF_STATUS error code 93 * @is_peer_map: notify is from peer map 94 * 95 * Return: void 96 */ 97 void dp_hmwds_ast_add_notify(struct dp_peer *peer, 98 uint8_t *mac_addr, 99 enum cdp_txrx_ast_entry_type type, 100 QDF_STATUS err, 101 bool is_peer_map); 102 103 #ifdef QCA_SUPPORT_WDS_EXTENDED 104 /** 105 * dp_wds_ext_peer_learn() - function to send event to control 106 * path on receiving 1st 4-address frame from backhaul. 107 * @soc: DP soc 108 * @ta_peer: WDS repeater peer 109 * 110 * Return: void 111 */ 112 static inline void dp_wds_ext_peer_learn(struct dp_soc *soc, 113 struct dp_peer *ta_peer) 114 { 115 uint8_t wds_ext_src_mac[QDF_MAC_ADDR_SIZE]; 116 117 if (ta_peer->vdev->wds_ext_enabled && 118 !qdf_atomic_test_and_set_bit(WDS_EXT_PEER_INIT_BIT, 119 &ta_peer->txrx_peer->wds_ext.init)) { 120 qdf_mem_copy(wds_ext_src_mac, &ta_peer->mac_addr.raw[0], 121 QDF_MAC_ADDR_SIZE); 122 soc->cdp_soc.ol_ops->rx_wds_ext_peer_learn( 123 soc->ctrl_psoc, 124 ta_peer->peer_id, 125 ta_peer->vdev->vdev_id, 126 wds_ext_src_mac); 127 } 128 } 129 #else 130 static inline void dp_wds_ext_peer_learn(struct dp_soc *soc, 131 struct dp_peer *ta_peer) 132 { 133 } 134 #endif 135 136 /** 137 * dp_rx_wds_add_or_update_ast() - Add or update the ast entry. 138 * 139 * @soc: core txrx main context 140 * @ta_txrx_peer: WDS repeater txrx peer 141 * @mac_addr: mac address of the peer 142 * @is_ad4_valid: 4-address valid flag 143 * @is_sa_valid: source address valid flag 144 * @is_chfrag_start: frag start flag 145 * @sa_idx: source-address index for peer 146 * @sa_sw_peer_id: software source-address peer-id 147 * 148 * Return: void: 149 */ 150 static inline void 151 dp_rx_wds_add_or_update_ast(struct dp_soc *soc, 152 struct dp_txrx_peer *ta_peer, 153 qdf_nbuf_t nbuf, uint8_t is_ad4_valid, 154 uint8_t is_sa_valid, uint8_t is_chfrag_start, 155 uint16_t sa_idx, uint16_t sa_sw_peer_id) 156 { 157 struct dp_peer *sa_peer; 158 struct dp_ast_entry *ast; 159 uint32_t flags = DP_AST_FLAGS_HM; 160 struct dp_pdev *pdev = ta_peer->vdev->pdev; 161 uint8_t wds_src_mac[QDF_MAC_ADDR_SIZE]; 162 struct dp_peer *ta_base_peer; 163 164 165 if (!(is_chfrag_start && is_ad4_valid)) 166 return; 167 168 if (qdf_unlikely(!is_sa_valid)) { 169 qdf_mem_copy(wds_src_mac, 170 (qdf_nbuf_data(nbuf) + QDF_MAC_ADDR_SIZE), 171 QDF_MAC_ADDR_SIZE); 172 173 ta_base_peer = dp_peer_get_ref_by_id(soc, ta_peer->peer_id, 174 DP_MOD_ID_RX); 175 if (ta_base_peer) { 176 if (ta_peer->vdev->opmode == wlan_op_mode_ap) 177 dp_wds_ext_peer_learn(soc, ta_base_peer); 178 179 dp_peer_add_ast(soc, ta_base_peer, wds_src_mac, 180 CDP_TXRX_AST_TYPE_WDS, flags); 181 182 dp_peer_unref_delete(ta_base_peer, DP_MOD_ID_RX); 183 } 184 return; 185 } 186 187 qdf_spin_lock_bh(&soc->ast_lock); 188 ast = soc->ast_table[sa_idx]; 189 190 if (!ast) { 191 qdf_spin_unlock_bh(&soc->ast_lock); 192 /* 193 * In HKv1, it is possible that HW retains the AST entry in 194 * GSE cache on 1 radio , even after the AST entry is deleted 195 * (on another radio). 196 * 197 * Due to this, host might still get sa_is_valid indications 198 * for frames with SA not really present in AST table. 199 * 200 * So we go ahead and send an add_ast command to FW in such 201 * cases where sa is reported still as valid, so that FW will 202 * invalidate this GSE cache entry and new AST entry gets 203 * cached. 204 */ 205 if (!soc->ast_override_support) { 206 qdf_mem_copy(wds_src_mac, 207 (qdf_nbuf_data(nbuf) + QDF_MAC_ADDR_SIZE), 208 QDF_MAC_ADDR_SIZE); 209 210 ta_base_peer = dp_peer_get_ref_by_id(soc, 211 ta_peer->peer_id, 212 DP_MOD_ID_RX); 213 214 if (ta_base_peer) { 215 dp_peer_add_ast(soc, ta_base_peer, 216 wds_src_mac, 217 CDP_TXRX_AST_TYPE_WDS, 218 flags); 219 220 dp_peer_unref_delete(ta_base_peer, 221 DP_MOD_ID_RX); 222 } 223 return; 224 } else { 225 /* In HKv2 smart monitor case, when NAC client is 226 * added first and this client roams within BSS to 227 * connect to RE, since we have an AST entry for 228 * NAC we get sa_is_valid bit set. So we check if 229 * smart monitor is enabled and send add_ast command 230 * to FW. 231 */ 232 ta_base_peer = dp_peer_get_ref_by_id(soc, 233 ta_peer->peer_id, 234 DP_MOD_ID_RX); 235 if (ta_base_peer) { 236 dp_monitor_neighbour_peer_add_ast(pdev, 237 ta_base_peer, 238 wds_src_mac, 239 nbuf, 240 flags); 241 dp_peer_unref_delete(ta_base_peer, 242 DP_MOD_ID_RX); 243 } 244 return; 245 } 246 } 247 248 /* 249 * Ensure we are updating the right AST entry by 250 * validating ast_idx. 251 * There is a possibility we might arrive here without 252 * AST MAP event , so this check is mandatory 253 */ 254 if (ast->is_mapped && (ast->ast_idx == sa_idx)) 255 ast->is_active = TRUE; 256 257 if (ast->peer_id != ta_peer->peer_id) { 258 if ((ast->type == CDP_TXRX_AST_TYPE_WDS_HM) || 259 (ast->type == CDP_TXRX_AST_TYPE_WDS_HM_SEC)) { 260 qdf_spin_unlock_bh(&soc->ast_lock); 261 return; 262 } 263 264 if ((ast->type != CDP_TXRX_AST_TYPE_STATIC) && 265 (ast->type != CDP_TXRX_AST_TYPE_SELF) && 266 (ast->type != CDP_TXRX_AST_TYPE_STA_BSS)) { 267 if (ast->pdev_id != ta_peer->vdev->pdev->pdev_id) { 268 /* This case is when a STA roams from one 269 * repeater to another repeater, but these 270 * repeaters are connected to root AP on 271 * different radios. 272 * Ex: rptr1 connected to ROOT AP over 5G 273 * and rptr2 connected to ROOT AP over 2G 274 * radio 275 */ 276 dp_peer_del_ast(soc, ast); 277 } else { 278 /* this case is when a STA roams from one 279 * reapter to another repeater, but inside 280 * same radio. 281 */ 282 /* For HKv2 do not update the AST entry if 283 * new ta_peer is on STA vap as SRC port 284 * learning is disable on STA vap 285 */ 286 if (soc->ast_override_support && 287 (ta_peer->vdev->opmode == wlan_op_mode_sta)) { 288 dp_peer_del_ast(soc, ast); 289 } else { 290 ta_base_peer = 291 dp_peer_get_ref_by_id(soc, 292 ta_peer->peer_id, 293 DP_MOD_ID_RX); 294 if (ta_base_peer) { 295 dp_wds_ext_peer_learn(soc, 296 ta_base_peer); 297 dp_peer_update_ast(soc, 298 ta_base_peer, 299 ast, flags); 300 301 dp_peer_unref_delete(ta_base_peer, 302 DP_MOD_ID_RX); 303 } 304 } 305 qdf_spin_unlock_bh(&soc->ast_lock); 306 return; 307 } 308 } 309 /* 310 * Do not kickout STA if it belongs to a different radio. 311 * For DBDC repeater, it is possible to arrive here 312 * for multicast loopback frames originated from connected 313 * clients and looped back (intrabss) by Root AP 314 */ 315 if (ast->pdev_id != ta_peer->vdev->pdev->pdev_id) { 316 qdf_spin_unlock_bh(&soc->ast_lock); 317 return; 318 } 319 320 qdf_spin_unlock_bh(&soc->ast_lock); 321 /* 322 * Kickout, when direct associated peer(SA) roams 323 * to another AP and reachable via TA peer 324 */ 325 sa_peer = dp_peer_get_ref_by_id(soc, ast->peer_id, 326 DP_MOD_ID_RX); 327 if (!sa_peer) 328 return; 329 330 if ((sa_peer->vdev->opmode == wlan_op_mode_ap) && 331 !sa_peer->delete_in_progress) { 332 qdf_mem_copy(wds_src_mac, 333 (qdf_nbuf_data(nbuf) + QDF_MAC_ADDR_SIZE), 334 QDF_MAC_ADDR_SIZE); 335 sa_peer->delete_in_progress = true; 336 if (soc->cdp_soc.ol_ops->peer_sta_kickout) { 337 soc->cdp_soc.ol_ops->peer_sta_kickout( 338 soc->ctrl_psoc, 339 sa_peer->vdev->pdev->pdev_id, 340 wds_src_mac); 341 } 342 } 343 dp_peer_unref_delete(sa_peer, DP_MOD_ID_RX); 344 return; 345 } 346 347 qdf_spin_unlock_bh(&soc->ast_lock); 348 } 349 350 /** 351 * dp_rx_wds_srcport_learn() - Add or update the STA PEER which 352 * is behind the WDS repeater. 353 * 354 * @soc: core txrx main context 355 * @rx_tlv_hdr: base address of RX TLV header 356 * @ta_peer: WDS repeater peer 357 * @nbuf: rx pkt 358 * 359 * Return: void: 360 */ 361 static inline void 362 dp_rx_wds_srcport_learn(struct dp_soc *soc, 363 uint8_t *rx_tlv_hdr, 364 struct dp_txrx_peer *ta_peer, 365 qdf_nbuf_t nbuf, 366 struct hal_rx_msdu_metadata msdu_end_info) 367 { 368 uint8_t sa_is_valid = qdf_nbuf_is_sa_valid(nbuf); 369 uint8_t is_chfrag_start = 0; 370 uint8_t is_ad4_valid = 0; 371 372 if (qdf_unlikely(!ta_peer)) 373 return; 374 375 is_chfrag_start = qdf_nbuf_is_rx_chfrag_start(nbuf); 376 if (is_chfrag_start) 377 is_ad4_valid = hal_rx_get_mpdu_mac_ad4_valid(soc->hal_soc, rx_tlv_hdr); 378 379 380 /* 381 * Get the AST entry from HW SA index and mark it as active 382 */ 383 dp_rx_wds_add_or_update_ast(soc, ta_peer, nbuf, is_ad4_valid, 384 sa_is_valid, is_chfrag_start, 385 msdu_end_info.sa_idx, msdu_end_info.sa_sw_peer_id); 386 } 387 388 #ifdef IPA_WDS_EASYMESH_FEATURE 389 /** 390 * dp_rx_ipa_wds_srcport_learn() - Add or update the STA PEER which 391 * is behind the WDS repeater. 392 * 393 * @soc: core txrx main context 394 * @ta_peer: WDS repeater peer 395 * @nbuf: rx pkt 396 * @msdu_end_info: msdu end info 397 * @ad4_valid: address4 valid bit 398 * @chfrag_start: Msdu start bit 399 * 400 * Return: void 401 */ 402 static inline void 403 dp_rx_ipa_wds_srcport_learn(struct dp_soc *soc, 404 struct dp_peer *ta_peer, qdf_nbuf_t nbuf, 405 struct hal_rx_msdu_metadata msdu_end_info, 406 bool ad4_valid, bool chfrag_start) 407 { 408 uint8_t sa_is_valid = qdf_nbuf_is_sa_valid(nbuf); 409 uint8_t is_chfrag_start = (uint8_t)chfrag_start; 410 uint8_t is_ad4_valid = (uint8_t)ad4_valid; 411 struct dp_txrx_peer *peer = (struct dp_txrx_peer *)ta_peer; 412 413 if (qdf_unlikely(!ta_peer)) 414 return; 415 416 /* 417 * Get the AST entry from HW SA index and mark it as active 418 */ 419 dp_rx_wds_add_or_update_ast(soc, peer, nbuf, is_ad4_valid, 420 sa_is_valid, is_chfrag_start, 421 msdu_end_info.sa_idx, 422 msdu_end_info.sa_sw_peer_id); 423 } 424 #endif 425 426 /* 427 * dp_rx_ast_set_active() - set the active flag of the astentry 428 * corresponding to a hw index. 429 * @soc: core txrx main context 430 * @sa_idx: hw idx 431 * @is_active: active flag 432 * 433 */ 434 static inline QDF_STATUS dp_rx_ast_set_active(struct dp_soc *soc, 435 uint16_t sa_idx, bool is_active) 436 { 437 struct dp_ast_entry *ast; 438 439 qdf_spin_lock_bh(&soc->ast_lock); 440 ast = soc->ast_table[sa_idx]; 441 442 if (!ast) { 443 qdf_spin_unlock_bh(&soc->ast_lock); 444 return QDF_STATUS_E_NULL_VALUE; 445 } 446 447 if (!ast->is_mapped) { 448 qdf_spin_unlock_bh(&soc->ast_lock); 449 return QDF_STATUS_E_INVAL; 450 } 451 452 /* 453 * Ensure we are updating the right AST entry by 454 * validating ast_idx. 455 * There is a possibility we might arrive here without 456 * AST MAP event , so this check is mandatory 457 */ 458 if (ast->ast_idx == sa_idx) { 459 ast->is_active = is_active; 460 qdf_spin_unlock_bh(&soc->ast_lock); 461 return QDF_STATUS_SUCCESS; 462 } 463 464 qdf_spin_unlock_bh(&soc->ast_lock); 465 return QDF_STATUS_E_FAILURE; 466 } 467 #endif /* DP_TXRX_WDS*/ 468