Browse Source

qcacmn: Add support for intra-bss forwarding

pkts should be forwarded from one STA to another
STA belonging to same VAP from within the driver

Change-Id: I68eb0dd91f7ac54352b4882ffdb9d5d53d627db1

Conflicts:
	dp/wifi3.0/dp_rx.c
	dp/wifi3.0/dp_types.h

Conflicts:
	dp/wifi3.0/dp_rx.c

Change-Id: I68eb0dd91f7ac54352b4882ffdb9d5d53d627db1
Tallapragada Kalyan 8 years ago
parent
commit
6f6166e36c
7 changed files with 394 additions and 19 deletions
  1. 5 2
      dp/wifi3.0/dp_htt.c
  2. 20 0
      dp/wifi3.0/dp_main.c
  3. 86 7
      dp/wifi3.0/dp_peer.c
  4. 1 1
      dp/wifi3.0/dp_peer.h
  5. 60 8
      dp/wifi3.0/dp_rx.c
  6. 147 1
      dp/wifi3.0/dp_types.h
  7. 75 0
      dp/wifi3.0/hal_rx.h

+ 5 - 2
dp/wifi3.0/dp_htt.c

@@ -518,9 +518,12 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt)
 			u_int8_t mac_addr_deswizzle_buf[HTT_MAC_ADDR_LEN];
 			u_int8_t *peer_mac_addr;
 			u_int16_t peer_id;
+			u_int16_t hw_peer_id;
 			u_int8_t vdev_id;
 
 			peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word);
+			hw_peer_id =
+				HTT_RX_PEER_MAP_HW_PEER_ID_GET(*(msg_word+2));
 			vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word);
 			peer_mac_addr = htt_t2h_mac_addr_deswizzle(
 				(u_int8_t *) (msg_word+1),
@@ -530,8 +533,8 @@ static void dp_htt_t2h_msg_handler(void *context, HTC_PACKET *pkt)
 				"HTT_T2H_MSG_TYPE_PEER_MAP msg for peer id %d vdev id %d n",
 				peer_id, vdev_id);
 
-			dp_rx_peer_map_handler(
-				soc->dp_soc, peer_id, vdev_id, peer_mac_addr);
+			dp_rx_peer_map_handler(soc->dp_soc, peer_id, hw_peer_id,
+						vdev_id, peer_mac_addr);
 			break;
 		}
 	case HTT_T2H_MSG_TYPE_PEER_UNMAP:

+ 20 - 0
dp/wifi3.0/dp_main.c

@@ -1692,6 +1692,13 @@ static void *dp_peer_create_wifi3(struct cdp_vdev *vdev_handle,
 	if (!peer)
 		return NULL; /* failure */
 
+	TAILQ_INIT(&peer->ast_entry_list);
+	qdf_mem_copy(&peer->self_ast_entry.mac_addr, peer_mac_addr,
+			DP_MAC_ADDR_LEN);
+	peer->self_ast_entry.peer = peer;
+	TAILQ_INSERT_HEAD(&peer->ast_entry_list, &peer->self_ast_entry,
+				ast_entry_elem);
+
 	qdf_mem_zero(peer, sizeof(struct dp_peer));
 	qdf_spinlock_create(&peer->peer_info_lock);
 
@@ -1849,6 +1856,8 @@ void dp_peer_unref_delete(void *peer_handle)
 	struct dp_peer *tmppeer;
 	int found = 0;
 	uint16_t peer_id;
+	uint16_t hw_peer_id;
+	struct dp_ast_entry *ast_entry;
 
 	/*
 	 * Hold the lock all the way from checking if the peer ref count
@@ -1932,6 +1941,17 @@ void dp_peer_unref_delete(void *peer_handle)
 #ifdef notyet
 		qdf_mempool_free(soc->osdev, soc->mempool_ol_ath_peer, peer);
 #else
+		TAILQ_FOREACH(ast_entry, &peer->ast_entry_list,
+				ast_entry_elem) {
+			hw_peer_id = ast_entry->ast_idx;
+			if (peer->self_ast_entry.ast_idx != hw_peer_id)
+				qdf_mem_free(ast_entry);
+			else
+				peer->self_ast_entry.ast_idx =
+							HTT_INVALID_PEER;
+
+			soc->ast_table[hw_peer_id] = NULL;
+		}
 		qdf_mem_free(peer);
 #endif
 		if (soc->cdp_soc.ol_ops->peer_unref_delete) {

+ 86 - 7
dp/wifi3.0/dp_peer.c

@@ -327,7 +327,8 @@ int dp_peer_find_attach(struct dp_soc *soc)
 }
 
 static inline void dp_peer_find_add_id(struct dp_soc *soc,
-	uint8_t *peer_mac_addr, uint16_t peer_id, uint8_t vdev_id)
+	uint8_t *peer_mac_addr, uint16_t peer_id, uint16_t hw_peer_id,
+	uint8_t vdev_id)
 {
 	struct dp_peer *peer;
 
@@ -353,6 +354,8 @@ static inline void dp_peer_find_add_id(struct dp_soc *soc,
 			  "%s: ref_cnt: %d", __func__,
 			   qdf_atomic_read(&peer->ref_cnt));
 		soc->peer_id_to_obj_map[peer_id] = peer;
+		peer->self_ast_entry.ast_idx = hw_peer_id;
+		soc->ast_table[hw_peer_id] = &peer->self_ast_entry;
 
 		if (dp_peer_find_add_id_to_obj(peer, peer_id)) {
 			/* TBDXXX: assert for now */
@@ -363,19 +366,95 @@ static inline void dp_peer_find_add_id(struct dp_soc *soc,
 	}
 }
 
+static inline void dp_peer_add_ast(struct dp_soc *soc,
+	struct dp_peer *peer, uint8_t *peer_mac_addr, uint16_t hw_peer_id,
+	uint8_t vdev_id)
+{
+	struct dp_ast_entry *ast_entry;
+
+	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+		"%s: peer %p ID %d vid %d mac %02x:%02x:%02x:%02x:%02x:%02x\n",
+		__func__, peer, hw_peer_id, vdev_id, peer_mac_addr[0],
+		peer_mac_addr[1], peer_mac_addr[2], peer_mac_addr[3],
+		peer_mac_addr[4], peer_mac_addr[5]);
+
+	TAILQ_FOREACH(ast_entry, &peer->ast_entry_list, ast_entry_elem) {
+		if (!(qdf_mem_cmp(peer_mac_addr, ast_entry->mac_addr,
+				DP_MAC_ADDR_LEN))) {
+			soc->ast_table[ast_entry->ast_idx] = NULL;
+			ast_entry->ast_idx = hw_peer_id;
+			soc->ast_table[hw_peer_id] = ast_entry;
+			return;
+		}
+	}
+
+	ast_entry = (struct dp_ast_entry *)
+			qdf_mem_malloc(sizeof(struct dp_ast_entry));
+
+	if (!ast_entry) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			FL("fail to allocate ast_entry for: %d"), hw_peer_id);
+		QDF_ASSERT(0);
+	}
+
+	qdf_mem_copy(&ast_entry->mac_addr, peer_mac_addr, DP_MAC_ADDR_LEN);
+	ast_entry->peer = peer;
+	ast_entry->next_hop = 1;
+	TAILQ_INSERT_TAIL(&peer->ast_entry_list, ast_entry, ast_entry_elem);
+	soc->ast_table[hw_peer_id] = ast_entry;
+	return;
+}
+
+/**
+ * dp_rx_peer_map_handler() - handle peer map event from firmware
+ * @soc_handle - genereic soc handle
+ * @peeri_id - peer_id from firmware
+ * @hw_peer_id - ast index for this peer
+ * vdev_id - vdev ID
+ * peer_mac_addr - macc assress of the peer
+ *
+ * associate the peer_id that firmware provided with peer entry
+ * and update the ast table in the host with the hw_peer_id.
+ *
+ * Return: none
+ */
+
 void
-dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, uint8_t vdev_id,
-	uint8_t *peer_mac_addr)
+dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, uint16_t hw_peer_id,
+			uint8_t vdev_id, uint8_t *peer_mac_addr)
 {
 	struct dp_soc *soc = (struct dp_soc *)soc_handle;
+	struct dp_peer *peer = NULL;
+
 
 	QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH,
-		"peer_map_event (soc:%p): peer_id %d, peer_mac "
+		"peer_map_event (soc:%p): peer_id %di, hw_peer_id %d, peer_mac "
 		"%02x:%02x:%02x:%02x:%02x:%02x, vdev_id %d\n", soc, peer_id,
-		peer_mac_addr[0], peer_mac_addr[1], peer_mac_addr[2],
-		peer_mac_addr[3], peer_mac_addr[4], peer_mac_addr[5], vdev_id);
+		hw_peer_id, peer_mac_addr[0], peer_mac_addr[1],
+		peer_mac_addr[2], peer_mac_addr[3], peer_mac_addr[4],
+		peer_mac_addr[5], vdev_id);
+
+	peer = soc->peer_id_to_obj_map[peer_id];
 
-	dp_peer_find_add_id(soc, peer_mac_addr, peer_id, vdev_id);
+	if ((hw_peer_id < 0) || (hw_peer_id > WLAN_UMAC_PSOC_MAX_PEERS)) {
+		QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+			"invalid hw_peer_id: %d", hw_peer_id);
+		QDF_ASSERT(0);
+	}
+
+	/*
+	 * check if peer already exists for this peer_id, if so
+	 * this peer map event is in response for a wds peer add
+	 * wmi command sent during wds source port learning.
+	 * in this case just add the ast entry to the existing
+	 * peer ast_list.
+	 */
+	if (!peer)
+		dp_peer_find_add_id(soc, peer_mac_addr, peer_id,
+					hw_peer_id, vdev_id);
+	else
+		dp_peer_add_ast(soc, peer, peer_mac_addr,
+					hw_peer_id, vdev_id);
 }
 
 void

+ 1 - 1
dp/wifi3.0/dp_peer.h

@@ -46,7 +46,7 @@ dp_peer_find_by_id(struct dp_soc *soc,
 }
 
 void dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id,
-	uint8_t vdev_id, uint8_t *peer_mac_addr);
+	uint16_t hw_peer_id, uint8_t vdev_id, uint8_t *peer_mac_addr);
 void dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id);
 void dp_rx_sec_ind_handler(void *soc_handle, uint16_t peer_id,
 	enum htt_sec_type sec_type, int is_unicast,

+ 60 - 8
dp/wifi3.0/dp_rx.c

@@ -283,10 +283,62 @@ dp_rx_intrabss_fwd(struct dp_soc *soc,
 			uint8_t *rx_tlv_hdr,
 			qdf_nbuf_t nbuf)
 {
-	DP_STATS_INC_PKT(sa_peer, rx.intra_bss, 1,
-			qdf_nbuf_len(nbuf));
-	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
-		FL("Intra-BSS forwarding not implemented"));
+	uint16_t da_idx;
+	uint16_t len;
+	struct dp_peer *da_peer;
+	struct dp_ast_entry *ast_entry;
+	qdf_nbuf_t nbuf_copy;
+
+	/* check if the destination peer is available in peer table
+	 * and also check if the source peer and destination peer
+	 * belong to the same vap and destination peer is not bss peer.
+	 */
+	if ((hal_rx_msdu_end_da_is_valid_get(rx_tlv_hdr) &&
+	   !hal_rx_msdu_end_da_is_mcbc_get(rx_tlv_hdr))) {
+		da_idx = hal_rx_msdu_end_da_idx_get(rx_tlv_hdr);
+
+		ast_entry = soc->ast_table[da_idx];
+		if (!ast_entry)
+			return false;
+
+		da_peer = ast_entry->peer;
+
+		if (!da_peer)
+			return false;
+
+		if (da_peer->vdev == sa_peer->vdev && !da_peer->bss_peer) {
+			memset(nbuf->cb, 0x0, sizeof(nbuf->cb));
+			len = qdf_nbuf_len(nbuf);
+			if (!dp_tx_send(sa_peer->vdev, nbuf)) {
+				DP_STATS_INC_PKT(sa_peer, rx.intra_bss, 1, len);
+				return true;
+			} else
+				return false;
+		}
+	}
+	/* if it is a broadcast pkt (eg: ARP) and it is not its own
+	 * source, then clone the pkt and send the cloned pkt for
+	 * intra BSS forwarding and original pkt up the network stack
+	 * Note: how do we handle multicast pkts. do we forward
+	 * all multicast pkts as is or let a higher layer module
+	 * like igmpsnoop decide whether to forward or not with
+	 * Mcast enhancement.
+	 */
+	else if (qdf_unlikely((hal_rx_msdu_end_da_is_mcbc_get(rx_tlv_hdr) &&
+		!sa_peer->bss_peer))) {
+		nbuf_copy = qdf_nbuf_copy(nbuf);
+		if (!nbuf_copy)
+			return false;
+		memset(nbuf_copy->cb, 0x0, sizeof(nbuf_copy->cb));
+		len = qdf_nbuf_len(nbuf_copy);
+		if (dp_tx_send(sa_peer->vdev, nbuf_copy))
+			qdf_nbuf_free(nbuf_copy);
+		else
+			DP_STATS_INC_PKT(sa_peer, rx.intra_bss, 1, len);
+	}
+	/* return false as we have to still send the original pkt
+	 * up the stack
+	 */
 	return false;
 }
 
@@ -426,7 +478,6 @@ QDF_STATUS dp_rx_filter_mesh_packets(struct dp_vdev *vdev, qdf_nbuf_t nbuf)
 
 #endif
 
-
 /**
  * dp_rx_process() - Brain of the Rx processing functionality
  *		     Called from the bottom half (tasklet/NET_RX_SOFTIRQ)
@@ -749,9 +800,10 @@ done:
 			dp_rx_wds_srcport_learn(soc, rx_tlv_hdr, peer, nbuf);
 
 			/* Intrabss-fwd */
-			if (peer &&
-				dp_rx_intrabss_fwd(soc, peer, rx_tlv_hdr, nbuf))
-				continue; /* Get next descriptor */
+			if (vdev->opmode != wlan_op_mode_sta)
+				if (dp_rx_intrabss_fwd(soc, peer, rx_tlv_hdr,
+									nbuf))
+					continue; /* Get next descriptor */
 
 			rx_bufs_used++;
 			DP_RX_LIST_APPEND(deliver_list_head,

+ 147 - 1
dp/wifi3.0/dp_types.h

@@ -56,6 +56,27 @@
 #define DP_QOS_TID 0x0f
 #define DP_IPV6_PRIORITY_SHIFT 20
 
+#if defined(CONFIG_MCL)
+#define MAX_PDEV_CNT 1
+#else
+#define MAX_PDEV_CNT 3
+#endif
+#define MAX_LINK_DESC_BANKS 8
+#define MAX_TXDESC_POOLS 4
+#define MAX_RXDESC_POOLS 4
+#define MAX_REO_DEST_RINGS 4
+#define MAX_TCL_DATA_RINGS 4
+#define DP_MAX_TX_RINGS 8
+#define DP_MAX_RX_RINGS 8
+#define MAX_IDLE_SCATTER_BUFS 16
+#define DP_MAX_IRQ_PER_CONTEXT 12
+#define DP_MAX_INTERRUPT_CONTEXTS 8
+#define DEFAULT_HW_PEER_ID 0xffff
+
+#define MAX_TX_HW_QUEUES 3
+
+#define DP_MAX_INTERRUPT_CONTEXTS 8
+
 struct dp_soc_cmn;
 struct dp_pdev;
 struct dp_vdev;
@@ -91,6 +112,7 @@ union dp_rx_desc_list_elem_t;
 #define DP_SW2HW_MACID(id) ((id) + 1)
 
 #define DP_HW2SW_MACID(id) ((id) > 0 ? ((id) - 1) : 0)
+#define DP_MAC_ADDR_LEN 6
 
 /**
  * enum dp_tx_frm_type
@@ -290,6 +312,124 @@ struct reo_desc_list_node {
 	struct dp_rx_tid rx_tid;
 };
 
+/* TODO: Proper comments have been added in the subsequesnt gerrit */
+/* packet info */
+struct dp_pkt_info {
+	uint32_t num; /*no of packets*/
+	uint32_t bytes; /* total no of bytes */
+};
+
+/* per pdev tx stats*/
+struct dp_tx_pdev_stats {
+
+	struct dp_pkt_info rcvd; /*total packets received for transmission */
+	struct {
+		/* Pkt Info for which completions were received */
+		struct dp_pkt_info comp_pkt;
+		uint32_t mcs_count[MAX_MCS + 1]; /* MCS Count */
+	} comp; /* Tx completions received*/
+
+	struct dp_pkt_info freed; /* Tx packets freed*/
+
+	struct dp_pkt_info processed; /* Tx packets processed*/
+	struct dp_pkt_info outstanding; /* Tx packets remaining for processing*/
+
+	struct {
+		struct dp_pkt_info dropped_pkt; /* Total packets dropped */
+		uint32_t desc_total;  /* total descriptors dropped */
+		uint32_t dma_map_error; /* Dropped due to Dma Error */
+		uint32_t ring_full;    /* dropped due to ring full */
+		uint32_t fw_discard;   /* Discarded bu firmware */
+		uint32_t fw_discard_retired; /* fw_discard_retired */
+		/* firmware_discard_untransmitted */
+		uint32_t firmware_discard_untransmitted;
+		uint32_t mpdu_age_out; /* mpdu_age_out */
+		uint32_t firmware_discard_reason1; /*firmware_discard_reason1*/
+		uint32_t firmware_discard_reason2; /*firmware_discard_reason2*/
+		uint32_t firmware_discard_reason3; /*firmware_discard_reason3*/
+	} dropped; /* Packets dropped on the Tx side */
+
+	struct {
+		struct dp_pkt_info sg_pkt; /* total scatter gather packets */
+		uint32_t dropped_host; /* SG packets dropped by host */
+		uint32_t dropped_target; /* SG packets dropped by target */
+	} sg; /* Scatter Gather packet info */
+
+	struct {
+		uint32_t num_seg;  /* No of segments in TSO packets */
+		struct dp_pkt_info tso_pkt; /* total no of TSO packets */
+		uint32_t dropped_host; /* TSO packets dropped by host */
+		uint32_t dropped_target; /* TSO packets dropped by target */
+	} tso; /* TSO packets info */
+
+	struct {
+		/* total no of multicast conversion packets */
+		struct dp_pkt_info mcast_pkt;
+		/* packets dropped due to map error */
+		uint32_t dropped_map_error;
+		/* packets dropped due to self Mac address */
+		uint32_t dropped_self_mac;
+		/* Packets dropped due to send fail */
+		uint32_t dropped_send_fail;
+		/* total unicast packets transmitted */
+		uint32_t ucast;
+	} mcast_en; /* Multicast Enhancement packets info */
+
+	/* Total packets passed Reinject handler */
+	struct dp_pkt_info reinject_pkts;
+	/*  Total packets passed to inspect handler */
+	struct dp_pkt_info inspect_pkts;
+	/* Total Raw packets */
+	struct dp_pkt_info raw_pkt;
+};
+
+/* Per pdev RX stats */
+struct dp_rx_pdev_stats {
+	struct dp_pkt_info rcvd_reo; /* packets received on the reo ring */
+	struct {
+		/* packets dropped because of no peer */
+		struct dp_pkt_info no_peer;
+		/* packets dropped because nsdu_done bit not set */
+		struct dp_pkt_info msdu_not_done;
+	} dropped; /* packets dropped on rx */
+	struct dp_pkt_info replenished; /* total packets replnished */
+	struct dp_pkt_info to_stack;    /* total packets sent up the stack */
+	struct dp_pkt_info intra_bss;   /* Intra BSS packets received */
+	struct dp_pkt_info wds;         /* WDS packets received */
+	struct dp_pkt_info desc;
+	struct dp_pkt_info buff;
+	struct dp_pkt_info raw;         /* Raw Pakets received */
+	struct {
+		uint32_t rxdma_unitialized; /* rxdma_unitialized errors */
+		uint32_t desc_alloc_fail; /* desc alloc failed errors */
+	} err;                          /* Rx errors */
+	uint32_t buf_freelist;         /* buffers added back in freelist */
+	uint32_t mcs_count[MAX_MCS + 1]; /* packets in different MCS rates */
+	uint32_t sgi_count[MAX_MCS + 1]; /* SGI count */
+	/*  Number of MSDUs with no MPDU level aggregation */
+	uint32_t non_ampdu_cnt;
+	/* Number of MSDUs part of AMSPU */
+	uint32_t ampdu_cnt;
+	/* Number of MSDUs with no MSDU level aggregation */
+	uint32_t non_amsdu_cnt;
+	/* Number of MSDUs part of AMSDU*/
+	uint32_t amsdu_cnt;
+	/* Packet count in spatiel Streams */
+	uint32_t nss[SS_COUNT];
+	/* Packet count in different Bandwidths */
+	uint32_t bw[SUPPORTED_BW];
+	/* reception type os packets */
+	uint32_t reception_type[SUPPORTED_RECEPTION_TYPES];
+};
+
+struct dp_ast_entry {
+	uint16_t ast_idx;
+	uint8_t mac_addr[DP_MAC_ADDR_LEN];
+	uint8_t next_hop;
+	struct dp_peer *peer;
+	TAILQ_ENTRY(dp_ast_entry) ast_entry_elem;
+};
+
 /* SOC level structure for data path */
 struct dp_soc {
 	/* Common base structure - Should be the first member */
@@ -502,6 +642,8 @@ struct dp_soc {
 	/* Enable processing of Tx completion status words */
 	bool process_tx_status;
 
+	struct dp_ast_entry *ast_table[WLAN_UMAC_PSOC_MAX_PEERS];
+
 #ifdef DP_INTR_POLL_BASED
 	/*interrupt timer*/
 	qdf_timer_t int_timer;
@@ -601,7 +743,6 @@ struct dp_pdev {
 
 struct dp_peer;
 
-#define DP_MAC_ADDR_LEN 6
 union dp_align_mac_addr {
 	uint8_t raw[DP_MAC_ADDR_LEN];
 	struct {
@@ -731,6 +872,8 @@ struct dp_peer {
 	/* VDEV to which this peer is associated */
 	struct dp_vdev *vdev;
 
+	struct dp_ast_entry self_ast_entry;
+
 	qdf_atomic_t ref_cnt;
 
 	/* TODO: See if multiple peer IDs are required in wifi3.0 */
@@ -785,5 +928,8 @@ struct dp_peer {
 	qdf_time_t last_deauth_rcvd;
 	/* Peer Stats */
 	struct cdp_peer_stats stats;
+
+	TAILQ_HEAD(, dp_ast_entry) ast_entry_list;
+	/* TBD */
 };
 #endif /* _DP_TYPES_H_ */

+ 75 - 0
dp/wifi3.0/hal_rx.h

@@ -1252,6 +1252,81 @@ QDF_STATUS hal_rx_mpdu_get_addr2(uint8_t *buf, uint8_t *mac_addr)
 	return QDF_STATUS_E_FAILURE;
 }
 
+#define HAL_RX_MSDU_END_DA_IDX_GET(_rx_msdu_end)	\
+	(_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_msdu_end,	\
+		RX_MSDU_END_13_DA_IDX_OFFSET)),		\
+		RX_MSDU_END_13_DA_IDX_MASK,		\
+		RX_MSDU_END_13_DA_IDX_LSB))
+
+ /**
+ * hal_rx_msdu_end_da_idx_get: API to get da_idx
+ * from rx_msdu_end TLV
+ *
+ * @ buf: pointer to the start of RX PKT TLV headers
+ * Return: da index
+ */
+static inline uint16_t
+hal_rx_msdu_end_da_idx_get(uint8_t *buf)
+{
+	struct rx_pkt_tlvs *pkt_tlvs = (struct rx_pkt_tlvs *)buf;
+	struct rx_msdu_end *msdu_end = &pkt_tlvs->msdu_end_tlv.rx_msdu_end;
+	uint16_t da_idx;
+
+	da_idx = HAL_RX_MSDU_END_DA_IDX_GET(msdu_end);
+
+	return da_idx;
+}
+
+#define HAL_RX_MSDU_END_DA_IS_VALID_GET(_rx_msdu_end)	\
+	(_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_msdu_end,	\
+		RX_MSDU_END_5_DA_IS_VALID_OFFSET)),	\
+		RX_MSDU_END_5_DA_IS_VALID_MASK,		\
+		RX_MSDU_END_5_DA_IS_VALID_LSB))
+
+ /**
+ * hal_rx_msdu_end_da_is_valid_get: API to check if da is valid
+ * from rx_msdu_end TLV
+ *
+ * @ buf: pointer to the start of RX PKT TLV headers
+ * Return: da_is_valid
+ */
+static inline uint8_t
+hal_rx_msdu_end_da_is_valid_get(uint8_t *buf)
+{
+	struct rx_pkt_tlvs *pkt_tlvs = (struct rx_pkt_tlvs *)buf;
+	struct rx_msdu_end *msdu_end = &pkt_tlvs->msdu_end_tlv.rx_msdu_end;
+	uint8_t da_is_valid;
+
+	da_is_valid = HAL_RX_MSDU_END_DA_IS_VALID_GET(msdu_end);
+
+	return da_is_valid;
+}
+
+#define HAL_RX_MSDU_END_DA_IS_MCBC_GET(_rx_msdu_end)	\
+	(_HAL_MS((*_OFFSET_TO_WORD_PTR(_rx_msdu_end,	\
+		RX_MSDU_END_5_DA_IS_MCBC_OFFSET)),	\
+		RX_MSDU_END_5_DA_IS_MCBC_MASK,		\
+		RX_MSDU_END_5_DA_IS_MCBC_LSB))
+
+ /**
+ * hal_rx_msdu_end_da_is_mcbc_get: API to check if pkt is MCBC
+ * from rx_msdu_end TLV
+ *
+ * @ buf: pointer to the start of RX PKT TLV headers
+ * Return: da_is_mcbc
+ */
+static inline uint8_t
+hal_rx_msdu_end_da_is_mcbc_get(uint8_t *buf)
+{
+	struct rx_pkt_tlvs *pkt_tlvs = (struct rx_pkt_tlvs *)buf;
+	struct rx_msdu_end *msdu_end = &pkt_tlvs->msdu_end_tlv.rx_msdu_end;
+	uint8_t da_is_mcbc;
+
+	da_is_mcbc = HAL_RX_MSDU_END_DA_IS_MCBC_GET(msdu_end);
+
+	return da_is_mcbc;
+}
+
 /*******************************************************************************
  * RX ERROR APIS
  ******************************************************************************/