--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -19,6 +19,13 @@ comment "CFG80211 needs to be enabled fo
 
 if MAC80211 != n
 
+config MAC80211_NSS_SUPPORT
+	bool "Enable NSS support for IPQ platform"
+	default n
+	---help---
+	This option enables support for NSS in boards
+	like AP148.
+
 config MAC80211_HAS_RC
 	bool
 
--- a/local-symbols
+++ b/local-symbols
@@ -31,6 +31,7 @@ LIB80211_CRYPT_CCMP=
 LIB80211_CRYPT_TKIP=
 LIB80211_DEBUG=
 MAC80211=
+MAC80211_NSS_SUPPORT=
 MAC80211_HAS_RC=
 MAC80211_RC_MINSTREL=
 MAC80211_RC_DEFAULT_MINSTREL=
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -36,6 +36,10 @@
 
 extern const struct cfg80211_ops mac80211_config_ops;
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+#include <nss_api_if.h>
+#endif
+
 struct ieee80211_local;
 struct ieee80211_mesh_fast_tx;
 
@@ -1118,6 +1122,12 @@ struct ieee80211_sub_if_data {
 	} debugfs;
 #endif
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+	struct nss_virt_if_handle *nssctx;
+	struct sk_buff_head rx_queue;
+	struct work_struct rx_work;
+#endif
+
 	/* must be last, dynamically sized area in this! */
 	struct ieee80211_vif vif;
 };
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -15,6 +15,7 @@
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
+#include <linux/module.h>
 #include <linux/kcov.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
@@ -27,6 +28,12 @@
 #include "wme.h"
 #include "rate.h"
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+bool nss_redirect = true;
+module_param(nss_redirect, bool, 0644);
+MODULE_PARM_DESC(nss_redirect, "module param to enable NSS Redirect; 1-enable, 0-disable");
+#endif
+
 /**
  * DOC: Interface list locking
  *
@@ -441,6 +448,64 @@ static int ieee80211_open(struct net_dev
 	return err;
 }
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+/* This callback is registered for nss redirect to receive packet exceptioned from nss in Rx path.
+ * When packet does not match any of the ecm rules is redirected back here.
+ */
+void receive_from_nss(struct net_device *dev, struct sk_buff *sk_buff, struct napi_struct *napi)
+{
+	struct net_device *netdev;
+	struct sk_buff *skb;
+	struct ieee80211_sub_if_data *sdata;
+
+	if (!dev) {
+		kfree(sk_buff);
+		return;
+	}
+
+	netdev = (struct net_device *)dev;
+	sdata = netdev_priv(netdev);
+	if (sdata->dev != dev) {
+		kfree(sk_buff);
+		return;
+	}
+	skb = (struct sk_buff *)sk_buff;
+	skb->dev = netdev;
+	skb->protocol = eth_type_trans(skb, netdev);
+	napi_gro_receive(napi, skb);
+}
+
+static int ieee80211_create_nss_virtif(struct ieee80211_sub_if_data *sdata, struct net_device *dev)
+{
+	if (sdata->nssctx != NULL) {
+		sdata_err(sdata, "Cannot create a NSS virtual interface. Already exists[n2h:%d, h2n:%d]!\n",
+			  sdata->nssctx->if_num_n2h, sdata->nssctx->if_num_h2n);
+		return 1;
+	}
+
+	sdata->nssctx = NULL;
+	if (nss_redirect) {
+		sdata->nssctx = nss_virt_if_create_sync(dev);
+		if (sdata->nssctx) {
+			sdata_info(sdata, "Created a NSS virtual interface\n");
+			nss_virt_if_register(sdata->nssctx, receive_from_nss, sdata->dev);
+		}
+		else
+			sdata_err(sdata, "Failed to create a NSS virtual interface\n");
+	}
+
+	return 0;
+}
+
+static void ieee80211_destroy_nss_virtif(struct ieee80211_sub_if_data *sdata)
+{
+	if (sdata->nssctx) {
+		nss_virt_if_destroy_sync(sdata->nssctx);
+		sdata_info(sdata, "Destroyed NSS virtual interface\n");
+	}
+}
+#endif
+
 static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down)
 {
 	struct ieee80211_local *local = sdata->local;
@@ -802,8 +867,24 @@ static void ieee80211_teardown_sdata(str
 	ieee80211_link_stop(&sdata->deflink);
 }
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+static int ieee80211_init(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	ieee80211_create_nss_virtif(sdata, dev);
+
+	return 0;
+}
+#endif
+
 static void ieee80211_uninit(struct net_device *dev)
 {
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	ieee80211_destroy_nss_virtif(sdata);
+#endif
 	ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
 }
 
@@ -831,6 +912,9 @@ static int ieee80211_netdev_setup_tc(str
 static const struct net_device_ops ieee80211_dataif_ops = {
 	.ndo_open		= ieee80211_open,
 	.ndo_stop		= ieee80211_stop,
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+	.ndo_init		= ieee80211_init,
+#endif
 	.ndo_uninit		= ieee80211_uninit,
 	.ndo_start_xmit		= ieee80211_subif_start_xmit,
 	.ndo_set_rx_mode	= ieee80211_set_multicast_list,
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -33,6 +33,60 @@
 #include "wme.h"
 #include "rate.h"
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+extern bool nss_redirect;
+
+#define case_rtn_string(val) case val: return #val
+
+static const char *nss_tx_status_str(nss_tx_status_t status)
+{
+	switch (status) {
+		case_rtn_string(NSS_TX_SUCCESS);
+		case_rtn_string(NSS_TX_FAILURE);
+		case_rtn_string(NSS_TX_FAILURE_QUEUE);
+		case_rtn_string(NSS_TX_FAILURE_NOT_READY);
+		case_rtn_string(NSS_TX_FAILURE_TOO_LARGE);
+		case_rtn_string(NSS_TX_FAILURE_TOO_SHORT);
+		case_rtn_string(NSS_TX_FAILURE_NOT_SUPPORTED);
+		case_rtn_string(NSS_TX_FAILURE_BAD_PARAM);
+		case_rtn_string(NSS_TX_FAILURE_NOT_ENABLED);
+		case_rtn_string(NSS_TX_FAILURE_SYNC_BAD_PARAM);
+		case_rtn_string(NSS_TX_FAILURE_SYNC_TIMEOUT);
+		case_rtn_string(NSS_TX_FAILURE_SYNC_FW_ERR);
+	default:
+		return "Unknown NSS TX status";
+	}
+}
+
+static void netif_rx_nss(struct ieee80211_rx_data *rx,
+			 struct sk_buff *skb)
+{
+	struct ieee80211_sub_if_data *sdata = rx->sdata;
+	int ret;
+
+	if (!sdata->nssctx)
+		goto out;
+
+	/* NSS expects ethernet header in skb data so resetting here */
+	skb_push(skb, ETH_HLEN);
+	ret = nss_virt_if_tx_buf(sdata->nssctx, skb);
+	if (ret) {
+		if (net_ratelimit() && ret != NSS_TX_FAILURE_TOO_SHORT) {
+			sdata_err(sdata, "NSS TX failed with error: %s\n",
+				  nss_tx_status_str(ret));
+		}
+		goto out;
+	}
+
+	return;
+out:
+	if (rx->list)
+		list_add_tail(&skb->list, rx->list);
+	else
+		netif_receive_skb(skb);
+}
+#endif
+
 /*
  * monitor mode reception
  *
@@ -2611,14 +2665,16 @@ static void ieee80211_deliver_skb_to_loc
 			ether_addr_copy(ehdr->h_dest, sdata->vif.addr);
 
 		/* deliver to local stack */
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+		if (likely(nss_redirect)) {
+			netif_rx_nss(rx, skb);
+		}
+#else
 		if (rx->list)
-#if LINUX_VERSION_IS_GEQ(4,19,0)
 			list_add_tail(&skb->list, rx->list);
-#else
-			__skb_queue_tail(rx->list, skb);
-#endif
 		else
 			netif_receive_skb(skb);
+#endif
 	}
 }
 
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -36,6 +36,11 @@
 #include "wme.h"
 #include "rate.h"
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+#include <net/ip.h>
+#include <net/dsfield.h>
+#endif
+
 /* misc utils */
 
 static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
@@ -1734,6 +1739,16 @@ static bool ieee80211_tx_frags(struct ie
 					return true;
 				}
 			} else {
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+				if (skb_queue_len(&local->pending[q]) >= 1000) {
+					spin_unlock_irqrestore(
+						&local->queue_stop_reason_lock,
+						flags);
+					ieee80211_purge_tx_queue(&local->hw,
+								 skbs);
+					return false;
+				}
+#endif
 
 				/*
 				 * Since queue is stopped, queue up frames for
@@ -4477,6 +4492,35 @@ static void ieee80211_mlo_multicast_tx(s
 	kfree_skb(skb);
 }
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+void ieee80211_xmit_nss_fixup(struct sk_buff *skb,
+			      struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	/* Packets from NSS does not have valid protocol, priority and other
+	 * network stack values. Derive required parameters (priority
+	 * and network_header) from payload for QoS header.
+	 * XXX: Here the assumption is that packet are in 802.3 format.
+	 * As of now priority is handled only for IPv4 and IPv6.
+	 */
+
+	if (sdata->nssctx && likely(!skb->protocol)) {
+		skb_set_network_header(skb, 14);
+		switch (((struct ethhdr *)skb->data)->h_proto) {
+		case htons(ETH_P_IP):
+			skb->priority = (ipv4_get_dsfield(ip_hdr(skb)) &
+					 0xfc) >> 5;
+			break;
+		case htons(ETH_P_IPV6):
+			skb->priority = (ipv6_get_dsfield(ipv6_hdr(skb)) &
+					 0xfc) >> 5;
+			break;
+		}
+	}
+}
+#endif
+
 /**
  * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs
  * @skb: packet to be sent
@@ -4490,6 +4534,10 @@ netdev_tx_t ieee80211_subif_start_xmit(s
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	const struct ethhdr *eth = (void *)skb->data;
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+	ieee80211_xmit_nss_fixup(skb, dev);
+#endif
+
 	if (likely(!is_multicast_ether_addr(eth->h_dest)))
 		goto normal;
 
@@ -4675,6 +4723,10 @@ netdev_tx_t ieee80211_subif_start_xmit_8
 	struct ieee80211_key *key;
 	struct sta_info *sta;
 
+#ifdef CPTCFG_MAC80211_NSS_SUPPORT
+	ieee80211_xmit_nss_fixup(skb, dev);
+#endif
+
 	if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
 		kfree_skb(skb);
 		return NETDEV_TX_OK;
