diff --git a/dp/inc/cdp_txrx_cmn.h b/dp/inc/cdp_txrx_cmn.h index a984ec5d894c..1093c00cf951 100644 --- a/dp/inc/cdp_txrx_cmn.h +++ b/dp/inc/cdp_txrx_cmn.h @@ -472,6 +472,31 @@ static inline uint8_t cdp_peer_ast_get_next_hop ast_handle); } +/** + * cdp_peer_ast_get_type() - Return type (Static, WDS, MEC) of AST entry + * @soc: DP SoC handle + * @ast_handle: Opaque handle to AST entry + * + * Return: AST entry type (Static/WDS/MEC) + */ +static inline enum cdp_txrx_ast_entry_type cdp_peer_ast_get_type + (ol_txrx_soc_handle soc, void *ast_handle) + +{ + if (!soc || !soc->ops) { + QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, + "%s: Invalid Instance:", __func__); + QDF_BUG(0); + return 0; + } + + if (!soc->ops->cmn_drv_ops || + !soc->ops->cmn_drv_ops->txrx_peer_ast_get_type) + return 0; + + return soc->ops->cmn_drv_ops->txrx_peer_ast_get_type(soc, ast_handle); +} + static inline void cdp_peer_ast_set_type (ol_txrx_soc_handle soc, void *ast_handle, enum cdp_txrx_ast_entry_type type) diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 1d48d98c4edf..cdc6830da0ff 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -304,6 +304,7 @@ enum ol_txrx_peer_state { enum cdp_txrx_ast_entry_type { CDP_TXRX_AST_TYPE_NONE, /* static ast entry for connected peer */ CDP_TXRX_AST_TYPE_STATIC, /* static ast entry for connected peer */ + CDP_TXRX_AST_TYPE_SELF, /* static ast entry for self peer (STA mode) */ CDP_TXRX_AST_TYPE_WDS, /* WDS peer ast entry type*/ CDP_TXRX_AST_TYPE_MEC, /* Multicast echo ast entry type */ CDP_TXRX_AST_TYPE_WDS_HM, /* HM WDS entry */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index 0e0b772fb2fd..74c2b51c80ac 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -120,6 +120,9 @@ struct cdp_cmn_ops { (ol_txrx_soc_handle soc, void *ast_hdl, enum cdp_txrx_ast_entry_type type); + enum cdp_txrx_ast_entry_type (*txrx_peer_ast_get_type) + (ol_txrx_soc_handle soc, void *ast_hdl); + void (*txrx_peer_delete)(void *peer, uint32_t bitmap); int (*txrx_set_monitor_mode)(struct cdp_vdev *vdev, diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 0d8a99ce9645..9d74060d2e31 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -484,13 +484,12 @@ static int dp_peer_update_ast_wifi3(struct cdp_soc_t *soc_hdl, /* * dp_wds_reset_ast_wifi3() - Reset the is_active param for ast entry - * @soc_handle: Datapath SOC handle - * @wds_macaddr: MAC address of the WDS entry to be added - * @vdev_hdl: vdev handle + * @soc_handle: Datapath SOC handle + * @wds_macaddr: WDS entry MAC Address * Return: None */ static void dp_wds_reset_ast_wifi3(struct cdp_soc_t *soc_hdl, - uint8_t *wds_macaddr, void *vdev_hdl) + uint8_t *wds_macaddr, void *vdev_handle) { struct dp_soc *soc = (struct dp_soc *)soc_hdl; struct dp_ast_entry *ast_entry = NULL; @@ -499,8 +498,10 @@ static void dp_wds_reset_ast_wifi3(struct cdp_soc_t *soc_hdl, ast_entry = dp_peer_ast_hash_find(soc, wds_macaddr); if (ast_entry) { - if (ast_entry->type != CDP_TXRX_AST_TYPE_STATIC) + if ((ast_entry->type != CDP_TXRX_AST_TYPE_STATIC) && + (ast_entry->type != CDP_TXRX_AST_TYPE_SELF)) { ast_entry->is_active = TRUE; + } } qdf_spin_unlock_bh(&soc->ast_lock); @@ -508,12 +509,11 @@ static void dp_wds_reset_ast_wifi3(struct cdp_soc_t *soc_hdl, /* * dp_wds_reset_ast_table_wifi3() - Reset the is_active param for all ast entry - * @soc: Datapath SOC handle - * @vdev_hdl: vdev handle + * @soc: Datapath SOC handle * * Return: None */ -static void dp_wds_reset_ast_table_wifi3(struct cdp_soc_t *soc_hdl, +static void dp_wds_reset_ast_table_wifi3(struct cdp_soc_t *soc_hdl, void *vdev_hdl) { struct dp_soc *soc = (struct dp_soc *) soc_hdl; @@ -615,7 +615,12 @@ static void dp_peer_ast_set_type_wifi3( type); } - +static enum cdp_txrx_ast_entry_type dp_peer_ast_get_type_wifi3( + struct cdp_soc_t *soc_hdl, + void *ast_entry_hdl) +{ + return ((struct dp_ast_entry *)ast_entry_hdl)->type; +} /** * dp_srng_find_ring_in_mask() - find which ext_group a ring belongs @@ -787,7 +792,8 @@ static void dp_print_ast_stats(struct dp_soc *soc) struct dp_pdev *pdev; struct dp_peer *peer; struct dp_ast_entry *ase, *tmp_ase; - char type[5][10] = {"NONE", "STATIC", "WDS", "MEC", "HMWDS"}; + char type[CDP_TXRX_AST_TYPE_MAX][10] = { + "NONE", "STATIC", "SELF", "WDS", "MEC", "HMWDS"}; DP_PRINT_STATS("AST Stats:"); DP_PRINT_STATS(" Entries Added = %d", soc->stats.ast.added); @@ -3756,6 +3762,42 @@ static inline void dp_peer_delete_ast_entries(struct dp_soc *soc, } #endif +#if ATH_SUPPORT_WRAP +static inline struct dp_peer *dp_peer_can_reuse(struct dp_vdev *vdev, + uint8_t *peer_mac_addr) +{ + struct dp_peer *peer; + + peer = dp_peer_find_hash_find(vdev->pdev->soc, peer_mac_addr, + 0, vdev->vdev_id); + if (!peer) + return NULL; + + if (peer->bss_peer) + return peer; + + qdf_atomic_dec(&peer->ref_cnt); + return NULL; +} +#else +static inline struct dp_peer *dp_peer_can_reuse(struct dp_vdev *vdev, + uint8_t *peer_mac_addr) +{ + struct dp_peer *peer; + + peer = dp_peer_find_hash_find(vdev->pdev->soc, peer_mac_addr, + 0, vdev->vdev_id); + if (!peer) + return NULL; + + if (peer->bss_peer && (peer->vdev->vdev_id == vdev->vdev_id)) + return peer; + + qdf_atomic_dec(&peer->ref_cnt); + return NULL; +} +#endif + /* * dp_peer_create_wifi3() - attach txrx peer * @txrx_vdev: Datapath VDEV handle @@ -3772,6 +3814,7 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle, struct dp_pdev *pdev; struct dp_soc *soc; struct dp_ast_entry *ast_entry; + enum cdp_txrx_ast_entry_type ast_type = CDP_TXRX_AST_TYPE_STATIC; /* preconditions */ qdf_assert(vdev); @@ -3780,19 +3823,32 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle, pdev = vdev->pdev; soc = pdev->soc; - peer = dp_peer_find_hash_find(pdev->soc, peer_mac_addr, - 0, vdev->vdev_id); + /* + * If a peer entry with given MAC address already exists, + * reuse the peer and reset the state of peer. + */ + peer = dp_peer_can_reuse(vdev, peer_mac_addr); if (peer) { peer->delete_in_progress = false; dp_peer_delete_ast_entries(soc, peer); + if ((vdev->opmode == wlan_op_mode_sta) && + !qdf_mem_cmp(peer_mac_addr, &vdev->mac_addr.raw[0], + DP_MAC_ADDR_LEN)) { + ast_type = CDP_TXRX_AST_TYPE_SELF; + } + + dp_peer_add_ast(soc, peer, peer_mac_addr, ast_type, 0); + /* - * on peer create, peer ref count decrements, sice new peer is not - * getting created earlier reference is reused, peer_unref_delete will - * take care of incrementing count - * */ + * Control path maintains a node count which is incremented + * for every new peer create command. Since new peer is not being + * created and earlier reference is reused here, + * peer_unref_delete event is sent to control path to + * increment the count back. + */ if (soc->cdp_soc.ol_ops->peer_unref_delete) { soc->cdp_soc.ol_ops->peer_unref_delete(pdev->ctrl_pdev, vdev->vdev_id, peer->mac_addr.raw); @@ -3801,12 +3857,15 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle, dp_local_peer_id_alloc(pdev, peer); DP_STATS_INIT(peer); + return (void *)peer; } else { /* * When a STA roams from RPTR AP to ROOT AP and vice versa, we * need to remove the AST entry which was earlier added as a WDS * entry. + * If an AST entry exists, but no peer entry exists with a given + * MAC addresses, we could deduce it as a WDS entry */ ast_entry = dp_peer_ast_hash_find(soc, peer_mac_addr); if (ast_entry) @@ -3831,7 +3890,13 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle, peer->vdev = vdev; peer->ctrl_peer = ctrl_peer; - dp_peer_add_ast(soc, peer, peer_mac_addr, CDP_TXRX_AST_TYPE_STATIC, 0); + if ((vdev->opmode == wlan_op_mode_sta) && + !qdf_mem_cmp(peer_mac_addr, &vdev->mac_addr.raw[0], + DP_MAC_ADDR_LEN)) { + ast_type = CDP_TXRX_AST_TYPE_SELF; + } + + dp_peer_add_ast(soc, peer, peer_mac_addr, ast_type, 0); qdf_spinlock_create(&peer->peer_info_lock); @@ -6545,6 +6610,9 @@ static void dp_set_vdev_param(struct cdp_vdev *vdev_handle, struct dp_vdev *vdev = (struct dp_vdev *)vdev_handle; switch (param) { case CDP_ENABLE_WDS: + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "wds_enable %d for vdev(%p) id(%d)\n", + val, vdev, vdev->vdev_id); vdev->wds_enabled = val; break; case CDP_ENABLE_NAWDS: @@ -7327,6 +7395,7 @@ static struct cdp_cmn_ops dp_ops_cmn = { .txrx_peer_ast_get_pdev_id = dp_peer_ast_get_pdev_id_wifi3, .txrx_peer_ast_get_next_hop = dp_peer_ast_get_next_hop_wifi3, .txrx_peer_ast_set_type = dp_peer_ast_set_type_wifi3, + .txrx_peer_ast_get_type = dp_peer_ast_get_type_wifi3, .txrx_peer_delete = dp_peer_delete_wifi3, .txrx_vdev_register = dp_vdev_register_wifi3, .txrx_soc_detach = dp_soc_detach_wifi3, diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index f56d82a1e208..c56b641269a7 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -461,6 +461,10 @@ int dp_peer_add_ast(struct dp_soc *soc, peer->self_ast_entry = ast_entry; ast_entry->type = CDP_TXRX_AST_TYPE_STATIC; break; + case CDP_TXRX_AST_TYPE_SELF: + peer->self_ast_entry = ast_entry; + ast_entry->type = CDP_TXRX_AST_TYPE_SELF; + break; case CDP_TXRX_AST_TYPE_WDS: ast_entry->next_hop = 1; ast_entry->type = CDP_TXRX_AST_TYPE_WDS; @@ -489,7 +493,8 @@ int dp_peer_add_ast(struct dp_soc *soc, else qdf_mem_copy(next_node_mac, peer->mac_addr.raw, 6); - if (ast_entry->type != CDP_TXRX_AST_TYPE_STATIC) { + if ((ast_entry->type != CDP_TXRX_AST_TYPE_STATIC) && + (ast_entry->type != CDP_TXRX_AST_TYPE_SELF)) { if (QDF_STATUS_SUCCESS == soc->cdp_soc.ol_ops->peer_add_wds_entry( peer->vdev->osif_vdev, @@ -547,25 +552,10 @@ int dp_peer_update_ast(struct dp_soc *soc, struct dp_peer *peer, { int ret = -1; struct dp_peer *old_peer; - struct dp_peer *sa_peer; - if (ast_entry->type == CDP_TXRX_AST_TYPE_STATIC) { - sa_peer = ast_entry->peer; - - /* - * Kickout, when direct associated peer(SA) roams - * to another AP and reachable via TA peer - */ - if (!sa_peer->delete_in_progress) { - sa_peer->delete_in_progress = true; - if (soc->cdp_soc.ol_ops->peer_sta_kickout) { - soc->cdp_soc.ol_ops->peer_sta_kickout( - sa_peer->vdev->pdev->ctrl_pdev, - ast_entry->mac_addr.raw); - } - return 0; - } - } + if ((ast_entry->type == CDP_TXRX_AST_TYPE_STATIC) || + (ast_entry->type == CDP_TXRX_AST_TYPE_SELF)) + return 0; old_peer = ast_entry->peer; TAILQ_REMOVE(&old_peer->ast_entry_list, ast_entry, ase_list_elem); @@ -578,7 +568,7 @@ int dp_peer_update_ast(struct dp_soc *soc, struct dp_peer *peer, TAILQ_INSERT_TAIL(&peer->ast_entry_list, ast_entry, ase_list_elem); ret = soc->cdp_soc.ol_ops->peer_update_wds_entry( - peer->vdev->osif_vdev, + peer->vdev->osif_vdev, ast_entry->mac_addr.raw, peer->mac_addr.raw, flags); diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index 144c9aad98bc..0043dad024c2 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -357,15 +357,6 @@ dp_rx_intrabss_fwd(struct dp_soc *soc, struct dp_peer *da_peer; struct dp_ast_entry *ast_entry; qdf_nbuf_t nbuf_copy; - struct dp_vdev *vdev = sa_peer->vdev; - - /* - * intrabss forwarding is not applicable if - * vap is nawds enabled or ap_bridge is false. - */ - if (vdev->nawds_enabled) - return false; - /* check if the destination peer is available in peer table * and also check if the source peer and destination peer @@ -1665,7 +1656,8 @@ done: if (qdf_likely(vdev->rx_decap_type == htt_cmn_pkt_type_ethernet) && - (qdf_likely(!vdev->mesh_vdev))) { + (qdf_likely(!vdev->mesh_vdev)) && + (vdev->wds_enabled)) { /* WDS Source Port Learning */ dp_rx_wds_srcport_learn(soc, rx_tlv_hdr, diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index df239f82134a..cdeb5ae69e18 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -396,14 +396,27 @@ dp_rx_wds_srcport_learn(struct dp_soc *soc, uint32_t flags = IEEE80211_NODE_F_WDS_HM; uint32_t ret = 0; uint8_t wds_src_mac[IEEE80211_ADDR_LEN]; + struct dp_peer *sa_peer; struct dp_ast_entry *ast; uint16_t sa_idx; - /* Do wds source port learning only if it is a 4-address mpdu */ - if (!(qdf_nbuf_is_rx_chfrag_start(nbuf) && - hal_rx_get_mpdu_mac_ad4_valid(rx_tlv_hdr))) + if (qdf_unlikely(!ta_peer)) return; + /* For AP mode : Do wds source port learning only if it is a + * 4-address mpdu + * + * For STA mode : Frames from RootAP backend will be in 3-address mode, + * till RootAP does the WDS source port learning; Hence in repeater/STA + * mode, we enable learning even in 3-address mode , to avoid RootAP + * backbone getting wrongly learnt as MEC on repeater + */ + if (ta_peer->vdev->opmode != wlan_op_mode_sta) { + if (!(qdf_nbuf_is_rx_chfrag_start(nbuf) && + hal_rx_get_mpdu_mac_ad4_valid(rx_tlv_hdr))) + return; + } + memcpy(wds_src_mac, (qdf_nbuf_data(nbuf) + IEEE80211_ADDR_LEN), IEEE80211_ADDR_LEN); @@ -439,12 +452,42 @@ dp_rx_wds_srcport_learn(struct dp_soc *soc, if (ast->ast_idx == sa_idx) ast->is_active = TRUE; - /* Handle client roaming */ - if (sa_sw_peer_id != ta_peer->peer_ids[0]) - dp_peer_update_ast(soc, ta_peer, ast, flags); + if (sa_sw_peer_id != ta_peer->peer_ids[0]) { + sa_peer = ast->peer; + + /* + * Do not kickout STA if it belongs to a different radio. + * For DBDC repeater, it is possible to arrive here + * for multicast loopback frames originated from connected + * clients and looped back (intrabss) by Root AP + */ + if (ast->pdev_id != ta_peer->vdev->pdev->pdev_id) { + qdf_spin_unlock_bh(&soc->ast_lock); + return; + } + + if ((ast->type != CDP_TXRX_AST_TYPE_STATIC) && + (ast->type != CDP_TXRX_AST_TYPE_SELF)) { + dp_peer_update_ast(soc, ta_peer, ast, flags); + qdf_spin_unlock_bh(&soc->ast_lock); + return; + } + + /* + * Kickout, when direct associated peer(SA) roams + * to another AP and reachable via TA peer + */ + if (!sa_peer->delete_in_progress) { + sa_peer->delete_in_progress = true; + if (soc->cdp_soc.ol_ops->peer_sta_kickout) { + soc->cdp_soc.ol_ops->peer_sta_kickout( + sa_peer->vdev->pdev->ctrl_pdev, + wds_src_mac); + } + } + } qdf_spin_unlock_bh(&soc->ast_lock); - return; } #else diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 5223179a4003..adeef55d4d75 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -2469,6 +2469,10 @@ void dp_tx_mec_handler(struct dp_vdev *vdev, uint8_t *status) if (!vdev->wds_enabled) return; + /* MEC required only in STA mode */ + if (vdev->opmode != wlan_op_mode_sta) + return; + soc = vdev->pdev->soc; qdf_spin_lock_bh(&soc->peer_ref_mutex); peer = TAILQ_FIRST(&vdev->peer_list);