Răsfoiți Sursa

qcacmn: DBDC repeater mode changes in AST

Add new ast_get_type API for DBDC repeater feature.
Add other changes required in WDS and MEC handling
required for DBDC repeater feature to function properly.

Apply sta kickout logic to handle roaming cases
only within same radio. For roaming across radios, DP should
rely on control path.

Change-Id: If9b35720082dd87de40827843a14238e818bc454
Pamidipati, Vijay 7 ani în urmă
părinte
comite
3756b7603e

+ 25 - 0
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)

+ 1 - 0
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 */

+ 3 - 0
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,

+ 86 - 17
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,

+ 10 - 20
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);

+ 2 - 10
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,

+ 50 - 7
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;
+		}
 
-	qdf_spin_unlock_bh(&soc->ast_lock);
+		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

+ 4 - 0
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);