Эх сурвалжийг харах

qcacld-3.0: Implement DP component TX/RX path support fo SAP interface

Implement per packet TX/RX path support for SAP interface in DP
componentization model.

Change-Id: I788dcbe14fe038f50ff5b834b89391408dc5d16a
CRs-Fixed: 3173469
Karthik Kantamneni 3 жил өмнө
parent
commit
a5fbc73775

+ 786 - 0
components/dp/core/src/wlan_dp_softap_txrx.c

@@ -22,16 +22,802 @@
   *
   */
 
+#include <wlan_dp_priv.h>
+#include <wlan_dp_main.h>
 #include <wlan_dp_txrx.h>
+#include "wlan_dp_public_struct.h"
 #include <qdf_types.h>
+#include <cdp_txrx_cmn.h>
+#include <cdp_txrx_peer_ops.h>
+#include <cdp_txrx_misc.h>
+#include <cdp_txrx_flow_ctrl_v2.h>
+#include "dp_txrx.h"
+#include "nan_public_structs.h"
+#include "nan_ucfg_api.h"
+#include <wlan_cm_ucfg_api.h>
+#include <enet.h>
+#include <cds_utils.h>
+#include <wlan_dp_bus_bandwidth.h>
+#include <wlan_tdls_ucfg_api.h>
+#include <qdf_trace.h>
 #include <qdf_nbuf.h>
 
+/* Preprocessor definitions and constants */
+#undef QCA_DP_SAP_DUMP_SK_BUFF
+
+/* Type declarations */
+
+/* Function definitions and documenation */
+#ifdef QCA_DP_SAP_DUMP_SK_BUFF
+/**
+ * dp_softap_dump_nbuf() - Dump an nbuf
+ * @nbuf: nbuf to dump
+ *
+ * Return: None
+ */
+static void dp_softap_dump_nbuf(qdf_nbuf_t nbuf)
+{
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+		  "%s: head = %pK ", __func__, nbuf->head);
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
+		  "%s: tail = %pK ", __func__, nbuf->tail);
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+		  "%s: end = %pK ", __func__, nbuf->end);
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+		  "%s: len = %d ", __func__, nbuf->len);
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+		  "%s: data_len = %d ", __func__, nbuf->data_len);
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+		  "%s: mac_len = %d", __func__, nbuf->mac_len);
+
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+		  "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ", nbuf->data[0],
+		  nbuf->data[1], nbuf->data[2], nbuf->data[3], nbuf->data[4],
+		  nbuf->data[5], nbuf->data[6], nbuf->data[7]);
+	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+		  "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", nbuf->data[8],
+		  nbuf->data[9], nbuf->data[10], nbuf->data[11], nbuf->data[12],
+		  nbuf->data[13], nbuf->data[14], nbuf->data[15]);
+}
+#else
+static inline void dp_softap_dump_nbuf(qdf_nbuf_t nbuf)
+{
+}
+#endif
+
+#define IEEE8021X_AUTH_TYPE_EAP 0
+#define EAP_CODE_OFFSET 18
+#define EAP_CODE_FAILURE 4
+
+/* Wait EAP Failure frame timeout in (MS) */
+#define EAP_FRM_TIME_OUT 80
+
+/**
+ * dp_softap_inspect_tx_eap_pkt() - Inspect eap pkt tx/tx-completion
+ * @dp_intf: pointer to DP interface
+ * @nbuf: pointer to n/w buffer
+ * @tx_comp: tx sending or tx completion
+ *
+ * Inspect the EAP-Failure pkt tx sending and tx completion.
+ *
+ * Return: void
+ */
+static void dp_softap_inspect_tx_eap_pkt(struct wlan_dp_intf *dp_intf,
+					 qdf_nbuf_t nbuf,
+					 bool tx_comp)
+{
+	struct qdf_mac_addr *mac_addr;
+	uint8_t *data;
+	uint8_t auth_type, eap_code;
+	struct wlan_objmgr_peer *peer;
+	struct wlan_dp_sta_info *sta_info;
+
+	if (qdf_likely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) !=
+	    QDF_NBUF_CB_PACKET_TYPE_EAPOL) ||
+	    qdf_nbuf_len(nbuf) < (EAP_CODE_OFFSET + 1))
+		return;
+
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() ||
+	    cds_is_load_or_unload_in_progress()) {
+		dp_debug("Recovery/(Un)load in Progress. Ignore!!!");
+		return;
+	}
+
+	if (dp_intf->device_mode != QDF_P2P_GO_MODE)
+		return;
+
+	if (dp_intf->bss_state != BSS_INTF_START) {
+		dp_debug("BSS intf state is not START");
+		return;
+	}
+	data = qdf_nbuf_data(nbuf);
+	auth_type = *(uint8_t *)(data + EAPOL_PACKET_TYPE_OFFSET);
+	if (auth_type != IEEE8021X_AUTH_TYPE_EAP)
+		return;
+	eap_code = *(uint8_t *)(data + EAP_CODE_OFFSET);
+	if (eap_code != EAP_CODE_FAILURE)
+		return;
+	mac_addr = (struct qdf_mac_addr *)qdf_nbuf_data(nbuf) +
+		QDF_NBUF_DEST_MAC_OFFSET;
+
+	peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc,
+					   mac_addr->bytes,
+					   WLAN_DP_ID);
+	if (!peer) {
+		dp_err("Peer object not found");
+		return;
+	}
+	sta_info = dp_get_peer_priv_obj(peer);
+	if (!sta_info) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
+		return;
+	}
+
+	if (tx_comp) {
+		dp_info("eap_failure frm tx done" QDF_MAC_ADDR_FMT,
+			QDF_MAC_ADDR_REF(mac_addr->bytes));
+		qdf_atomic_clear_bit(DP_PENDING_TYPE_EAP_FAILURE,
+				     &sta_info->pending_eap_frm_type);
+		qdf_event_set(&dp_intf->qdf_sta_eap_frm_done_event);
+	} else {
+		dp_info("eap_failure frm tx pending" QDF_MAC_ADDR_FMT,
+			QDF_MAC_ADDR_REF(mac_addr->bytes));
+		qdf_event_reset(&dp_intf->qdf_sta_eap_frm_done_event);
+		qdf_atomic_set_bit(DP_PENDING_TYPE_EAP_FAILURE,
+				   &sta_info->pending_eap_frm_type);
+		QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 1;
+	}
+	wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
+}
+
+void dp_softap_check_wait_for_tx_eap_pkt(struct wlan_dp_intf *dp_intf,
+					 struct qdf_mac_addr *mac_addr)
+{
+	struct wlan_objmgr_peer *peer;
+	struct wlan_dp_sta_info *sta_info;
+	QDF_STATUS qdf_status;
+
+	if (dp_intf->device_mode != QDF_P2P_GO_MODE)
+		return;
+
+	peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc,
+					   mac_addr->bytes,
+					   WLAN_DP_ID);
+	if (!peer) {
+		dp_err("Peer object not found");
+		return;
+	}
+
+	sta_info = dp_get_peer_priv_obj(peer);
+	if (qdf_atomic_test_bit(DP_PENDING_TYPE_EAP_FAILURE,
+				&sta_info->pending_eap_frm_type)) {
+		dp_info("eap_failure frm pending" QDF_MAC_ADDR_FMT,
+			QDF_MAC_ADDR_REF(mac_addr->bytes));
+		qdf_status = qdf_wait_for_event_completion(
+				&dp_intf->qdf_sta_eap_frm_done_event,
+				EAP_FRM_TIME_OUT);
+		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
+			dp_debug("eap_failure tx timeout");
+	}
+	wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
+}
+
+#ifdef SAP_DHCP_FW_IND
+/**
+ * dp_post_dhcp_ind() - Send DHCP START/STOP indication to FW
+ * @dp_intf: pointer to DP interface
+ * @sta_id: peer station ID
+ * @type: WMA message type
+ *
+ * Return: error number
+ */
+int dp_post_dhcp_ind(struct wlan_dp_intf *dp_intf, uint8_t *mac_addr,
+		     bool dhcp_start)
+{
+	struct dp_dhcp_ind msg;
+	struct wlan_dp_psoc_sb_ops *sb_ops = &dp_intf->dp_ctx->sb_ops;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	dp_info("Post DHCP indication,sta_mac=" QDF_MAC_ADDR_FMT
+		 " ,  start=%u", QDF_MAC_ADDR_REF(mac_addr), dhcp_start);
+
+	if (!dp_intf) {
+		dp_err("NULL DP interface");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	msg.dhcp_start = dhcp_start;
+	msg.device_mode = dp_intf->device_mode;
+	qdf_mem_copy(msg.intf_mac_addr.bytes,
+		     dp_intf->mac_addr.bytes,
+		     QDF_MAC_ADDR_SIZE);
+	qdf_mem_copy(msg.peer_mac_addr.bytes,
+		     mac_addr,
+		     QDF_MAC_ADDR_SIZE);
+
+	status = sb_ops->dp_send_dhcp_ind(dp_intf->intf_id, &msg);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		dp_err("Post DHCP Ind MSG fail");
+		return QDF_STATUS_E_FAULT;
+	}
+
+	return 0;
+}
+
+#define DHCP_CLIENT_MAC_ADDR_OFFSET 0x46
+
+/**
+ * dp_softap_notify_dhcp_ind() - Notify SAP for DHCP indication for tx desc
+ * @context: pointer to DP interface context
+ * @netbuf: pointer to OS packet (sk_buff)
+ *
+ * Return: None
+ */
+static void dp_softap_notify_dhcp_ind(void *intf_context, qdf_nbuf_t nbuf)
+{
+	uint8_t *dest_mac_addr;
+	struct wlan_dp_intf *dp_intf = intf_context;
+
+	if (is_dp_intf_valid(dp_intf))
+		return;
+
+	dest_mac_addr = qdf_nbuf_data(nbuf) + DHCP_CLIENT_MAC_ADDR_OFFSET;
+
+	/*stop dhcp indication*/
+	dp_post_dhcp_ind(dp_intf, dest_mac_addr, false);
+}
+
+int dp_softap_inspect_dhcp_packet(struct wlan_dp_intf *dp_intf,
+				  qdf_nbuf_t nbuf,
+				  enum qdf_proto_dir dir)
+{
+	enum qdf_proto_subtype subtype = QDF_PROTO_INVALID;
+	struct wlan_objmgr_peer *peer;
+	struct wlan_dp_sta_info *sta_info;
+	int errno = 0;
+	struct qdf_mac_addr *src_mac;
+
+	if (((dp_intf->device_mode == QDF_SAP_MODE) ||
+	     (dp_intf->device_mode == QDF_P2P_GO_MODE)) &&
+	    ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP ==
+				QDF_NBUF_CB_GET_PACKET_TYPE(nbuf)) ||
+	     (dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(nbuf) == true))) {
+		src_mac = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) +
+						  DHCP_CLIENT_MAC_ADDR_OFFSET);
+
+		subtype = qdf_nbuf_get_dhcp_subtype(nbuf);
+
+		peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc,
+						   src_mac->bytes,
+						   WLAN_DP_ID);
+		if (!peer) {
+			dp_err("Peer object not found");
+			return QDF_STATUS_E_INVAL;
+		}
+
+		sta_info = dp_get_peer_priv_obj(peer);
+		if (!sta_info) {
+			dp_err("Station not found");
+			wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
+			return QDF_STATUS_E_INVAL;
+		}
+
+		dp_info("ENTER: type=%d, phase=%d, nego_status=%d",
+			subtype,
+			sta_info->dhcp_phase,
+			sta_info->dhcp_nego_status);
+
+		switch (subtype) {
+		case QDF_PROTO_DHCP_DISCOVER:
+			if (dir != QDF_RX)
+				break;
+			if (sta_info->dhcp_nego_status == DHCP_NEGO_STOP)
+				errno =	dp_post_dhcp_ind(dp_intf,
+						sta_info->sta_mac.bytes,
+						true);
+			sta_info->dhcp_phase = DHCP_PHASE_DISCOVER;
+			sta_info->dhcp_nego_status = DHCP_NEGO_IN_PROGRESS;
+			break;
+		case QDF_PROTO_DHCP_OFFER:
+			sta_info->dhcp_phase = DHCP_PHASE_OFFER;
+			break;
+		case QDF_PROTO_DHCP_REQUEST:
+			if (dir != QDF_RX)
+				break;
+			if (sta_info->dhcp_nego_status == DHCP_NEGO_STOP)
+				errno = dp_post_dhcp_ind(
+						dp_intf,
+						sta_info->sta_mac.bytes,
+						true);
+			sta_info->dhcp_nego_status = DHCP_NEGO_IN_PROGRESS;
+			/* fallthrough */
+		case QDF_PROTO_DHCP_DECLINE:
+			if (dir == QDF_RX)
+				sta_info->dhcp_phase = DHCP_PHASE_REQUEST;
+			break;
+		case QDF_PROTO_DHCP_ACK:
+		case QDF_PROTO_DHCP_NACK:
+			sta_info->dhcp_phase = DHCP_PHASE_ACK;
+			if (sta_info->dhcp_nego_status ==
+				DHCP_NEGO_IN_PROGRESS) {
+				dp_debug("Setting NOTIFY_COMP Flag");
+				QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 1;
+			}
+			sta_info->dhcp_nego_status = DHCP_NEGO_STOP;
+			break;
+		default:
+			break;
+		}
+
+		wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID);
+		dp_info("EXIT: phase=%d, nego_status=%d",
+			sta_info->dhcp_phase,
+			sta_info->dhcp_nego_status);
+	}
+
+	return errno;
+}
+#else
+static void dp_softap_notify_dhcp_ind(void *context, qdf_nbuf_t nbuf)
+{
+}
+#endif /* SAP_DHCP_FW_IND */
+
+#if defined(IPA_OFFLOAD)
+static
+qdf_nbuf_t dp_sap_nbuf_orphan(struct wlan_dp_intf *dp_intf,
+			      qdf_nbuf_t nbuf)
+{
+	if (!qdf_nbuf_ipa_owned_get(nbuf)) {
+		nbuf = dp_nbuf_orphan(dp_intf, nbuf);
+	} else {
+		/*
+		 * Clear the IPA ownership after check it to avoid ipa_free_skb
+		 * is called when Tx completed for intra-BSS Tx packets
+		 */
+		qdf_nbuf_ipa_owned_clear(nbuf);
+	}
+	return nbuf;
+}
+#else
+static inline
+qdf_nbuf_t dp_sap_nbuf_orphan(struct wlan_dp_intf *dp_intf,
+			      qdf_nbuf_t nbuf)
+{
+	return dp_nbuf_orphan(dp_intf, nbuf);
+}
+#endif /* IPA_OFFLOAD */
+
+#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
+static
+void dp_softap_get_tx_resource(struct wlan_dp_intf *dp_intf,
+			       qdf_nbuf_t nbuf)
+{
+	if (QDF_NBUF_CB_GET_IS_BCAST(nbuf) || QDF_NBUF_CB_GET_IS_MCAST(nbuf))
+		dp_get_tx_resource(dp_intf, &dp_intf->mac_addr);
+	else
+		dp_get_tx_resource(dp_intf,
+				   (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) +
+							   QDF_NBUF_DEST_MAC_OFFSET));
+}
+#else
+#define dp_softap_get_tx_resource(dp_intf, nbuf)
+#endif
+
+#ifdef FEATURE_WDS
+void
+dp_wds_replace_peer_mac(void *soc, struct wlan_dp_intf *dp_intf,
+			uint8_t *mac_addr)
+{
+	struct cdp_ast_entry_info ast_entry_info = {0};
+	cdp_config_param_type val;
+	QDF_STATUS status;
+
+	if (!cdp_find_peer_exist(soc, OL_TXRX_PDEV_ID, mac_addr)) {
+		status = cdp_txrx_get_vdev_param(soc, dp_intf->intf_id,
+						 CDP_ENABLE_WDS, &val);
+		if (!QDF_IS_STATUS_SUCCESS(status))
+			return;
+
+		if (!val.cdp_vdev_param_wds)
+			return;
+
+		if (!cdp_peer_get_ast_info_by_soc(soc,  mac_addr,
+						  &ast_entry_info))
+			return;
+
+		qdf_mem_copy(mac_addr, ast_entry_info.peer_mac_addr,
+			     QDF_MAC_ADDR_SIZE);
+	}
+}
+#else
+static inline
+void dp_wds_replace_peer_mac(void *soc, struct wlan_dp_intf *dp_intf,
+			     uint8_t *mac_addr)
+{
+}
+#endif /* FEATURE_WDS*/
+
+static QDF_STATUS dp_softap_validate_peer_state(struct wlan_dp_intf *dp_intf,
+						qdf_nbuf_t nbuf)
+{
+	struct qdf_mac_addr *dest_mac_addr, *mac_addr;
+	static struct qdf_mac_addr bcast_mac_addr = QDF_MAC_ADDR_BCAST_INIT;
+
+	dest_mac_addr = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) +
+						QDF_NBUF_DEST_MAC_OFFSET);
+
+	if (QDF_NBUF_CB_GET_IS_MCAST(nbuf))
+		mac_addr = &bcast_mac_addr;
+	else
+		mac_addr = dest_mac_addr;
+
+	if (!QDF_NBUF_CB_GET_IS_BCAST(nbuf) &&
+	    !QDF_NBUF_CB_GET_IS_MCAST(nbuf)) {
+		/* for a unicast frame */
+		enum ol_txrx_peer_state peer_state;
+		void *soc = cds_get_context(QDF_MODULE_ID_SOC);
+
+		QDF_BUG(soc);
+		dp_wds_replace_peer_mac(soc, dp_intf, mac_addr->bytes);
+		peer_state = cdp_peer_state_get(soc, dp_intf->intf_id,
+						mac_addr->bytes);
+
+		if (peer_state == OL_TXRX_PEER_STATE_INVALID) {
+			dp_debug_rl("Failed to find right station");
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		if (peer_state != OL_TXRX_PEER_STATE_CONN &&
+		    peer_state != OL_TXRX_PEER_STATE_AUTH) {
+			dp_debug_rl("Station not connected yet");
+			return QDF_STATUS_E_FAILURE;
+		}
+
+		if (peer_state == OL_TXRX_PEER_STATE_CONN) {
+			if (qdf_ntohs(qdf_nbuf_get_protocol(nbuf)) !=
+			    ETHERTYPE_PAE) {
+				dp_debug_rl("NON-EAPOL packet in non-Authenticated state");
+				return QDF_STATUS_E_FAILURE;
+			}
+		}
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+static
+QDF_STATUS dp_softap_validate_driver_state(struct wlan_dp_intf *dp_intf)
+{
+	if (qdf_unlikely(cds_is_driver_transitioning())) {
+		dp_err_rl("driver is transitioning, drop pkt");
+		return QDF_STATUS_E_ABORTED;
+	}
+
+	/*
+	 * below unified mask will take care of SAP TX block
+	 * WLAN suspend state check
+	 * BSS start check and
+	 * DP TX function register check
+	 */
+	if (qdf_unlikely(dp_intf->sap_tx_block_mask)) {
+		dp_err_rl("Softap TX blocked mask: %u",
+			  dp_intf->sap_tx_block_mask);
+		return QDF_STATUS_E_ABORTED;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void dp_softap_config_tx_pkt_tracing(struct wlan_dp_intf *dp_intf,
+					    qdf_nbuf_t nbuf)
+{
+	if (dp_is_current_high_throughput(dp_intf->dp_ctx))
+		return;
+
+	QDF_NBUF_CB_TX_PACKET_TRACK(nbuf) = QDF_NBUF_TX_PKT_DATA_TRACK;
+	QDF_NBUF_UPDATE_TX_PKT_COUNT(nbuf, QDF_NBUF_TX_PKT_DP);
+	qdf_dp_trace_set_track(nbuf, QDF_TX);
+	DPTRACE(qdf_dp_trace(nbuf, QDF_DP_TRACE_TX_PACKET_PTR_RECORD,
+			     QDF_TRACE_DEFAULT_PDEV_ID,
+			     qdf_nbuf_data_addr(nbuf),
+			     sizeof(qdf_nbuf_data(nbuf)),
+			     QDF_TX));
+}
+
+/**
+ * dp_softap_start_xmit() - Transmit a frame
+ * @nbuf: pointer to Network buffer
+ * @dp_intf: DP interface
+ *
+ * Return: QDF_STATUS_SUCCESS on successful transmission
+ */
 QDF_STATUS dp_softap_start_xmit(qdf_nbuf_t nbuf, struct wlan_dp_intf *dp_intf)
 {
+	struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx;
+	struct qdf_mac_addr *dest_mac_addr;
+	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
+	uint32_t num_seg;
+	struct dp_tx_rx_stats *stats = &dp_intf->dp_stats.tx_rx_stats;
+	int cpu = qdf_get_smp_processor_id();
+
+	dest_mac_addr = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) +
+						QDF_NBUF_DEST_MAC_OFFSET);
+	++stats->per_cpu[cpu].tx_called;
+	stats->cont_txtimeout_cnt = 0;
+
+	if (QDF_IS_STATUS_ERROR(dp_softap_validate_driver_state(dp_intf)))
+		goto drop_pkt;
+
+	wlan_dp_pkt_add_timestamp(dp_intf, QDF_PKT_TX_DRIVER_ENTRY, nbuf);
+
+	if (QDF_IS_STATUS_ERROR(dp_softap_validate_peer_state(dp_intf, nbuf)))
+		goto drop_pkt;
+
+	dp_softap_get_tx_resource(dp_intf, nbuf);
+
+	nbuf = dp_sap_nbuf_orphan(dp_intf, nbuf);
+	if (!nbuf)
+		goto drop_pkt_accounting;
+
+	qdf_net_buf_debug_acquire_skb(nbuf, __FILE__, __LINE__);
+
+	QDF_NET_DEV_STATS_TX_BYTES(&dp_intf->stats) += qdf_nbuf_len(nbuf);
+
+	if (qdf_nbuf_is_tso(nbuf)) {
+		num_seg = qdf_nbuf_get_tso_num_seg(nbuf);
+		QDF_NET_DEV_STATS_TX_PKTS(&dp_intf->stats) += num_seg;
+	} else {
+		QDF_NET_DEV_STATS_INC_TX_PKTS(&dp_intf->stats);
+		dp_ctx->no_tx_offload_pkt_cnt++;
+	}
+
+	QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 0;
+
+	if (qdf_unlikely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) ==
+			 QDF_NBUF_CB_PACKET_TYPE_DHCP))
+		dp_softap_inspect_dhcp_packet(dp_intf, nbuf, QDF_TX);
+
+	if (qdf_unlikely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) ==
+			 QDF_NBUF_CB_PACKET_TYPE_EAPOL)) {
+		dp_softap_inspect_tx_eap_pkt(dp_intf, nbuf, false);
+		dp_event_eapol_log(nbuf, QDF_TX);
+	}
+
+	dp_softap_config_tx_pkt_tracing(dp_intf, nbuf);
+
+	/* check whether need to linearize skb, like non-linear udp data */
+	if (dp_nbuf_nontso_linearize(nbuf) != QDF_STATUS_SUCCESS) {
+		dp_debug_rl("nbuf %pK linearize failed. drop the pkt", nbuf);
+		goto drop_pkt_and_release_skb;
+	}
+
+	if (dp_intf->tx_fn(soc, dp_intf->intf_id, nbuf)) {
+		dp_debug("Failed to send packet to txrx for sta: "
+			 QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(dest_mac_addr->bytes));
+		goto drop_pkt_and_release_skb;
+	}
+
 	return QDF_STATUS_SUCCESS;
+
+drop_pkt_and_release_skb:
+	qdf_net_buf_debug_release_skb(nbuf);
+drop_pkt:
+	qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID,
+			      QDF_DP_TRACE_DROP_PACKET_RECORD, 0,
+			      QDF_TX);
+	qdf_nbuf_kfree(nbuf);
+drop_pkt_accounting:
+	QDF_NET_DEV_STATS_INC_TX_DROPEED(&dp_intf->stats);
+
+	return QDF_STATUS_E_FAILURE;
 }
 
+void dp_softap_tx_timeout(struct wlan_dp_intf *dp_intf)
+{
+	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
+
+	cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC));
+
+	++dp_intf->dp_stats.tx_rx_stats.tx_timeout_cnt;
+	++dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt;
+
+	if (dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt >
+	    DP_TX_STALL_THRESHOLD) {
+		dp_err("Detected data stall due to continuous TX timeouts");
+		dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt = 0;
+
+		if (cdp_cfg_get(soc, cfg_dp_enable_data_stall))
+			cdp_post_data_stall_event(soc,
+					  DATA_STALL_LOG_INDICATOR_HOST_DRIVER,
+					  DATA_STALL_LOG_HOST_SOFTAP_TX_TIMEOUT,
+					  OL_TXRX_PDEV_ID, 0xFF,
+					  DATA_STALL_LOG_RECOVERY_TRIGGER_PDR);
+	}
+}
+
+/**
+ * dp_softap_notify_tx_compl_cbk() - callback to notify tx completion
+ * @nbuf: pointer to n/w buffer
+ * @dp_intf: pointer to DP interface
+ * @flags: tx status flag
+ *
+ * Return: None
+ */
+void dp_softap_notify_tx_compl_cbk(qdf_nbuf_t nbuf,
+				   void *context, uint16_t flag)
+{
+	int errno;
+	struct wlan_dp_intf *dp_intf = context;
+
+	errno = is_dp_intf_valid(dp_intf);
+	if (errno)
+		return;
+
+	if (QDF_NBUF_CB_PACKET_TYPE_DHCP == QDF_NBUF_CB_GET_PACKET_TYPE(nbuf)) {
+		dp_debug("sending DHCP indication");
+		dp_softap_notify_dhcp_ind(context, nbuf);
+	} else if (QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) ==
+						QDF_NBUF_CB_PACKET_TYPE_EAPOL) {
+		dp_softap_inspect_tx_eap_pkt(dp_intf, nbuf, true);
+	}
+}
+
+#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS
+static inline
+void dp_softap_tsf_timestamp_rx(struct wlan_dp_psoc_context *dp_ctx,
+				qdf_nbuf_t netbuf)
+{
+	dp_ctx->dp_ops.dp_tsf_timestamp_rx(dp_ctx->dp_ops.callback_ctx,
+					   netbuf);
+}
+#else
+static inline
+void dp_softap_tsf_timestamp_rx(struct wlan_dp_psoc_context *dp_ctx,
+				qdf_nbuf_t netbuf)
+{
+}
+#endif
+
+#ifdef WLAN_FEATURE_11BE_MLO
+static inline bool dp_nbuf_dst_addr_is_mld_addr(struct wlan_dp_intf *dp_intf,
+						qdf_nbuf_t nbuf)
+{
+	struct qdf_mac_addr *mld_addr;
+
+	mld_addr = (struct qdf_mac_addr *)
+		wlan_vdev_mlme_get_mldaddr(dp_intf->vdev);
+
+	if (!qdf_is_macaddr_zero(mld_addr) &&
+	    !qdf_mem_cmp(mld_addr->bytes,
+			 (qdf_nbuf_data(nbuf) +
+			  QDF_NBUF_DEST_MAC_OFFSET),
+			 QDF_MAC_ADDR_SIZE))
+		return true;
+
+	return false;
+}
+#else
+static inline bool dp_nbuf_dst_addr_is_mld_addr(struct wlan_dp_intf *dp_intf,
+						qdf_nbuf_t nbuf)
+{
+	return false;
+}
+#endif
+
 QDF_STATUS dp_softap_rx_packet_cbk(void *intf_ctx, qdf_nbuf_t rx_buf)
 {
+	struct wlan_dp_intf *dp_intf = NULL;
+	QDF_STATUS qdf_status;
+	unsigned int cpu_index;
+	qdf_nbuf_t nbuf = NULL;
+	qdf_nbuf_t next = NULL;
+	struct wlan_dp_psoc_context *dp_ctx = NULL;
+	bool is_eapol = false;
+	struct dp_tx_rx_stats *stats;
+
+	/* Sanity check on inputs */
+	if (unlikely((!intf_ctx) || (!rx_buf))) {
+		dp_err("Null params being passed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	dp_intf = (struct wlan_dp_intf *)intf_ctx;
+	dp_ctx = dp_intf->dp_ctx;
+
+	stats = &dp_intf->dp_stats.tx_rx_stats;
+	/* walk the chain until all are processed */
+	next = rx_buf;
+
+	while (next) {
+		nbuf = next;
+		next = qdf_nbuf_next(nbuf);
+		qdf_nbuf_set_next(nbuf, NULL);
+
+		dp_softap_dump_nbuf(nbuf);
+
+		qdf_nbuf_set_dev(nbuf, dp_intf->dev);
+
+		cpu_index = qdf_get_cpu();
+		++stats->per_cpu[cpu_index].rx_packets;
+		QDF_NET_DEV_STATS_INC_RX_PKTS(&dp_intf->stats);
+		/* count aggregated RX frame into stats */
+		QDF_NET_DEV_STATS_RX_PKTS(&dp_intf->stats) +=
+			qdf_nbuf_get_gso_segs(nbuf);
+		QDF_NET_DEV_STATS_RX_BYTES(&dp_intf->stats) +=
+			qdf_nbuf_len(nbuf);
+
+		dp_softap_inspect_dhcp_packet(dp_intf, nbuf, QDF_RX);
+
+		if (qdf_nbuf_is_ipv4_eapol_pkt(nbuf))
+			is_eapol = true;
+
+		if (qdf_unlikely(is_eapol &&
+		    !(!qdf_mem_cmp(dp_intf->mac_addr.bytes,
+				   qdf_nbuf_data(nbuf) +
+				   QDF_NBUF_DEST_MAC_OFFSET,
+				   QDF_MAC_ADDR_SIZE) ||
+		    dp_nbuf_dst_addr_is_mld_addr(dp_intf, nbuf)))) {
+			qdf_nbuf_free(nbuf);
+			continue;
+		}
+
+		wlan_dp_pkt_add_timestamp(dp_intf,
+					  QDF_PKT_RX_DRIVER_EXIT, nbuf);
+
+		dp_event_eapol_log(nbuf, QDF_RX);
+		qdf_dp_trace_log_pkt(dp_intf->intf_id,
+				     nbuf, QDF_RX, QDF_TRACE_DEFAULT_PDEV_ID);
+		DPTRACE(qdf_dp_trace(nbuf,
+				     QDF_DP_TRACE_RX_PACKET_PTR_RECORD,
+				     QDF_TRACE_DEFAULT_PDEV_ID,
+				     qdf_nbuf_data_addr(nbuf),
+				     sizeof(qdf_nbuf_data(nbuf)), QDF_RX));
+		DPTRACE(qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID,
+					      QDF_DP_TRACE_RX_PACKET_RECORD,
+					      0, QDF_RX));
+
+		if (dp_rx_pkt_tracepoints_enabled())
+			qdf_trace_dp_packet(nbuf, QDF_RX, NULL, 0);
+
+		qdf_nbuf_set_protocol_eth_tye_trans(nbuf);
+
+		/* hold configurable wakelock for unicast traffic */
+		if (!dp_is_current_high_throughput(dp_ctx) &&
+		    dp_ctx->dp_cfg.rx_wakelock_timeout &&
+		    !qdf_nbuf_pkt_type_is_mcast(nbuf) &&
+		    !qdf_nbuf_pkt_type_is_bcast(nbuf)) {
+			cds_host_diag_log_work(&dp_ctx->rx_wake_lock,
+					dp_ctx->dp_cfg.rx_wakelock_timeout,
+					WIFI_POWER_EVENT_WAKELOCK_HOLD_RX);
+			qdf_wake_lock_timeout_acquire(&dp_ctx->rx_wake_lock,
+					dp_ctx->dp_cfg.rx_wakelock_timeout);
+		}
+
+		/* Remove SKB from internal tracking table before submitting
+		 * it to stack
+		 */
+		qdf_net_buf_debug_release_skb(nbuf);
+
+		dp_softap_tsf_timestamp_rx(dp_ctx, nbuf);
+
+		if (is_eapol && SEND_EAPOL_OVER_NL) {
+			if (dp_ctx->dp_ops.dp_send_rx_pkt_over_nl(dp_intf->dev,
+					(u8 *)&dp_intf->conn_info.peer_macaddr,
+								  nbuf, false))
+				qdf_status = QDF_STATUS_SUCCESS;
+			else
+				qdf_status = QDF_STATUS_E_INVAL;
+			qdf_nbuf_dev_kfree(nbuf);
+		} else {
+			qdf_status = wlan_dp_rx_deliver_to_stack(dp_intf, nbuf);
+		}
+
+		if (QDF_IS_STATUS_SUCCESS(qdf_status))
+			++stats->per_cpu[cpu_index].rx_delivered;
+		else
+			++stats->per_cpu[cpu_index].rx_refused;
+	}
+
 	return QDF_STATUS_SUCCESS;
 }