1 2 /* 3 * Copyright (c) 2016-2021 The Linux Foundation. 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_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->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_peer: WDS repeater 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, struct dp_peer *ta_peer, 152 qdf_nbuf_t nbuf, uint8_t is_ad4_valid, 153 uint8_t is_sa_valid, uint8_t is_chfrag_start, 154 uint16_t sa_idx, uint16_t sa_sw_peer_id) 155 { 156 struct dp_peer *sa_peer; 157 struct dp_ast_entry *ast; 158 uint32_t flags = DP_AST_FLAGS_HM; 159 uint32_t ret = 0; 160 struct dp_pdev *pdev = ta_peer->vdev->pdev; 161 uint8_t wds_src_mac[QDF_MAC_ADDR_SIZE]; 162 163 /* For AP mode : Do wds source port learning only if it is a 164 * 4-address mpdu 165 * 166 * For STA mode : Frames from RootAP backend will be in 3-address mode, 167 * till RootAP does the WDS source port learning; Hence in repeater/STA 168 * mode, we enable learning even in 3-address mode , to avoid RootAP 169 * backbone getting wrongly learnt as MEC on repeater 170 */ 171 if (ta_peer->vdev->opmode != wlan_op_mode_sta) { 172 if (!(is_chfrag_start && is_ad4_valid)) 173 return; 174 } else { 175 /* For HKv2 Source port learing is not needed in STA mode 176 * as we have support in HW 177 * 178 * if sa_valid bit is set there is a AST entry added on AP VAP 179 * and this peer has roamed behind ROOT AP in this case proceed 180 * further to check for roaming 181 */ 182 if (soc->ast_override_support && !is_sa_valid) 183 return; 184 } 185 186 if (qdf_unlikely(!is_sa_valid)) { 187 qdf_mem_copy(wds_src_mac, 188 (qdf_nbuf_data(nbuf) + QDF_MAC_ADDR_SIZE), 189 QDF_MAC_ADDR_SIZE); 190 191 dp_wds_ext_peer_learn(soc, ta_peer); 192 ret = dp_peer_add_ast(soc, 193 ta_peer, 194 wds_src_mac, 195 CDP_TXRX_AST_TYPE_WDS, 196 flags); 197 return; 198 } 199 200 qdf_spin_lock_bh(&soc->ast_lock); 201 ast = soc->ast_table[sa_idx]; 202 203 if (!ast) { 204 qdf_spin_unlock_bh(&soc->ast_lock); 205 /* 206 * In HKv1, it is possible that HW retains the AST entry in 207 * GSE cache on 1 radio , even after the AST entry is deleted 208 * (on another radio). 209 * 210 * Due to this, host might still get sa_is_valid indications 211 * for frames with SA not really present in AST table. 212 * 213 * So we go ahead and send an add_ast command to FW in such 214 * cases where sa is reported still as valid, so that FW will 215 * invalidate this GSE cache entry and new AST entry gets 216 * cached. 217 */ 218 if (!soc->ast_override_support) { 219 qdf_mem_copy(wds_src_mac, 220 (qdf_nbuf_data(nbuf) + QDF_MAC_ADDR_SIZE), 221 QDF_MAC_ADDR_SIZE); 222 223 ret = dp_peer_add_ast(soc, 224 ta_peer, 225 wds_src_mac, 226 CDP_TXRX_AST_TYPE_WDS, 227 flags); 228 return; 229 } else { 230 /* In HKv2 smart monitor case, when NAC client is 231 * added first and this client roams within BSS to 232 * connect to RE, since we have an AST entry for 233 * NAC we get sa_is_valid bit set. So we check if 234 * smart monitor is enabled and send add_ast command 235 * to FW. 236 */ 237 dp_monitor_neighbour_peer_add_ast(pdev, ta_peer, 238 wds_src_mac, nbuf, 239 flags); 240 return; 241 } 242 } 243 244 245 if ((ast->type == CDP_TXRX_AST_TYPE_WDS_HM) || 246 (ast->type == CDP_TXRX_AST_TYPE_WDS_HM_SEC)) { 247 qdf_spin_unlock_bh(&soc->ast_lock); 248 return; 249 } 250 251 /* 252 * Ensure we are updating the right AST entry by 253 * validating ast_idx. 254 * There is a possibility we might arrive here without 255 * AST MAP event , so this check is mandatory 256 */ 257 if (ast->is_mapped && (ast->ast_idx == sa_idx)) 258 ast->is_active = TRUE; 259 260 if (sa_sw_peer_id != ta_peer->peer_id) { 261 262 if ((ast->type != CDP_TXRX_AST_TYPE_STATIC) && 263 (ast->type != CDP_TXRX_AST_TYPE_SELF) && 264 (ast->type != CDP_TXRX_AST_TYPE_STA_BSS)) { 265 if (ast->pdev_id != ta_peer->vdev->pdev->pdev_id) { 266 /* This case is when a STA roams from one 267 * repeater to another repeater, but these 268 * repeaters are connected to root AP on 269 * different radios. 270 * Ex: rptr1 connected to ROOT AP over 5G 271 * and rptr2 connected to ROOT AP over 2G 272 * radio 273 */ 274 dp_peer_del_ast(soc, ast); 275 } else { 276 /* this case is when a STA roams from one 277 * reapter to another repeater, but inside 278 * same radio. 279 */ 280 /* For HKv2 do not update the AST entry if 281 * new ta_peer is on STA vap as SRC port 282 * learning is disable on STA vap 283 */ 284 if (soc->ast_override_support && 285 (ta_peer->vdev->opmode == wlan_op_mode_sta)) { 286 dp_peer_del_ast(soc, ast); 287 } else { 288 dp_wds_ext_peer_learn(soc, ta_peer); 289 dp_peer_update_ast(soc, ta_peer, ast, flags); 290 } 291 qdf_spin_unlock_bh(&soc->ast_lock); 292 return; 293 } 294 } 295 /* 296 * Do not kickout STA if it belongs to a different radio. 297 * For DBDC repeater, it is possible to arrive here 298 * for multicast loopback frames originated from connected 299 * clients and looped back (intrabss) by Root AP 300 */ 301 if (ast->pdev_id != ta_peer->vdev->pdev->pdev_id) { 302 qdf_spin_unlock_bh(&soc->ast_lock); 303 return; 304 } 305 306 qdf_spin_unlock_bh(&soc->ast_lock); 307 /* 308 * Kickout, when direct associated peer(SA) roams 309 * to another AP and reachable via TA peer 310 */ 311 sa_peer = dp_peer_get_ref_by_id(soc, ast->peer_id, 312 DP_MOD_ID_RX); 313 if (!sa_peer) 314 return; 315 316 if ((sa_peer->vdev->opmode == wlan_op_mode_ap) && 317 !sa_peer->delete_in_progress) { 318 qdf_mem_copy(wds_src_mac, 319 (qdf_nbuf_data(nbuf) + QDF_MAC_ADDR_SIZE), 320 QDF_MAC_ADDR_SIZE); 321 sa_peer->delete_in_progress = true; 322 if (soc->cdp_soc.ol_ops->peer_sta_kickout) { 323 soc->cdp_soc.ol_ops->peer_sta_kickout( 324 soc->ctrl_psoc, 325 sa_peer->vdev->pdev->pdev_id, 326 wds_src_mac); 327 } 328 } 329 dp_peer_unref_delete(sa_peer, DP_MOD_ID_RX); 330 return; 331 } 332 333 qdf_spin_unlock_bh(&soc->ast_lock); 334 } 335 336 /** 337 * dp_rx_wds_srcport_learn() - Add or update the STA PEER which 338 * is behind the WDS repeater. 339 * 340 * @soc: core txrx main context 341 * @rx_tlv_hdr: base address of RX TLV header 342 * @ta_peer: WDS repeater peer 343 * @nbuf: rx pkt 344 * 345 * Return: void: 346 */ 347 static inline void 348 dp_rx_wds_srcport_learn(struct dp_soc *soc, 349 uint8_t *rx_tlv_hdr, 350 struct dp_peer *ta_peer, 351 qdf_nbuf_t nbuf, 352 struct hal_rx_msdu_metadata msdu_end_info) 353 { 354 uint8_t sa_is_valid = qdf_nbuf_is_sa_valid(nbuf); 355 uint8_t is_chfrag_start = 0; 356 uint8_t is_ad4_valid = 0; 357 358 if (qdf_unlikely(!ta_peer)) 359 return; 360 361 is_chfrag_start = qdf_nbuf_is_rx_chfrag_start(nbuf); 362 if (is_chfrag_start) 363 is_ad4_valid = hal_rx_get_mpdu_mac_ad4_valid(soc->hal_soc, rx_tlv_hdr); 364 365 366 /* 367 * Get the AST entry from HW SA index and mark it as active 368 */ 369 dp_rx_wds_add_or_update_ast(soc, ta_peer, nbuf, is_ad4_valid, 370 sa_is_valid, is_chfrag_start, 371 msdu_end_info.sa_idx, msdu_end_info.sa_sw_peer_id); 372 } 373 374 /* 375 * dp_rx_ast_set_active() - set the active flag of the astentry 376 * corresponding to a hw index. 377 * @soc: core txrx main context 378 * @sa_idx: hw idx 379 * @is_active: active flag 380 * 381 */ 382 static inline QDF_STATUS dp_rx_ast_set_active(struct dp_soc *soc, 383 uint16_t sa_idx, bool is_active) 384 { 385 struct dp_ast_entry *ast; 386 387 qdf_spin_lock_bh(&soc->ast_lock); 388 ast = soc->ast_table[sa_idx]; 389 390 if (!ast) { 391 qdf_spin_unlock_bh(&soc->ast_lock); 392 return QDF_STATUS_E_NULL_VALUE; 393 } 394 395 if (!ast->is_mapped) { 396 qdf_spin_unlock_bh(&soc->ast_lock); 397 return QDF_STATUS_E_INVAL; 398 } 399 400 /* 401 * Ensure we are updating the right AST entry by 402 * validating ast_idx. 403 * There is a possibility we might arrive here without 404 * AST MAP event , so this check is mandatory 405 */ 406 if (ast->ast_idx == sa_idx) { 407 ast->is_active = is_active; 408 qdf_spin_unlock_bh(&soc->ast_lock); 409 return QDF_STATUS_SUCCESS; 410 } 411 412 qdf_spin_unlock_bh(&soc->ast_lock); 413 return QDF_STATUS_E_FAILURE; 414 } 415 #endif /* DP_TXRX_WDS*/ 416