Quellcode durchsuchen

qcacmn: Add support for DBDC repeater

Added CDP callback APIs so the DBDC repeater module
outside of cmn_dev can add, delete and update the AST
entries. Also with this change the sending of wds cmds
to fw is tied to adding AST, deleteing AST and updating
the AST entries.

Change-Id: I48d31962236860f50e16b771abaf3b8825b798df
Tallapragada Kalyan vor 7 Jahren
Ursprung
Commit
57b6bb3e1d

+ 132 - 0
dp/inc/cdp_txrx_cmn.h

@@ -257,6 +257,138 @@ static inline void cdp_peer_setup
 			peer);
 }
 
+static inline int cdp_peer_add_ast
+	(ol_txrx_soc_handle soc, struct cdp_peer *peer_handle,
+	uint8_t *mac_addr, enum cdp_txrx_ast_entry_type type, uint32_t flags)
+{
+	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_add_ast)
+		return 0;
+
+	return soc->ops->cmn_drv_ops->txrx_peer_add_ast(soc,
+							peer_handle,
+							mac_addr,
+							type,
+							flags);
+}
+
+static inline int cdp_peer_update_ast
+	(ol_txrx_soc_handle soc, void *ast_handle,
+	struct cdp_peer *peer_handle, uint32_t flags)
+{
+	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_update_ast)
+		return 0;
+
+	return soc->ops->cmn_drv_ops->txrx_peer_update_ast(soc,
+							peer_handle,
+							ast_handle,
+							flags);
+}
+
+static inline void cdp_peer_del_ast
+	(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;
+	}
+
+	if (!soc->ops->cmn_drv_ops ||
+	    !soc->ops->cmn_drv_ops->txrx_peer_del_ast)
+		return;
+
+	soc->ops->cmn_drv_ops->txrx_peer_del_ast(soc, ast_handle);
+}
+
+static inline void *cdp_peer_ast_hash_find
+	(ol_txrx_soc_handle soc, uint8_t *ast_mac_addr)
+{
+	if (!soc || !soc->ops) {
+		QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
+				"%s: Invalid Instance:", __func__);
+		QDF_BUG(0);
+		return NULL;
+	}
+
+	if (!soc->ops->cmn_drv_ops ||
+	    !soc->ops->cmn_drv_ops->txrx_peer_ast_hash_find)
+		return NULL;
+
+	return soc->ops->cmn_drv_ops->txrx_peer_ast_hash_find(soc,
+								ast_mac_addr);
+}
+
+static inline uint8_t cdp_peer_ast_get_pdev_id
+	(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 0xff;
+	}
+
+	if (!soc->ops->cmn_drv_ops ||
+	    !soc->ops->cmn_drv_ops->txrx_peer_ast_get_pdev_id)
+		return 0xff;
+
+	return soc->ops->cmn_drv_ops->txrx_peer_ast_get_pdev_id(soc,
+								ast_handle);
+}
+
+static inline uint8_t cdp_peer_ast_get_next_hop
+	(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 0xff;
+	}
+
+	if (!soc->ops->cmn_drv_ops ||
+	    !soc->ops->cmn_drv_ops->txrx_peer_ast_get_next_hop)
+		return 0xff;
+
+	return soc->ops->cmn_drv_ops->txrx_peer_ast_get_next_hop(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)
+{
+	if (!soc || !soc->ops) {
+		QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
+				"%s: Invalid Instance:", __func__);
+		QDF_BUG(0);
+		return;
+	}
+
+	if (!soc->ops->cmn_drv_ops ||
+	    !soc->ops->cmn_drv_ops->txrx_peer_ast_set_type)
+		return;
+
+	soc->ops->cmn_drv_ops->txrx_peer_ast_set_type(soc, ast_handle, type);
+}
+
 static inline void cdp_peer_teardown
 	(ol_txrx_soc_handle soc, struct cdp_vdev *vdev, void *peer)
 {

+ 2 - 1
dp/inc/cdp_txrx_cmn_struct.h

@@ -274,9 +274,10 @@ 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_STATIC, /* static ast entry for connected peer */
 	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 */
 	CDP_TXRX_AST_TYPE_MAX
 };
 

+ 28 - 3
dp/inc/cdp_txrx_ops.h

@@ -80,6 +80,31 @@ struct cdp_cmn_ops {
 	void (*txrx_peer_teardown)
 		(struct cdp_vdev *vdev_hdl, void *peer_hdl);
 
+	int (*txrx_peer_add_ast)
+		(ol_txrx_soc_handle soc, struct cdp_peer *peer_hdl,
+		uint8_t *mac_addr, enum  cdp_txrx_ast_entry_type type,
+		uint32_t flags);
+
+	void (*txrx_peer_del_ast)
+		(ol_txrx_soc_handle soc, void *ast_hdl);
+
+	int (*txrx_peer_update_ast)
+		(ol_txrx_soc_handle soc, struct cdp_peer *peer_hdl,
+		void *ast_hdl, uint32_t flags);
+
+	void *(*txrx_peer_ast_hash_find)
+		(ol_txrx_soc_handle soc, uint8_t *ast_mac_addr);
+
+	uint8_t (*txrx_peer_ast_get_pdev_id)
+		(ol_txrx_soc_handle soc, void *ast_hdl);
+
+	uint8_t (*txrx_peer_ast_get_next_hop)
+		(ol_txrx_soc_handle soc, void *ast_hdl);
+
+	void (*txrx_peer_ast_set_type)
+		(ol_txrx_soc_handle soc, void *ast_hdl,
+		enum cdp_txrx_ast_entry_type type);
+
 	void (*txrx_peer_delete)(void *peer, uint32_t bitmap);
 
 	int (*txrx_set_monitor_mode)(struct cdp_vdev *vdev,
@@ -636,13 +661,13 @@ struct ol_if_ops {
 	int (*peer_unref_delete)(void *scn_handle, uint8_t vdev_id,
 			uint8_t *peer_macaddr);
 	bool (*is_hw_dbs_2x2_capable)(struct wlan_objmgr_psoc *psoc);
-	int (*peer_add_wds_entry)(void *ol_osif_vdev_handle,
+	int (*peer_add_wds_entry)(void *ol_soc_handle,
 			const uint8_t *dest_macaddr, uint8_t *peer_macaddr,
 			uint32_t flags);
-	int (*peer_update_wds_entry)(void *ol_osif_vdev_handle,
+	int (*peer_update_wds_entry)(void *ol_soc_handle,
 			uint8_t *dest_macaddr, uint8_t *peer_macaddr,
 			uint32_t flags);
-	void (*peer_del_wds_entry)(void *ol_osif_vdev_handle,
+	void (*peer_del_wds_entry)(void *ol_soc_handle,
 			uint8_t *wds_macaddr);
 	QDF_STATUS (*lro_hash_config)(void *scn_handle,
 			struct cdp_lro_hash_config *lro_hash);

+ 116 - 18
dp/wifi3.0/dp_main.c

@@ -61,6 +61,9 @@ static void dp_pkt_log_con_service(struct cdp_pdev *ppdev, void *scn);
 #endif
 #endif
 static void dp_pktlogmod_exit(struct dp_pdev *handle);
+static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle,
+					uint8_t *peer_mac_addr);
+static void dp_peer_delete_wifi3(void *peer_handle, uint32_t bitmap);
 
 #define DP_INTR_POLL_TIMER_MS	10
 #define DP_WDS_AGING_TIMER_DEFAULT_MS	120000
@@ -282,6 +285,83 @@ const int dp_stats_mapping_table[][STATS_TYPE_MAX] = {
 	{TXRX_FW_STATS_INVALID, TXRX_SRNG_PTR_STATS},
 };
 
+static int dp_peer_add_ast_wifi3(struct cdp_soc_t *soc_hdl,
+					struct cdp_peer *peer_hdl,
+					uint8_t *mac_addr,
+					enum cdp_txrx_ast_entry_type type,
+					uint32_t flags)
+{
+
+	return dp_peer_add_ast((struct dp_soc *)soc_hdl,
+				(struct dp_peer *)peer_hdl,
+				mac_addr,
+				type,
+				flags);
+}
+
+static void dp_peer_del_ast_wifi3(struct cdp_soc_t *soc_hdl,
+					 void *ast_entry_hdl)
+{
+	struct dp_soc *soc = (struct dp_soc *)soc_hdl;
+	qdf_spin_lock_bh(&soc->ast_lock);
+	dp_peer_del_ast((struct dp_soc *)soc_hdl,
+			(struct dp_ast_entry *)ast_entry_hdl);
+	qdf_spin_unlock_bh(&soc->ast_lock);
+}
+
+static int dp_peer_update_ast_wifi3(struct cdp_soc_t *soc_hdl,
+						struct cdp_peer *peer_hdl,
+						void *ast_entry_hdl,
+						uint32_t flags)
+{
+	int status;
+	struct dp_soc *soc = (struct dp_soc *)soc_hdl;
+	qdf_spin_lock_bh(&soc->ast_lock);
+	status = dp_peer_update_ast(soc,
+					(struct dp_peer *)peer_hdl,
+					(struct dp_ast_entry *)ast_entry_hdl,
+					flags);
+	qdf_spin_unlock_bh(&soc->ast_lock);
+	return status;
+}
+
+static void *dp_peer_ast_hash_find_wifi3(struct cdp_soc_t *soc_hdl,
+						uint8_t *ast_mac_addr)
+{
+	struct dp_ast_entry *ast_entry;
+	struct dp_soc *soc = (struct dp_soc *)soc_hdl;
+	qdf_spin_lock_bh(&soc->ast_lock);
+	ast_entry = dp_peer_ast_hash_find(soc, ast_mac_addr);
+	qdf_spin_unlock_bh(&soc->ast_lock);
+	return (void *)ast_entry;
+}
+
+static uint8_t dp_peer_ast_get_pdev_id_wifi3(struct cdp_soc_t *soc_hdl,
+							void *ast_entry_hdl)
+{
+	return dp_peer_ast_get_pdev_id((struct dp_soc *)soc_hdl,
+					(struct dp_ast_entry *)ast_entry_hdl);
+}
+
+static uint8_t dp_peer_ast_get_next_hop_wifi3(struct cdp_soc_t *soc_hdl,
+							void *ast_entry_hdl)
+{
+	return dp_peer_ast_get_next_hop((struct dp_soc *)soc_hdl,
+					(struct dp_ast_entry *)ast_entry_hdl);
+}
+
+static void dp_peer_ast_set_type_wifi3(
+					struct cdp_soc_t *soc_hdl,
+					void *ast_entry_hdl,
+					enum cdp_txrx_ast_entry_type type)
+{
+	dp_peer_ast_set_type((struct dp_soc *)soc_hdl,
+				(struct dp_ast_entry *)ast_entry_hdl,
+				type);
+}
+
+
+
 /**
  * dp_srng_find_ring_in_mask() - find which ext_group a ring belongs
  * @ring_num: ring num of the ring being queried
@@ -468,14 +548,20 @@ static void dp_print_ast_stats(struct dp_soc *soc)
 							" type = %d"
 							" next_hop = %d"
 							" is_active = %d"
-							" is_bss = %d",
+							" is_bss = %d"
+							" ast_idx = %d"
+							" pdev_id = %d"
+							" vdev_id = %d",
 							++num_entries,
 							ase->mac_addr.raw,
 							ase->peer->mac_addr.raw,
 							ase->type,
 							ase->next_hop,
 							ase->is_active,
-							ase->is_bss);
+							ase->is_bss,
+							ase->ast_idx,
+							ase->pdev_id,
+							ase->vdev_id);
 				}
 			}
 		}
@@ -1462,8 +1548,12 @@ static void dp_wds_aging_timer_fn(void *soc_hdl)
 				DP_PEER_ITERATE_ASE_LIST(peer, ase, temp_ase) {
 					/*
 					 * Do not expire static ast entries
+					 * and HM WDS entries
 					 */
-					if (ase->type == CDP_TXRX_AST_TYPE_STATIC)
+					if (ase->type ==
+						CDP_TXRX_AST_TYPE_STATIC ||
+						ase->type ==
+						CDP_TXRX_AST_TYPE_WDS_HM)
 						continue;
 
 					if (ase->is_active) {
@@ -1472,11 +1562,6 @@ static void dp_wds_aging_timer_fn(void *soc_hdl)
 					}
 
 					DP_STATS_INC(soc, ast.aged_out, 1);
-
-					soc->cdp_soc.ol_ops->peer_del_wds_entry(
-							vdev->osif_vdev,
-							ase->mac_addr.raw);
-
 					dp_peer_del_ast(soc, ase);
 				}
 			}
@@ -3015,6 +3100,10 @@ static struct cdp_vdev *dp_vdev_attach_wifi3(struct cdp_pdev *txrx_pdev,
 		"Created vdev %pK (%pM)", vdev, vdev->mac_addr.raw);
 	DP_STATS_INIT(vdev);
 
+	if (wlan_op_mode_sta == vdev->opmode)
+		dp_peer_create_wifi3((struct cdp_vdev *)vdev,
+							vdev->mac_addr.raw);
+
 	return (struct cdp_vdev *)vdev;
 
 fail1:
@@ -3112,6 +3201,9 @@ static void dp_vdev_detach_wifi3(struct cdp_vdev *vdev_handle,
 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH,
 		FL("deleting vdev object %pK (%pM)"), vdev, vdev->mac_addr.raw);
 
+	if (wlan_op_mode_sta == vdev->opmode)
+		dp_peer_delete_wifi3(vdev->vap_bss_peer, 0);
+
 	qdf_mem_free(vdev);
 
 	if (callback)
@@ -3157,7 +3249,7 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle,
 	/* store provided params */
 	peer->vdev = vdev;
 
-	dp_peer_add_ast(soc, peer, peer_mac_addr, dp_ast_type_static);
+	dp_peer_add_ast(soc, peer, peer_mac_addr, CDP_TXRX_AST_TYPE_STATIC, 0);
 
 	qdf_spinlock_create(&peer->peer_info_lock);
 
@@ -3179,7 +3271,11 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle,
 	qdf_atomic_inc(&peer->ref_cnt);
 
 	/* add this peer into the vdev's list */
-	TAILQ_INSERT_TAIL(&vdev->peer_list, peer, peer_list_elem);
+	if (wlan_op_mode_sta == vdev->opmode)
+		TAILQ_INSERT_HEAD(&vdev->peer_list, peer, peer_list_elem);
+	else
+		TAILQ_INSERT_TAIL(&vdev->peer_list, peer, peer_list_elem);
+
 	qdf_spin_unlock_bh(&soc->peer_ref_mutex);
 
 	/* TODO: See if hash based search is required */
@@ -6087,16 +6183,11 @@ static inline void dp_peer_delete_ast_entries(struct dp_soc *soc,
 		struct dp_peer *peer)
 {
 	struct dp_ast_entry *ast_entry, *temp_ast_entry;
-	qdf_spin_lock_bh(&soc->ast_lock);
-	DP_PEER_ITERATE_ASE_LIST(peer, ast_entry, temp_ast_entry) {
-		if (ast_entry->next_hop) {
-			soc->cdp_soc.ol_ops->peer_del_wds_entry(
-					peer->vdev->osif_vdev,
-					ast_entry->mac_addr.raw);
-		}
 
+	qdf_spin_lock_bh(&soc->ast_lock);
+	DP_PEER_ITERATE_ASE_LIST(peer, ast_entry, temp_ast_entry)
 		dp_peer_del_ast(soc, ast_entry);
-	}
+
 	qdf_spin_unlock_bh(&soc->ast_lock);
 }
 #else
@@ -6176,6 +6267,13 @@ static struct cdp_cmn_ops dp_ops_cmn = {
 #else
 	.txrx_peer_teardown = NULL,
 #endif
+	.txrx_peer_add_ast = dp_peer_add_ast_wifi3,
+	.txrx_peer_del_ast = dp_peer_del_ast_wifi3,
+	.txrx_peer_update_ast = dp_peer_update_ast_wifi3,
+	.txrx_peer_ast_hash_find = dp_peer_ast_hash_find_wifi3,
+	.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_delete = dp_peer_delete_wifi3,
 	.txrx_vdev_register = dp_vdev_register_wifi3,
 	.txrx_soc_detach = dp_soc_detach_wifi3,

+ 158 - 24
dp/wifi3.0/dp_peer.c

@@ -314,20 +314,15 @@ static inline void dp_peer_ast_hash_remove(struct dp_soc *soc,
  * Return: AST entry
  */
 struct dp_ast_entry *dp_peer_ast_hash_find(struct dp_soc *soc,
-	uint8_t *ast_mac_addr, int mac_addr_is_aligned)
+						uint8_t *ast_mac_addr)
 {
 	union dp_align_mac_addr local_mac_addr_aligned, *mac_addr;
 	unsigned index;
 	struct dp_ast_entry *ase;
 
-	if (mac_addr_is_aligned) {
-		mac_addr = (union dp_align_mac_addr *) ast_mac_addr;
-	} else {
-		qdf_mem_copy(
-			&local_mac_addr_aligned.raw[0],
+	qdf_mem_copy(&local_mac_addr_aligned.raw[0],
 			ast_mac_addr, DP_MAC_ADDR_LEN);
-		mac_addr = &local_mac_addr_aligned;
-	}
+	mac_addr = &local_mac_addr_aligned;
 
 	index = dp_peer_ast_hash_index(soc, mac_addr);
 	TAILQ_FOREACH(ase, &soc->ast_hash.bins[index], hash_list_elem) {
@@ -408,10 +403,23 @@ static inline void dp_peer_map_ast(struct dp_soc *soc,
  * Return: 0 if new entry is allocated,
  *         1 if entry already exists or if allocation has failed
  */
-int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer,
-		uint8_t *mac_addr, enum dp_ast_type is_self)
+int dp_peer_add_ast(struct dp_soc *soc,
+			struct dp_peer *peer,
+			uint8_t *mac_addr,
+			enum cdp_txrx_ast_entry_type type,
+			uint32_t flags)
 {
 	struct dp_ast_entry *ast_entry;
+	struct dp_vdev *vdev = peer->vdev;
+	uint8_t next_node_mac[6];
+	bool ret = 1;
+
+	if (!vdev) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			FL("Peers vdev is NULL"));
+		QDF_ASSERT(0);
+		return ret;
+	}
 
 	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
 		"%s: peer %pK mac %02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -421,13 +429,14 @@ int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer,
 	qdf_spin_lock_bh(&soc->ast_lock);
 
 	/* If AST entry already exists , just return from here */
-	ast_entry = dp_peer_ast_hash_find(soc, mac_addr, 0);
+	ast_entry = dp_peer_ast_hash_find(soc, mac_addr);
+
 	if (ast_entry) {
 		if (ast_entry->type == CDP_TXRX_AST_TYPE_MEC)
 			ast_entry->is_active = TRUE;
 
 		qdf_spin_unlock_bh(&soc->ast_lock);
-		return 1;
+		return ret;
 	}
 
 	ast_entry = (struct dp_ast_entry *)
@@ -438,22 +447,28 @@ int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer,
 		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
 			FL("fail to allocate ast_entry"));
 		QDF_ASSERT(0);
-		return 1;
+		return ret;
 	}
 
 	qdf_mem_copy(&ast_entry->mac_addr.raw[0], mac_addr, DP_MAC_ADDR_LEN);
 	ast_entry->peer = peer;
+	ast_entry->pdev_id = vdev->pdev->pdev_id;
+	ast_entry->vdev_id = vdev->vdev_id;
 
-	switch (is_self) {
-	case dp_ast_type_static:
+	switch (type) {
+	case CDP_TXRX_AST_TYPE_STATIC:
 		peer->self_ast_entry = ast_entry;
 		ast_entry->type = CDP_TXRX_AST_TYPE_STATIC;
 		break;
-	case dp_ast_type_wds:
+	case CDP_TXRX_AST_TYPE_WDS:
 		ast_entry->next_hop = 1;
 		ast_entry->type = CDP_TXRX_AST_TYPE_WDS;
 		break;
-	case dp_ast_type_mec:
+	case CDP_TXRX_AST_TYPE_WDS_HM:
+		ast_entry->next_hop = 1;
+		ast_entry->type = CDP_TXRX_AST_TYPE_WDS_HM;
+		break;
+	case CDP_TXRX_AST_TYPE_MEC:
 		ast_entry->next_hop = 1;
 		ast_entry->type = CDP_TXRX_AST_TYPE_MEC;
 		break;
@@ -467,7 +482,21 @@ int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer,
 	DP_STATS_INC(soc, ast.added, 1);
 	dp_peer_ast_hash_add(soc, ast_entry);
 	qdf_spin_unlock_bh(&soc->ast_lock);
-	return 0;
+
+	if (ast_entry->type == CDP_TXRX_AST_TYPE_WDS)
+		qdf_mem_copy(next_node_mac, peer->mac_addr.raw, 6);
+	else
+		qdf_mem_copy(next_node_mac, peer->vdev->mac_addr.raw, 6);
+
+	if (ast_entry->type != CDP_TXRX_AST_TYPE_STATIC) {
+		ret = soc->cdp_soc.ol_ops->peer_add_wds_entry(
+				peer->vdev->osif_vdev,
+				mac_addr,
+				next_node_mac,
+				flags);
+	}
+
+	return ret;
 }
 
 /*
@@ -481,31 +510,117 @@ int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer,
  *
  * Return: None
  */
-void dp_peer_del_ast(struct dp_soc *soc,
-		struct dp_ast_entry *ast_entry)
+void dp_peer_del_ast(struct dp_soc *soc, struct dp_ast_entry *ast_entry)
 {
 	struct dp_peer *peer = ast_entry->peer;
+
+	if (ast_entry->next_hop)
+		soc->cdp_soc.ol_ops->peer_del_wds_entry(peer->vdev->osif_vdev,
+						ast_entry->mac_addr.raw);
+
 	soc->ast_table[ast_entry->ast_idx] = NULL;
 	TAILQ_REMOVE(&peer->ast_entry_list, ast_entry, ase_list_elem);
 	DP_STATS_INC(soc, ast.deleted, 1);
 	dp_peer_ast_hash_remove(soc, ast_entry);
 	qdf_mem_free(ast_entry);
 }
+
+/*
+ * dp_peer_update_ast() - Delete and free AST entry
+ * @soc: SoC handle
+ * @peer: peer to which ast node belongs
+ * @ast_entry: AST entry of the node
+ * @flags: wds or hmwds
+ *
+ * This function update the AST entry to the roamed peer and soc tables
+ * It assumes caller has taken the ast lock to protect the access to these
+ * tables
+ *
+ * Return: 0 if ast entry is updated successfully
+ *         1 failure
+ */
+int dp_peer_update_ast(struct dp_soc *soc, struct dp_peer *peer,
+		       struct dp_ast_entry *ast_entry, uint32_t flags)
+{
+	bool ret = 1;
+
+	ast_entry->peer = peer;
+	if (ast_entry->type != CDP_TXRX_AST_TYPE_STATIC) {
+		ret = soc->cdp_soc.ol_ops->peer_update_wds_entry(
+				peer->vdev->osif_vdev,
+				ast_entry->mac_addr.raw,
+				peer->mac_addr.raw,
+				flags);
+	}
+	return ret;
+}
+
+/*
+ * dp_peer_ast_get_pdev_id() - get pdev_id from the ast entry
+ * @soc: SoC handle
+ * @ast_entry: AST entry of the node
+ *
+ * This function gets the pdev_id from the ast entry.
+ *
+ * Return: (uint8_t) pdev_id
+ */
+uint8_t dp_peer_ast_get_pdev_id(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry)
+{
+	return ast_entry->pdev_id;
+}
+
+/*
+ * dp_peer_ast_get_next_hop() - get next_hop from the ast entry
+ * @soc: SoC handle
+ * @ast_entry: AST entry of the node
+ *
+ * This function gets the next hop from the ast entry.
+ *
+ * Return: (uint8_t) next_hop
+ */
+uint8_t dp_peer_ast_get_next_hop(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry)
+{
+	return ast_entry->next_hop;
+}
+
+/*
+ * dp_peer_ast_set_type() - set type from the ast entry
+ * @soc: SoC handle
+ * @ast_entry: AST entry of the node
+ *
+ * This function sets the type in the ast entry.
+ *
+ * Return:
+ */
+void dp_peer_ast_set_type(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry,
+				enum cdp_txrx_ast_entry_type type)
+{
+	ast_entry->type = type;
+}
+
 #else
 int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer,
-		uint8_t *mac_addr, enum dp_ast_type is_self)
+		uint8_t *mac_addr, enum cdp_txrx_ast_entry_type type,
+		uint32_t flags)
 {
 	return 1;
 }
 
-void dp_peer_del_ast(struct dp_soc *soc,
-		struct dp_ast_entry *ast_entry)
+void dp_peer_del_ast(struct dp_soc *soc, struct dp_ast_entry *ast_entry)
 {
 }
 
+int dp_peer_update_ast(struct dp_soc *soc, struct dp_peer *peer,
+			struct dp_ast_entry *ast_entry, uint32_t flags)
+{
+	return 1;
+}
 
 struct dp_ast_entry *dp_peer_ast_hash_find(struct dp_soc *soc,
-	uint8_t *ast_mac_addr, int mac_addr_is_aligned)
+						uint8_t *ast_mac_addr)
 {
 	return NULL;
 }
@@ -525,6 +640,25 @@ static inline void dp_peer_map_ast(struct dp_soc *soc,
 static void dp_peer_ast_hash_detach(struct dp_soc *soc)
 {
 }
+
+void dp_peer_ast_set_type(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry,
+				enum cdp_txrx_ast_entry_type type)
+{
+}
+
+uint8_t dp_peer_ast_get_pdev_id(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry)
+{
+	return 0xff;
+}
+
+
+uint8_t dp_peer_ast_get_next_hop(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry)
+{
+	return 0xff;
+}
 #endif
 
 #if ATH_SUPPORT_WRAP

+ 21 - 6
dp/wifi3.0/dp_peer.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -54,13 +54,28 @@ void dp_rx_sec_ind_handler(void *soc_handle, uint16_t peer_id,
 uint8_t dp_get_peer_mac_addr_frm_id(struct cdp_soc_t *soc_handle,
 		uint16_t peer_id, uint8_t *peer_mac);
 
-
 int dp_peer_add_ast(struct dp_soc *soc, struct dp_peer *peer,
-		uint8_t *mac_addr, enum dp_ast_type is_self);
-void dp_peer_del_ast(struct dp_soc *soc,
-		struct dp_ast_entry *ast_entry);
+		uint8_t *mac_addr, enum cdp_txrx_ast_entry_type type,
+		uint32_t flags);
+
+void dp_peer_del_ast(struct dp_soc *soc, struct dp_ast_entry *ast_entry);
+
+int dp_peer_update_ast(struct dp_soc *soc, struct dp_peer *peer,
+			struct dp_ast_entry *ast_entry,	uint32_t flags);
+
 struct dp_ast_entry *dp_peer_ast_hash_find(struct dp_soc *soc,
-		uint8_t *ast_mac_addr, int mac_addr_is_aligned);
+						uint8_t *ast_mac_addr);
+
+uint8_t dp_peer_ast_get_pdev_id(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry);
+
+
+uint8_t dp_peer_ast_get_next_hop(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry);
+
+void dp_peer_ast_set_type(struct dp_soc *soc,
+				struct dp_ast_entry *ast_entry,
+				enum cdp_txrx_ast_entry_type type);
 
 /*
  * dp_get_vdev_from_soc_vdev_id_wifi3() -

+ 6 - 13
dp/wifi3.0/dp_rx.h

@@ -365,14 +365,12 @@ dp_rx_wds_srcport_learn(struct dp_soc *soc,
 		IEEE80211_ADDR_LEN);
 
 	if (qdf_unlikely(!hal_rx_msdu_end_sa_is_valid_get(rx_tlv_hdr))) {
-		if (!dp_peer_add_ast(soc, ta_peer, wds_src_mac,
-							dp_ast_type_wds)) {
-			ret = soc->cdp_soc.ol_ops->peer_add_wds_entry(
-					ta_peer->vdev->osif_vdev,
+		ret = dp_peer_add_ast(soc,
+					ta_peer,
 					wds_src_mac,
-					ta_peer->mac_addr.raw,
+					CDP_TXRX_AST_TYPE_WDS,
 					flags);
-		}
+
 	} else {
 		/*
 		 * Get the AST entry from HW SA index and mark it as active
@@ -391,13 +389,8 @@ dp_rx_wds_srcport_learn(struct dp_soc *soc,
 			ast->is_active = TRUE;
 		}
 
-		if (sa_sw_peer_id != ta_peer->peer_ids[0]) {
-			ret = soc->cdp_soc.ol_ops->peer_update_wds_entry(
-					ta_peer->vdev->osif_vdev,
-					wds_src_mac,
-					ta_peer->mac_addr.raw,
-					flags);
-		}
+		if (ast && sa_sw_peer_id != ta_peer->peer_ids[0])
+			dp_peer_update_ast(soc, ta_peer, ast, flags);
 	}
 	return;
 }

+ 28 - 3
dp/wifi3.0/dp_rx_err.c

@@ -66,7 +66,7 @@ static inline bool dp_rx_mcast_echo_check(struct dp_soc *soc,
 {
 	struct dp_vdev *vdev = peer->vdev;
 	struct dp_ast_entry *ase;
-	uint16_t sa_idx;
+	uint16_t sa_idx = 0;
 	uint8_t *data;
 
 	/*
@@ -99,7 +99,8 @@ static inline bool dp_rx_mcast_echo_check(struct dp_soc *soc,
 	if (hal_rx_msdu_end_sa_is_valid_get(rx_tlv_hdr)) {
 		sa_idx = hal_rx_msdu_end_sa_idx_get(rx_tlv_hdr);
 
-		if ((sa_idx < 0) || (sa_idx > (WLAN_UMAC_PSOC_MAX_PEERS * 2))) {
+		if ((sa_idx < 0) ||
+				(sa_idx >= (WLAN_UMAC_PSOC_MAX_PEERS * 2))) {
 			qdf_spin_unlock_bh(&soc->ast_lock);
 			QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
 					"invalid sa_idx: %d", sa_idx);
@@ -107,10 +108,34 @@ static inline bool dp_rx_mcast_echo_check(struct dp_soc *soc,
 		}
 
 		ase = soc->ast_table[sa_idx];
+		if (!ase) {
+			/* We do not get a peer map event for STA and without
+			 * this event we don't know what is STA's sa_idx.
+			 * For this reason the AST is still not associated to
+			 * any index postion in ast_table.
+			 * In these kind of scenarios where sa is valid but
+			 * ast is not in ast_table, we use the below API to get
+			 * AST entry for STA's own mac_address.
+			 */
+			ase = dp_peer_ast_hash_find(soc,
+							&data[DP_MAC_ADDR_LEN]);
+
+		}
 	} else
-		ase = dp_peer_ast_hash_find(soc, &data[DP_MAC_ADDR_LEN], 0);
+		ase = dp_peer_ast_hash_find(soc, &data[DP_MAC_ADDR_LEN]);
 
 	if (ase) {
+		ase->ast_idx = sa_idx;
+		soc->ast_table[sa_idx] = ase;
+
+		if (ase->pdev_id != vdev->pdev->pdev_id) {
+			qdf_spin_unlock_bh(&soc->ast_lock);
+			QDF_TRACE(QDF_MODULE_ID_DP,
+				QDF_TRACE_LEVEL_INFO,
+				 "Detected DBDC Root AP");
+			return false;
+		}
+
 		if ((ase->type == CDP_TXRX_AST_TYPE_MEC) ||
 				(ase->peer != peer)) {
 			qdf_spin_unlock_bh(&soc->ast_lock);

+ 8 - 8
dp/wifi3.0/dp_tx.c

@@ -1605,7 +1605,8 @@ static qdf_nbuf_t dp_tx_prepare_nawds(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 	qdf_nbuf_t nbuf_copy;
 
 	qdf_spin_lock_bh(&(soc->ast_lock));
-	ast_entry = dp_peer_ast_hash_find(soc, (uint8_t *)(eh->ether_shost), 0);
+	ast_entry = dp_peer_ast_hash_find(soc, (uint8_t *)(eh->ether_shost));
+
 	if (ast_entry)
 		sa_peer = ast_entry->peer;
 
@@ -2028,7 +2029,8 @@ void dp_tx_reinject_handler(struct dp_tx_desc_s *tx_desc, uint8_t *status)
 
 	qdf_spin_lock_bh(&(soc->ast_lock));
 
-	ast_entry = dp_peer_ast_hash_find(soc, (uint8_t *)(eh->ether_shost), 0);
+	ast_entry = dp_peer_ast_hash_find(soc, (uint8_t *)(eh->ether_shost));
+
 	if (ast_entry)
 		sa_peer = ast_entry->peer;
 
@@ -2364,14 +2366,12 @@ void dp_tx_mec_handler(struct dp_vdev *vdev, uint8_t *status)
 		mac_addr[(DP_MAC_ADDR_LEN - 1) - i] =
 					status[(DP_MAC_ADDR_LEN - 2) + i];
 
-	if (qdf_mem_cmp(mac_addr, vdev->mac_addr.raw, DP_MAC_ADDR_LEN) &&
-		!dp_peer_add_ast(soc, peer, mac_addr, dp_ast_type_mec)) {
-			soc->cdp_soc.ol_ops->peer_add_wds_entry(
-				vdev->osif_vdev,
+	if (qdf_mem_cmp(mac_addr, vdev->mac_addr.raw, DP_MAC_ADDR_LEN))
+		dp_peer_add_ast(soc,
+				peer,
 				mac_addr,
-				vdev->mac_addr.raw,
+				CDP_TXRX_AST_TYPE_MEC,
 				flags);
-	}
 }
 #else
 static void dp_tx_mec_handler(struct dp_vdev *vdev, uint8_t *status)

+ 4 - 0
dp/wifi3.0/dp_types.h

@@ -555,6 +555,8 @@ union dp_align_mac_addr {
  *             (used for aging out/expiry)
  * @ase_list_elem: node in peer AST list
  * @is_bss: flag to indicate if entry corresponds to bss peer
+ * @pdev_id: pdev ID
+ * @vdev_id: vdev ID
  * @type: flag to indicate type of the entry(static/WDS/MEC)
  * @hash_list_elem: node in soc AST hash list (mac address used as hash)
  */
@@ -566,6 +568,8 @@ struct dp_ast_entry {
 	bool next_hop;
 	bool is_active;
 	bool is_bss;
+	uint8_t pdev_id;
+	uint8_t vdev_id;
 	enum cdp_txrx_ast_entry_type type;
 	TAILQ_ENTRY(dp_ast_entry) ase_list_elem;
 	TAILQ_ENTRY(dp_ast_entry) hash_list_elem;