[qca-nss-drv] Add support for async messaging in virt_if

Add support for asynchronous messaging in virt_if and
dynamic_interface.

CRs-Fixed: 853868
Change-Id: I06c0dc74d8fce74cab50d565560590351759a8d3
Signed-off-by: Sundarajan Srinivasan <sundaraj@codeaurora.org>
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index a6ef7e2..d1b52eb 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -85,7 +85,6 @@
 #define NSS_MAX_VIRTUAL_INTERFACES 16
 #define NSS_MAX_TUNNEL_INTERFACES 4
 #define NSS_MAX_SPECIAL_INTERFACES 30
-#define NSS_MAX_DYNAMIC_INTERFACES 64
 #define NSS_MAX_WIFI_RADIO_INTERFACES 3
 
 /**
@@ -664,15 +663,6 @@
 extern void *nss_create_virt_if(struct net_device *netdev);
 
 /**
- * @brief Obtain NSS Interface number for a virtual interface context
- *
- * @param context Interface context
- *
- * @return int32_t The NSS interface number
- */
-int32_t nss_virt_if_get_interface_num(void *if_ctx);
-
-/**
  * @brief Destroy virtual interface (VAPs)
  *
  * @param ctx Context provided by NSS driver during registration
diff --git a/exports/nss_dynamic_interface.h b/exports/nss_dynamic_interface.h
index e42c2b9..efc8ba6 100644
--- a/exports/nss_dynamic_interface.h
+++ b/exports/nss_dynamic_interface.h
@@ -22,22 +22,77 @@
 #ifndef __NSS_DYNAMIC_INTERFACE_H
 #define __NSS_DYNAMIC_INTERFACE_H
 
+#define NSS_MAX_DYNAMIC_INTERFACES 64
+
 /**
  * Dynamic Interface types
  */
 enum nss_dynamic_interface_type {
-	NSS_DYNAMIC_INTERFACE_TYPE_NONE = 0,
-	NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR = 1,	/* GRE_REDIR Interface type */
-	NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP = 2,		/* CAPWAP Interface type */
-	NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD = 3,		/* TUN6RD Interface type */
-	NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR = 4,	/* 802.3 redirect Interface type */
-	NSS_DYNAMIC_INTERFACE_TYPE_WIFI = 5,		/* Wifi redirect Interface type */
-	NSS_DYNAMIC_INTERFACE_TYPE_RADIO_0 = 6,		/* WIFI radio type0 */
-	NSS_DYNAMIC_INTERFACE_TYPE_RADIO_1 = 7,		/* WIFI radio type1 */
-	NSS_DYNAMIC_INTERFACE_TYPE_RADIO_2 = 8,		/* WIFI radio type2 */
+	NSS_DYNAMIC_INTERFACE_TYPE_NONE,
+	NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR,	/* GRE_REDIR Interface type */
+	NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP,		/* CAPWAP Interface type */
+	NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD,		/* TUN6RD Interface type */
+	NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR,	/* 802.3 redirect Interface type */
+	NSS_DYNAMIC_INTERFACE_TYPE_WIFI,		/* Wifi redirect Interface type */
+	NSS_DYNAMIC_INTERFACE_TYPE_RADIO_0,		/* WIFI radio type0 */
+	NSS_DYNAMIC_INTERFACE_TYPE_RADIO_1,		/* WIFI radio type1 */
+	NSS_DYNAMIC_INTERFACE_TYPE_RADIO_2,		/* WIFI radio type2 */
+	NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED,
 	NSS_DYNAMIC_INTERFACE_TYPE_MAX
 };
 
+typedef enum nss_dynamic_interface_type nss_dynamic_interface_assigned;
+
+/*
+ * Dynamic Interface request types
+ */
+enum nss_dynamic_interface_message_types {
+	NSS_DYNAMIC_INTERFACE_ALLOC_NODE,	/* Alloc node message type */
+	NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,	/* Dealloc node message type */
+	NSS_DYNAMIC_INTERFACE_MAX,
+};
+
+/*
+ * Dynamic interface alloc node msg
+ */
+struct nss_dynamic_interface_alloc_node_msg {
+	enum nss_dynamic_interface_type type;	/* Dynamic Interface type */
+	/*
+	 * Response
+	 */
+	int if_num;				/* Interface number */
+};
+
+/*
+ * Dynamic interface dealloc node msg
+ */
+struct nss_dynamic_interface_dealloc_node_msg {
+	enum nss_dynamic_interface_type type;	/* Dynamic Interface type */
+	int if_num;				/* Interface number */
+};
+
+/*
+ * Message structure to send/receive Dynamic Interface messages
+ */
+struct nss_dynamic_interface_msg {
+	struct nss_cmn_msg cm;							/* Common Message */
+	union {
+		struct nss_dynamic_interface_alloc_node_msg alloc_node;		/* Msg: Allocate dynamic node */
+		struct nss_dynamic_interface_dealloc_node_msg dealloc_node;	/* Msg: deallocate dynamic node */
+	} msg;
+};
+
+/*
+ * Private data structure of dynamic interface
+ */
+struct nss_dynamic_interface_pvt {
+	struct semaphore sem;			/* Semaphore structure */
+	struct completion complete;		/* completion structure */
+	int current_if_num;			/* Current interface number */
+	enum nss_cmn_response response;		/* Message response */
+	nss_dynamic_interface_assigned type[NSS_MAX_DYNAMIC_INTERFACES]; /* Array of assigned interface types */
+};
+
 /**
  * @brief allocate node for dynamic interface on NSS
  *
@@ -75,4 +130,38 @@
  */
 extern enum nss_dynamic_interface_type nss_dynamic_interface_get_type(int if_num);
 
+/**
+ * @brief Transmits an asynchronous message to firmware.
+ *
+ * @param nss_ctx context
+ * @param msg dynamic interface message to be sent to the firmware.
+ *
+ * @return message Tx status
+ */
+extern nss_tx_status_t nss_dynamic_interface_tx(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *msg);
+
+/**
+ * @brief Dynamic interface message callback type
+ *
+ * @param app_data app_data returned to callback fn.
+ * @param msg nss common message
+ *
+ * @return void
+ */
+typedef void (*nss_dynamic_interface_msg_callback_t)(void *app_data, struct nss_cmn_msg *msg);
+
+/**
+ * @brief Initialize dynamic interface message
+ *
+ * @param ndm dynamic interface message to be initialized.
+ * @param if_num Interface number.
+ * @param type dynamic interface type
+ * @param len message length
+ * @param cb callback to be invoked
+ * @param app_data app_data passed to the callback fn.
+ *
+ * @return void
+ */
+void nss_dynamic_interface_msg_init(struct nss_dynamic_interface_msg *ndm, uint16_t if_num, uint32_t type, uint32_t len,
+						void *cb, void *app_data);
 #endif /* __NSS_DYNAMIC_INTERFACE_H*/
diff --git a/exports/nss_virt_if.h b/exports/nss_virt_if.h
index 6ea97fd..506c114 100644
--- a/exports/nss_virt_if.h
+++ b/exports/nss_virt_if.h
@@ -123,6 +123,7 @@
 struct nss_virt_if_handle {
 	struct nss_ctx_instance *nss_ctx;	/*< NSS context */
 	int32_t if_num;				/*< interface number */
+	struct net_device *ndev;		/*< Associated netdevice */
 	struct nss_virt_if_pvt *pvt;		/*< Private data structure */
 	struct nss_virt_if_stats stats;		/*< virt_if stats */
 	atomic_t refcnt;			/*< Reference count */
@@ -131,20 +132,44 @@
 };
 
 /**
- * @brief Create a virtual interface
+ * @brief Create a virtual interface, asynchronously
  *
- * @param netdev net device associated with Wifi
- * @return Pointer to nss_virt_if_handle struct
+ * @param netdev net device associated with client
+ * @param cb callback to be invoked when the response from the FW is received
+ * @param app_data app_data to be passed to the callback.
+ *
+ * @return int command tx status
  */
-extern struct nss_virt_if_handle *nss_virt_if_create(struct net_device *netdev);
+extern int nss_virt_if_create(struct net_device *netdev, nss_virt_if_msg_callback_t cb, void *app_data);
 
 /**
- * @brief Destroy the virtual interface associated with the if_num
+ * @brief Create a virtual interface, synchronously.
+ *
+ * @param netdev net device associated with WiFi
+ *
+ * @return Pointer to nss_virt_if_handle struct
+ */
+extern struct nss_virt_if_handle *nss_virt_if_create_sync(struct net_device *netdev);
+
+/**
+ * @brief Destroy the virtual interface associated with the if_num, asynchronously.
  *
  * @param handle virtual interface handle (provided during dynamic_interface allocation)
+ * @param cb callback to be invoked when the response from the FW is received
+ * @param app_data app_data to be passed to the callback.
+ *
  * @return command Tx status
  */
-extern nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle);
+extern nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle, nss_virt_if_msg_callback_t cb, void *app_data);
+
+/**
+ * @brief Destroy the virtual interface associated with the if_num, synchronously.
+ *
+ * @param handle virtual interface handle (provided during dynamic_interface allocation)
+ *
+ * @return command Tx status
+ */
+extern nss_tx_status_t nss_virt_if_destroy_sync(struct nss_virt_if_handle *handle);
 
 /**
  * @brief Send message to virtual interface
@@ -180,11 +205,12 @@
 					nss_virt_if_data_callback_t data_callback,
 					struct net_device *netdev);
 
-
 /**
  * @brief Unregister virtual interface from NSS driver
  *
  * @param handle virtual interface handle
+ *
+ * @return void
  */
 extern void nss_virt_if_unregister(struct nss_virt_if_handle *handle);
 
@@ -199,4 +225,13 @@
  */
 extern int32_t nss_virt_if_copy_stats(int32_t if_num, int i, char *line);
 
+/**
+ * @brief Returns the virtual interface number associated with the handle.
+ *
+ * @param handle virtual interface handle(provided during dynamic_interface allocation)
+ *
+ * @return if_num virtual interface number.
+ */
+extern int32_t nss_virt_if_get_interface_num(struct nss_virt_if_handle *handle);
+
 #endif /* __NSS_VIRT_IF_H */
diff --git a/nss_cmn.c b/nss_cmn.c
index 9fab600..853c1c6 100644
--- a/nss_cmn.c
+++ b/nss_cmn.c
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2015 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
  * above copyright notice and this permission notice appear in all copies.
@@ -139,7 +139,9 @@
  */
 bool nss_cmn_interface_is_virtual(void *nss_ctx, int32_t interface_num)
 {
-	return (NSS_IS_IF_TYPE(DYNAMIC, interface_num) || NSS_IS_IF_TYPE(VIRTUAL, interface_num));
+	return ((nss_dynamic_interface_get_type(interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_WIFI)
+		|| (nss_dynamic_interface_get_type(interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR)
+		|| (nss_dynamic_interface_get_type(interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED));
 }
 
 /*
diff --git a/nss_core.c b/nss_core.c
index 8ae4914..b6ef1a0 100755
--- a/nss_core.c
+++ b/nss_core.c
@@ -1620,7 +1620,7 @@
 		(uint16_t)(nbuf->end - nbuf->head), (uint32_t)nbuf->priority, mss, bit_flags);
 
 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
-	if (unlikely(!NSS_IS_IF_TYPE(VIRTUAL, if_num))) {
+	if (unlikely(!nss_cmn_interface_is_virtual(nss_ctx, if_num))) {
 		if (likely(nbuf->destructor == NULL)) {
 			if (likely(skb_recycle_check(nbuf, nss_ctx->max_buf_size))) {
 				bit_flags |= H2N_BIT_FLAG_BUFFER_REUSE;
diff --git a/nss_core.h b/nss_core.h
index 35f57ac..78bda23 100755
--- a/nss_core.h
+++ b/nss_core.h
@@ -671,6 +671,7 @@
 	struct dentry *core_log_dentry;	/* NSS Core's FW log file */
 	struct dentry *wifi_if_dentry;		/* wifi_if stats dentry */
 	struct dentry *virt_if_dentry;	/* virt_if stats dentry */
+	struct dentry *tx_rx_virt_if_dentry; /* tx_rx_virt_if stats dentry. Will be deprecated soon */
 	struct nss_ctx_instance nss[NSS_MAX_CORES];
 					/* NSS contexts */
 	/*
diff --git a/nss_dynamic_interface.c b/nss_dynamic_interface.c
index a340b94..920587d 100644
--- a/nss_dynamic_interface.c
+++ b/nss_dynamic_interface.c
@@ -21,22 +21,14 @@
 static struct nss_dynamic_interface_pvt di;
 
 /*
- * nss_dynamic_interface_msg_init()
- *	Initialize dynamic interface message.
- */
-static void nss_dynamic_interface_msg_init(struct nss_dynamic_interface_msg *ndm, uint16_t if_num, uint32_t type, uint32_t len,
-						void *cb, void *app_data)
-{
-	nss_cmn_msg_init(&ndm->cm, if_num, type, len, cb, app_data);
-}
-
-/*
  * nss_dynamic_interface_handler()
- * 	handle NSS -> HLOS messages for dynamic interfaces
+ * 	Handle NSS -> HLOS messages for dynamic interfaces
  */
 static void nss_dynamic_interface_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
 {
+	nss_dynamic_interface_msg_callback_t cb;
 	struct nss_dynamic_interface_msg *ndim = (struct nss_dynamic_interface_msg *)ncm;
+	int32_t if_num;
 
 	BUG_ON(ncm->interface != NSS_DYNAMIC_INTERFACE);
 
@@ -64,39 +56,103 @@
 	switch (ndim->cm.type) {
 	case NSS_DYNAMIC_INTERFACE_ALLOC_NODE:
 		if (ncm->response == NSS_CMN_RESPONSE_ACK) {
-			nss_info("%p if_num %d\n", nss_ctx, ndim->msg.alloc_node.if_num);
+			nss_info("%p alloc_node response ack if_num %d\n", nss_ctx, ndim->msg.alloc_node.if_num);
 			di.current_if_num = ndim->msg.alloc_node.if_num;
+			if_num = di.current_if_num;
+			if (if_num > 0) {
+				di.type[if_num - NSS_DYNAMIC_IF_START] = ndim->msg.alloc_node.type;
+			} else {
+				nss_warning("%p: if_num < 0\n", nss_ctx);
+			}
 		}
 
-		/*
-		 * Unblock the alloc_node message.
-		 */
-		complete(&di.complete);
 		break;
 
 	case NSS_DYNAMIC_INTERFACE_DEALLOC_NODE:
 		if (ncm->response == NSS_CMN_RESPONSE_ACK) {
-			nss_info("%p if_num %d\n", nss_ctx, ndim->msg.dealloc_node.if_num);
+			nss_info("%p dealloc_node response ack if_num %d\n", nss_ctx, ndim->msg.dealloc_node.if_num);
 			di.current_if_num = ndim->msg.dealloc_node.if_num;
+			if_num = di.current_if_num;
+			di.type[if_num - NSS_DYNAMIC_IF_START] = NSS_DYNAMIC_INTERFACE_TYPE_NONE;
 		}
 
-		/*
-		 * Unblock the dealloc_node message.
-		 */
-		complete(&di.complete);
 		break;
 
 	default:
 		nss_warning("%p: Received response %d for type %d, interface %d",
 				nss_ctx, ncm->response, ncm->type, ncm->interface);
+		return;
 	}
+
+	/*
+	 * Do we have a callback?
+	 */
+	if (!ncm->cb) {
+		nss_warning("%p: nss_dynamic_interface_handler cb is NULL\n", nss_ctx);
+		return;
+	}
+
+	/*
+	 * Callback
+	 */
+	cb = (nss_dynamic_interface_msg_callback_t)ncm->cb;
+	cb((void *)ncm->app_data, ncm);
+}
+
+/*
+ * nss_dynamic_interface_callback
+ *	Callback to handle the message response from NSS FW.
+ */
+static void nss_dynamic_interface_callback(void *app_data, struct nss_cmn_msg *ncm)
+{
+	/*
+	 * Unblock the sleeping function.
+	 */
+	di.response = ncm->response;
+	complete(&di.complete);
+}
+
+/*
+ * nss_dynamic_interface_tx_sync()
+ *	Send the message to NSS and wait till we get an ACK or NACK for this msg.
+ */
+static nss_tx_status_t nss_dynamic_interface_tx_sync(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *ndim)
+{
+	nss_tx_status_t status;
+	int ret;
+
+	/*
+	 * Acquring a semaphore , so that only one caller can send msg at a time.
+	 */
+	down(&di.sem);
+	di.response = false;
+
+	status = nss_dynamic_interface_tx(nss_ctx, ndim);
+	if (status != NSS_TX_SUCCESS) {
+		up(&di.sem);
+		nss_warning("%p: not able to transmit msg successfully\n", nss_ctx);
+		return status;
+	}
+
+	/*
+	 * Blocking call, wait till we get ACK for this msg.
+	 */
+	ret = wait_for_completion_timeout(&di.complete, msecs_to_jiffies(NSS_DYNAMIC_INTERFACE_COMP_TIMEOUT));
+	if (ret == 0) {
+		up(&di.sem);
+		nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
+		return NSS_TX_FAILURE;
+	}
+
+	up(&di.sem);
+	return status;
 }
 
 /*
  * nss_dynamic_interface_tx()
- * 	Transmit a dynamic interface message to NSSFW
+ * 	Transmit a dynamic interface message to NSSFW, asynchronously.
  */
-static nss_tx_status_t nss_dynamic_interface_tx(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *msg)
+nss_tx_status_t nss_dynamic_interface_tx(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *msg)
 {
 	struct nss_dynamic_interface_msg *nm;
 	struct nss_cmn_msg *ncm = &msg->cm;
@@ -156,33 +212,6 @@
 }
 
 /*
- * nss_dynamic_interface_tx_sync()
- *	Send the message to NSS and wait till we get an ACK or NACK for this msg.
- */
-static nss_tx_status_t nss_dynamic_interface_tx_sync(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *ndim)
-{
-	nss_tx_status_t status;
-	int ret;
-
-	status = nss_dynamic_interface_tx(nss_ctx, ndim);
-	if (status != NSS_TX_SUCCESS) {
-		nss_warning("%p: not able to transmit msg successfully\n", nss_ctx);
-		return status;
-	}
-
-	/*
-	 * Blocking call, wait till we get ACK for this msg.
-	 */
-	ret = wait_for_completion_timeout(&di.complete, msecs_to_jiffies(NSS_DYNAMIC_INTERFACE_COMP_TIMEOUT));
-	if (ret == 0) {
-		nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
-		return NSS_TX_FAILURE;
-	}
-
-	return status;
-}
-
-/*
  * nss_dynamic_interface_alloc_node()
  *	Allocates node of perticular type on NSS and returns interface_num for this node or -1 in case of failure.
  *
@@ -192,80 +221,54 @@
 int nss_dynamic_interface_alloc_node(enum nss_dynamic_interface_type type)
 {
 	struct nss_ctx_instance *nss_ctx = NULL;
-	struct nss_dynamic_interface_msg *ndim;
+	struct nss_dynamic_interface_msg ndim;
 	struct nss_dynamic_interface_alloc_node_msg *ndia;
 	uint32_t core_id;
 	nss_tx_status_t status;
-	int if_num;
 
 	if (type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX) {
 		nss_warning("Dynamic if msg drooped as type is wrong %d\n", type);
 		return -1;
 	}
 
-	ndim = vmalloc(sizeof(struct nss_dynamic_interface_msg));
-	if (!ndim) {
-		nss_warning(" Not able to allocate memory for alloc node message\n");
-		return -1;
-	}
-
 	core_id = nss_top_main.dynamic_interface_table[type];
 	nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[core_id];
 
-	nss_dynamic_interface_msg_init(ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_ALLOC_NODE,
-				sizeof(struct nss_dynamic_interface_alloc_node_msg), NULL, NULL);
+	nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_ALLOC_NODE,
+				sizeof(struct nss_dynamic_interface_alloc_node_msg), nss_dynamic_interface_callback, (void *)nss_ctx);
 
-	ndia = &ndim->msg.alloc_node;
+	ndia = &ndim.msg.alloc_node;
 	ndia->type = type;
 
 	/*
-	 * Initialize interface number to -1.
+	 * Initialize if_num to -1. The allocated if_num is returned by the firmware
+	 * in the response message.
 	 */
 	ndia->if_num = -1;
 
 	/*
-	 * Acquring a semaphore , so that only one caller can send msg at a time.
-	 */
-	down(&di.sem);
-
-	di.current_if_num = -1;
-
-	/*
 	 * Calling synchronous transmit function.
 	 */
-	status = nss_dynamic_interface_tx_sync(nss_ctx, ndim);
+	status = nss_dynamic_interface_tx_sync(nss_ctx, &ndim);
 	if (status != NSS_TX_SUCCESS) {
-		up(&di.sem);
-		vfree(ndim);
 		nss_warning("%p not able to transmit alloc node msg\n", nss_ctx);
 		return -1;
 	}
 
 	/*
-	 * di.current_if_num contains the right interface number.
+	 * Check di.response and return -1 if its a NACK else proceed.
 	 */
-	if (di.current_if_num < 0) {
+	if (di.response != NSS_CMN_RESPONSE_ACK) {
 		nss_warning("%p Received NACK from NSS\n", nss_ctx);
+		return -1;
 	}
 
-	if_num = di.current_if_num;
-	if (if_num > 0) {
-		di.if_num[if_num - NSS_DYNAMIC_IF_START].type = type;
-	}
-
-	/*
-	 * Release Semaphore
-	 */
-	up(&di.sem);
-
-	vfree(ndim);
-
-	return if_num;
+	return di.current_if_num;
 }
 
 /*
  * nss_dynamic_interface_dealloc_node()
- *	Deallocate node of perticular type and if_num on NSS.
+ *	Deallocate node of particular type and if_num in NSS.
  *
  * Note: This will just mark the state of node as not active, actual memory will be freed when reference count of that node becomes 0.
  * This function should not be called from soft_irq or interrupt context because it blocks till ACK/NACK is received for the message
@@ -274,68 +277,45 @@
 nss_tx_status_t nss_dynamic_interface_dealloc_node(int if_num, enum nss_dynamic_interface_type type)
 {
 	struct nss_ctx_instance *nss_ctx = NULL;
-	struct nss_dynamic_interface_msg *ndim;
+	struct nss_dynamic_interface_msg ndim;
 	struct nss_dynamic_interface_dealloc_node_msg *ndid;
 	uint32_t core_id;
 	nss_tx_status_t status;
 
 	if (type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX) {
-		nss_warning("Dynamic if msg dropped as type is wrong %d\n", type);
-		return NSS_TX_FAILURE;
-	}
-
-	ndim = vmalloc(sizeof(struct nss_dynamic_interface_msg));
-	if (!ndim) {
-		nss_warning(" Not able to allocate memory for dealloc node message\n");
-		return NSS_TX_FAILURE;
+		nss_warning("Dynamic if msg dropped as type is wrong type %d if_num %d\n", type, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
 	}
 
 	core_id = nss_top_main.dynamic_interface_table[type];
 	nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[core_id];
 
-	nss_dynamic_interface_msg_init(ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,
-				sizeof(struct nss_dynamic_interface_dealloc_node_msg), NULL, NULL);
+	if (nss_is_dynamic_interface(if_num) == false) {
+		nss_warning("%p: nss_dynamic_interface if_num is not in range %d\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
 
-	ndid = &ndim->msg.dealloc_node;
+	nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,
+				sizeof(struct nss_dynamic_interface_dealloc_node_msg), nss_dynamic_interface_callback, (void *)nss_ctx);
+
+	ndid = &ndim.msg.dealloc_node;
 	ndid->type = type;
 	ndid->if_num = if_num;
 
 	/*
-	 * Acquring a semaphore , so that only one caller can send msg at a time.
-	 */
-	down(&di.sem);
-
-	di.current_if_num = -1;
-
-	/*
 	 * Calling synchronous transmit function.
 	 */
-	status = nss_dynamic_interface_tx_sync(nss_ctx, ndim);
+	status = nss_dynamic_interface_tx_sync(nss_ctx, &ndim);
 	if (status != NSS_TX_SUCCESS) {
-		up (&di.sem);
-		vfree(ndim);
 		nss_warning("%p not able to transmit alloc node msg\n", nss_ctx);
 		return status;
 	}
 
-	if (di.current_if_num < 0) {
-		up (&di.sem);
-		vfree(ndim);
+	if (di.response != NSS_CMN_RESPONSE_ACK) {
 		nss_warning("%p Received NACK from NSS\n", nss_ctx);
-		return NSS_TX_FAILURE;
+		return -1;
 	}
 
-	if (if_num > 0) {
-		di.if_num[if_num - NSS_DYNAMIC_IF_START].type = NSS_DYNAMIC_INTERFACE_TYPE_NONE;
-	}
-
-	/*
-	 * Release Semaphore
-	 */
-	up(&di.sem);
-
-	vfree(ndim);
-
 	return status;
 }
 
@@ -370,7 +350,17 @@
 		return NSS_DYNAMIC_INTERFACE_TYPE_NONE;
 	}
 
-	return di.if_num[if_num - NSS_DYNAMIC_IF_START].type;
+	return di.type[if_num - NSS_DYNAMIC_IF_START];
+}
+
+/*
+ * nss_dynamic_interface_msg_init()
+ *	Initialize dynamic interface message.
+ */
+void nss_dynamic_interface_msg_init(struct nss_dynamic_interface_msg *ndm, uint16_t if_num, uint32_t type, uint32_t len,
+						void *cb, void *app_data)
+{
+	nss_cmn_msg_init(&ndm->cm, if_num, type, len, cb, app_data);
 }
 
 EXPORT_SYMBOL(nss_dynamic_interface_alloc_node);
diff --git a/nss_hlos_if.h b/nss_hlos_if.h
index 036e47e..ae96db5 100755
--- a/nss_hlos_if.h
+++ b/nss_hlos_if.h
@@ -308,68 +308,6 @@
 };
 
 /*
- * Dynamic interface messages
- */
-
-/*
- * Dynamic Interface request/response types
- */
-enum nss_dynamic_interface_message_types {
-	NSS_DYNAMIC_INTERFACE_ALLOC_NODE,	/* Alloc node message type */
-	NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,	/* Dealloc node message type */
-	NSS_DYNAMIC_INTERFACE_MAX,
-};
-
-/*
- * Dynamic interface alloc node msg
- */
-struct nss_dynamic_interface_alloc_node_msg {
-	enum nss_dynamic_interface_type type;	/* Dynamic Interface type */
-	/*
-	 * Response
-	 */
-	int if_num;				/* Interface number */
-};
-
-/*
- * This structure is there to keep information
- * pertaining to each if_num allocated through
- * dynamic interface API
- */
-struct nss_dynamic_interface_assigned {
-	enum nss_dynamic_interface_type type;
-};
-
-/*
- * Private data structure of dynamic interface
- */
-struct nss_dynamic_interface_pvt {
-	struct semaphore sem;			/* Semaphore structure */
-	struct completion complete;		/* completion structure */
-	int current_if_num;			/* Current interface number */
-	struct nss_dynamic_interface_assigned if_num[NSS_MAX_DYNAMIC_INTERFACES];
-};
-
-/*
- * Dynamic interface dealloc node msg
- */
-struct nss_dynamic_interface_dealloc_node_msg {
-	enum nss_dynamic_interface_type type;	/* Dynamic Interface type */
-	int if_num;				/* Interface number */
-};
-
-/*
- * Message structure to send/receive Dynamic Interface messages
- */
-struct nss_dynamic_interface_msg {
-	struct nss_cmn_msg cm;							/* Common Message */
-	union {
-		struct nss_dynamic_interface_alloc_node_msg alloc_node;		/* Msg: Allocate dynamic node */
-		struct nss_dynamic_interface_dealloc_node_msg dealloc_node;	/* Msg: deallocate dynamic node */
-	} msg;
-};
-
-/*
  * H2N Buffer Types
  */
 #define H2N_BUFFER_EMPTY			0
diff --git a/nss_if.c b/nss_if.c
index b64f521..0ce06cc 100644
--- a/nss_if.c
+++ b/nss_if.c
@@ -39,11 +39,9 @@
 		return;
 	}
 
-	/*
-	 * As the base class we allow both virtual and physical interfaces.
-	 */
-	if (ncm->interface > NSS_TUNNEL_IF_START) {
-		nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
+	if (!nss_is_dynamic_interface(ncm->interface) &&
+		!((ncm->interface >= NSS_PHYSICAL_IF_START) && (ncm->interface < NSS_VIRTUAL_IF_START))) {
+		nss_warning("%p: interface %d not in physical or dynamic if range\n", nss_ctx, ncm->interface);
 		return;
 	}
 
@@ -87,6 +85,12 @@
 		return NSS_TX_FAILURE_NOT_READY;
 	}
 
+	if (!nss_is_dynamic_interface(if_num) &&
+		!((if_num >= NSS_PHYSICAL_IF_START) && (if_num < NSS_VIRTUAL_IF_START))) {
+		nss_warning("%p: interface %d not in physical or dynamic if range\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
 	status = nss_core_send_buffer(nss_ctx, if_num, os_buf, NSS_IF_DATA_QUEUE_0, H2N_BUFFER_PACKET, 0);
 	if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
 		nss_warning("%p: Unable to enqueue 'Phys If Tx' packet\n", nss_ctx);
@@ -126,13 +130,6 @@
 	/*
 	 * Sanity check the message
 	 */
-	/*
-	 * As the base class we allow both virtual and physical interfaces.
-	 */
-	if (ncm->interface > NSS_TUNNEL_IF_START) {
-		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
-		return NSS_TX_FAILURE;
-	}
 
 	if (ncm->type > NSS_IF_MAX_MSG_TYPES) {
 		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
diff --git a/nss_stats.c b/nss_stats.c
index 71fd9ac..d5ed3e5 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -34,6 +34,8 @@
  */
 extern struct nss_top_instance nss_top_main;
 
+extern int32_t nss_tx_rx_virt_if_copy_stats(int32_t if_num, int i, char *line);
+
 uint64_t stats_shadow_pppoe_except[NSS_PPPOE_NUM_SESSION_PER_INTERFACE][NSS_PPPOE_EXCEPTION_EVENT_MAX];
 
 /*
@@ -1783,6 +1785,87 @@
 }
 
 /*
+ * nss_stats_tx_rx_virt_if_read()
+ *	Read tx_rx_virt_if statistics
+ */
+static ssize_t nss_stats_tx_rx_virt_if_read(struct file *fp, char __user *ubuf,
+						size_t sz, loff_t *ppos)
+{
+	struct nss_stats_data *data = fp->private_data;
+	int32_t if_num = NSS_DYNAMIC_IF_START;
+	int32_t max_if_num = if_num + NSS_MAX_DYNAMIC_INTERFACES;
+	size_t bytes = 0;
+	ssize_t bytes_read = 0;
+	char line[80];
+	int start, end;
+
+	if (data) {
+		if_num = data->if_num;
+	}
+
+	if (if_num > max_if_num) {
+		return 0;
+	}
+
+	for (; if_num < max_if_num; if_num++) {
+		if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED)
+			continue;
+
+		bytes = scnprintf(line, sizeof(line), "if_num %d stats start:\n\n", if_num);
+		if ((bytes_read + bytes) > sz)
+			break;
+
+		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
+			bytes_read = -EFAULT;
+			goto end;
+		}
+
+		bytes_read += bytes;
+
+		start = 0;
+		end = 7;
+		while (bytes_read < sz && start < end) {
+			bytes = nss_tx_rx_virt_if_copy_stats(if_num, start, line);
+			if (!bytes)
+				break;
+
+			if ((bytes_read + bytes) > sz)
+				break;
+
+			if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
+				bytes_read = -EFAULT;
+				goto end;
+			}
+
+			bytes_read += bytes;
+			start++;
+		}
+
+		bytes = scnprintf(line, sizeof(line), "if_num %d stats end:\n\n", if_num);
+		if (bytes_read > (sz - bytes))
+			break;
+
+		if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
+			bytes_read = -EFAULT;
+			goto end;
+		}
+
+		bytes_read += bytes;
+	}
+
+	if (bytes_read > 0) {
+		*ppos = bytes_read;
+	}
+
+	if (data) {
+		data->if_num = if_num;
+	}
+
+end:
+	return bytes_read;
+}
+
+/*
  * nss_stats_open()
  */
 static int nss_stats_open(struct inode *inode, struct file *filp)
@@ -1893,6 +1976,8 @@
 
 NSS_STATS_DECLARE_FILE_OPERATIONS(virt_if)
 
+NSS_STATS_DECLARE_FILE_OPERATIONS(tx_rx_virt_if)
+
 /*
  * wifi_stats_ops
  */
@@ -2097,6 +2182,13 @@
 		return;
 	}
 
+	nss_top_main.tx_rx_virt_if_dentry = debugfs_create_file("tx_rx_virt_if", 0400,
+						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_tx_rx_virt_if_ops);
+	if (unlikely(nss_top_main.virt_if_dentry == NULL)) {
+		nss_warning("Failed to create qca-nss-drv/stats/tx_rx_virt_if file in debugfs");
+		return;
+	}
+
 	nss_log_init();
 }
 
diff --git a/nss_tx_rx_common.h b/nss_tx_rx_common.h
index 94a3c93..95e67f4 100644
--- a/nss_tx_rx_common.h
+++ b/nss_tx_rx_common.h
@@ -60,14 +60,123 @@
 #endif
 
 /*
- * Handles associated with redir interfaces(virt_if & wifi_if).
+ * Deprecated Redirect
+ */
+
+/**
+ * @brief Request/Response types
+ */
+enum nss_tx_rx_virt_if_msg_types {
+	NSS_TX_RX_VIRT_IF_OPEN = NSS_IF_OPEN,
+	NSS_TX_RX_VIRT_IF_CLOSE = NSS_IF_CLOSE,
+	NSS_TX_RX_VIRT_IF_LINK_STATE_NOTIFY = NSS_IF_LINK_STATE_NOTIFY,
+	NSS_TX_RX_VIRT_IF_MTU_CHANGE = NSS_IF_MTU_CHANGE,
+	NSS_TX_RX_VIRT_IF_MAC_ADDR_SET = NSS_IF_MAC_ADDR_SET,
+	NSS_TX_RX_VIRT_IF_STATS_SYNC = NSS_IF_STATS,
+	NSS_TX_RX_VIRT_IF_ISHAPER_ASSIGN = NSS_IF_ISHAPER_ASSIGN,
+	NSS_TX_RX_VIRT_IF_BSHAPER_ASSIGN = NSS_IF_BSHAPER_ASSIGN,
+	NSS_TX_RX_VIRT_IF_ISHAPER_UNASSIGN = NSS_IF_ISHAPER_UNASSIGN,
+	NSS_TX_RX_VIRT_IF_BSHAPER_UNASSIGN = NSS_IF_BSHAPER_UNASSIGN,
+	NSS_TX_RX_VIRT_IF_ISHAPER_CONFIG = NSS_IF_ISHAPER_CONFIG,
+	NSS_TX_RX_VIRT_IF_BSHAPER_CONFIG = NSS_IF_BSHAPER_CONFIG,
+	NSS_TX_RX_VIRT_IF_TX_CREATE_MSG = NSS_IF_MAX_MSG_TYPES + 1,
+	NSS_TX_RX_VIRT_IF_TX_DESTROY_MSG,
+	NSS_TX_RX_VIRT_IF_STATS_SYNC_MSG,
+	NSS_TX_RX_VIRT_IF_MAX_MSG_TYPES,
+};
+
+/**
+ * virt_if error types
+ */
+enum nss_tx_rx_virt_if_error_types {
+	NSS_TX_RX_VIRT_IF_SUCCESS,			/*< Success */
+	NSS_TX_RX_VIRT_IF_CORE_FAILURE,		/*< nss core failure */
+	NSS_TX_RX_VIRT_IF_ALLOC_FAILURE,		/*< Memory allocation failure */
+	NSS_TX_RX_VIRT_IF_DYNAMIC_IF_FAILURE,	/*< Dynamic interface failure */
+	NSS_TX_RX_VIRT_IF_MSG_TX_FAILURE,		/*< Message transmission failure */
+	NSS_TX_RX_VIRT_IF_REG_FAILURE,		/*< Registration failure */
+	NSS_TX_RX_VIRT_IF_CORE_NOT_INITIALIZED,	/*< NSS core not intialized */
+};
+
+/**
+ * Structure which contains stats received from NSS.
+ */
+struct nss_tx_rx_virt_if_stats {
+	struct nss_if_stats node_stats;	/**< common stats */
+	uint32_t tx_enqueue_failed;	/**< tx enqueue failures in the FW */
+	uint32_t shaper_enqueue_failed;	/**< shaper enqueue failures in the FW */
+};
+
+/**
+ * The NSS virtual interface creation structure.
+ */
+struct nss_tx_rx_virt_if_create_msg {
+	uint32_t flags;			/**< Interface flags */
+	uint8_t mac_addr[ETH_ALEN];	/**< MAC address */
+};
+
+/**
+ * The NSS virtual interface destruction structure.
+ */
+struct nss_tx_rx_virt_if_destroy_msg {
+	int32_t reserved;		/**< place holder */
+};
+
+/**
+ * Message structure to send/receive virtual interface commands
+ */
+struct nss_tx_rx_virt_if_msg {
+	struct nss_cmn_msg cm;
+				/**< Message Header */
+	union {
+		union nss_if_msgs if_msgs;
+		struct nss_tx_rx_virt_if_create_msg if_create;
+				/**< Message: create virt if rule */
+		struct nss_tx_rx_virt_if_destroy_msg if_destroy;
+				/**< Message: destroy virt if rule */
+		struct nss_tx_rx_virt_if_stats stats;
+				/**< Message: stats */
+	} msg;
+};
+
+/*
+ * Private data structure for virt_if interface
+ */
+struct nss_tx_rx_virt_if_pvt {
+	struct semaphore sem;
+	struct completion complete;
+	int response;
+	int sem_init_done;
+};
+
+typedef void (*nss_tx_rx_virt_if_data_callback_t)(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi);
+typedef void (*nss_tx_rx_virt_if_msg_callback_t)(void *app_data, struct nss_cmn_msg *msg);
+
+/*
+ * Handles associated with redir interfaces(virt_if & wifi_i).
  * TODO: Once wifi moves to using the new interfaces, this will be deprecated.
  */
-struct nss_redir_handle {
-	struct nss_wifi_if_handle *whandle;
-	struct nss_virt_if_handle *vhandle;
+
+struct nss_tx_rx_virt_if_handle {
+	struct nss_ctx_instance *nss_ctx;
+	int32_t if_num;
+	struct nss_tx_rx_virt_if_pvt *pvt;
+	struct nss_tx_rx_virt_if_stats stats;
+	nss_tx_rx_virt_if_msg_callback_t cb;
+	void *app_data;
 };
 
+/**
+ * @brief Get stats for redir interface from NSS driver
+ *
+ * @param if_num Interface number (provided during dynamic_interface allocation)
+ * @param i index of stats
+ * @param line buffer into which the stats will be copied.
+ *
+ * @return int32_t Returns 0 if if_num is not in range or the number of bytes copied.
+ */
+extern int32_t nss_tx_rx_virt_if_copy_stats(int32_t if_num, int i, char *line);
+
 /*
  * CB handlers for variour interfaces
  */
diff --git a/nss_tx_rx_virt_if.c b/nss_tx_rx_virt_if.c
index fc3eb2f..4ac7bbe 100644
--- a/nss_tx_rx_virt_if.c
+++ b/nss_tx_rx_virt_if.c
@@ -22,19 +22,163 @@
 #include "nss_tx_rx_common.h"
 #include <net/arp.h>
 
+#define NSS_TX_RX_VIRT_IF_TX_TIMEOUT		3000 /* 3 Seconds */
+#define NSS_TX_RX_VIRT_IF_GET_INDEX(if_num)	(if_num-NSS_DYNAMIC_IF_START)
+#define NSS_TX_RX_VIRT_IF_802_3_PKT		0x2
+#define NSS_TX_RX_VIRT_IF_NATIVE_WIFI_PKT 	0x3
+
 extern int nss_ctl_redirect;
 
 /*
+ * Data structure that holds the virtual interface context.
+ */
+static struct nss_tx_rx_virt_if_handle *nss_tx_rx_virt_if_handles[NSS_MAX_DYNAMIC_INTERFACES];
+
+/*
+ * Spinlock to protect the global data structure virt_handle.
+ */
+DEFINE_SPINLOCK(nss_tx_rx_virt_if_lock);
+
+/*
+ * nss_tx_rx_virt_if_stats_sync()
+ *	Sync stats from the NSS FW
+ */
+static void nss_tx_rx_virt_if_stats_sync(struct nss_tx_rx_virt_if_handle *handle,
+					struct nss_tx_rx_virt_if_stats *nwis)
+{
+	struct nss_tx_rx_virt_if_stats *stats = &handle->stats;
+
+	stats->node_stats.rx_packets += nwis->node_stats.rx_packets;
+	stats->node_stats.rx_bytes += nwis->node_stats.rx_bytes;
+	stats->node_stats.rx_dropped += nwis->node_stats.rx_dropped;
+	stats->node_stats.tx_packets += nwis->node_stats.tx_packets;
+	stats->node_stats.tx_bytes += nwis->node_stats.tx_bytes;
+	stats->tx_enqueue_failed += nwis->tx_enqueue_failed;
+	stats->shaper_enqueue_failed += nwis->shaper_enqueue_failed;
+}
+
+/*
+ * nss_tx_rx_virt_if_msg_handler()
+ *	Handle msg responses from the FW on virtual interfaces
+ */
+static void nss_tx_rx_virt_if_msg_handler(struct nss_ctx_instance *nss_ctx,
+					struct nss_cmn_msg *ncm,
+					__attribute__((unused))void *app_data)
+{
+	struct nss_tx_rx_virt_if_msg *nvim = (struct nss_tx_rx_virt_if_msg *)ncm;
+	int32_t if_num;
+
+	nss_tx_rx_virt_if_msg_callback_t cb;
+	struct nss_tx_rx_virt_if_handle *handle = NULL;
+
+	/*
+	 * Sanity check the message type
+	 */
+	if (ncm->type > NSS_VIRT_IF_MAX_MSG_TYPES) {
+		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
+		return;
+	}
+
+	/*
+	 * Messages value that are within the base class are handled by the base class.
+	 */
+	if (ncm->type < NSS_IF_MAX_MSG_TYPES) {
+		return nss_if_msg_handler(nss_ctx, ncm, app_data);
+	}
+
+	if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
+		nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
+		return;
+	}
+
+	if_num = NSS_TX_RX_VIRT_IF_GET_INDEX(ncm->interface);
+
+	spin_lock_bh(&nss_tx_rx_virt_if_lock);
+	if (!nss_tx_rx_virt_if_handles[if_num]) {
+		spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+		nss_warning("%p: redir_if handle is NULL\n", nss_ctx);
+		return;
+	}
+
+	handle = nss_tx_rx_virt_if_handles[if_num];
+	spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+
+	switch (nvim->cm.type) {
+	case NSS_VIRT_IF_STATS_SYNC_MSG:
+		nss_tx_rx_virt_if_stats_sync(handle, &nvim->msg.stats);
+		break;
+	}
+
+	/*
+	 * Log failures
+	 */
+	nss_core_log_msg_failures(nss_ctx, ncm);
+
+	/*
+	 * Update the callback and app_data for NOTIFY messages, IPv4 sends all notify messages
+	 * to the same callback/app_data.
+	 */
+	if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
+		ncm->cb = (uint32_t)nss_ctx->nss_top->virt_if_msg_callback[ncm->interface];
+		ncm->app_data = (uint32_t)nss_ctx->nss_top->subsys_dp_register[ncm->interface].ndev;
+	}
+
+	/*
+	 * Do we have a callback?
+	 */
+	if (!ncm->cb) {
+		return;
+	}
+
+	/*
+	 * Callback
+	 */
+	cb = (nss_tx_rx_virt_if_msg_callback_t)ncm->cb;
+	cb((void *)ncm->app_data, ncm);
+}
+
+/*
+ * nss_tx_rx_virt_if_callback
+ *	Callback to handle the completion of NSS ->HLOS messages.
+ */
+static void nss_tx_rx_virt_if_callback(void *app_data, struct nss_cmn_msg *ncm)
+{
+	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)app_data;
+	struct nss_tx_rx_virt_if_pvt *nvip = handle->pvt;
+
+	if (ncm->response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("%p: redir_if Error response %d\n", handle->nss_ctx, ncm->response);
+		nvip->response = NSS_TX_FAILURE;
+		complete(&nvip->complete);
+		return;
+	}
+
+	nvip->response = NSS_TX_SUCCESS;
+	complete(&nvip->complete);
+}
+
+/*
  * nss_register_virt_if()
  */
 void *nss_register_virt_if(void *ctx,
 				nss_virt_if_rx_callback_t rx_callback,
 				struct net_device *netdev)
 {
-	struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
+	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
 
-	nss_wifi_if_register(handle->whandle, rx_callback, netdev);
-	nss_virt_if_register(handle->vhandle, rx_callback, netdev);
+	int32_t if_num;
+
+	if (!handle) {
+		nss_warning("handle is NULL\n");
+		return NULL;
+	}
+
+	if_num = handle->if_num;
+
+	nss_top_main.subsys_dp_register[if_num].ndev = netdev;
+	nss_top_main.subsys_dp_register[if_num].cb = rx_callback;
+	nss_top_main.subsys_dp_register[if_num].app_data = NULL;
+	nss_top_main.subsys_dp_register[if_num].features = (uint32_t)netdev->features;
 
 	return ctx;
 }
@@ -44,10 +188,22 @@
  */
 void nss_unregister_virt_if(void *ctx)
 {
-	struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
+	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
+	int32_t if_num;
 
-	nss_wifi_if_unregister(handle->whandle);
-	nss_virt_if_unregister(handle->vhandle);
+	if (!handle) {
+		nss_warning("handle is NULL\n");
+		return;
+	}
+
+	if_num = handle->if_num;
+
+	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+	nss_top_main.subsys_dp_register[if_num].cb = NULL;
+	nss_top_main.subsys_dp_register[if_num].app_data = NULL;
+	nss_top_main.subsys_dp_register[if_num].features = 0;
+
+	nss_top_main.if_rx_msg_callback[if_num] = NULL;
 }
 
 /*
@@ -56,13 +212,75 @@
  */
 nss_tx_status_t nss_tx_virt_if_recvbuf(void *ctx, struct sk_buff *skb, uint32_t nwifi)
 {
-	struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
+	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
+	int32_t if_num = handle->if_num;
+	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+	nss_tx_status_t status;
 
-	if (nwifi) {
-		return nss_wifi_if_tx_buf(handle->whandle, skb);
-	} else {
-		return nss_virt_if_tx_buf(handle->vhandle, skb);
+	if (unlikely(nss_ctl_redirect == 0)) {
+		return NSS_TX_FAILURE_NOT_ENABLED;
 	}
+
+	if (unlikely(skb->vlan_tci)) {
+		return NSS_TX_FAILURE_NOT_SUPPORTED;
+	}
+
+	nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num));
+	nss_trace("%p: Virtual Rx packet, if_num:%d, skb:%p", nss_ctx, if_num, skb);
+
+	/*
+	 * Get the NSS context that will handle this packet and check that it is initialised and ready
+	 */
+	NSS_VERIFY_CTX_MAGIC(nss_ctx);
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: Virtual Rx packet dropped as core not ready", nss_ctx);
+		return NSS_TX_FAILURE_NOT_READY;
+	}
+
+	/*
+	 * Sanity check the SKB to ensure that it's suitable for us
+	 */
+	if (unlikely(skb->len <= ETH_HLEN)) {
+		nss_warning("%p: Virtual Rx packet: %p too short", nss_ctx, skb);
+		return NSS_TX_FAILURE_TOO_SHORT;
+	}
+
+	if (unlikely(skb_shinfo(skb)->nr_frags != 0)) {
+		/*
+		 * TODO: If we have a connection matching rule for this skbuff,
+		 * do we need to flush it??
+		 */
+		nss_warning("%p: Delivering the packet to Linux because of fragmented skb: %p\n", nss_ctx, skb);
+		return NSS_TX_FAILURE_NOT_SUPPORTED;
+	}
+
+	/*
+	 * We differentiate between skbs with priority to identify native vs non-native wifi pkts
+	 */
+	if (nwifi) {
+		skb->priority = NSS_TX_RX_VIRT_IF_NATIVE_WIFI_PKT;
+	} else {
+		skb->priority = NSS_TX_RX_VIRT_IF_802_3_PKT;
+	}
+
+	/*
+	 * Direct the buffer to the NSS
+	 */
+	status = nss_core_send_buffer(nss_ctx, if_num, skb, NSS_IF_DATA_QUEUE_0,
+					H2N_BUFFER_PACKET, H2N_BIT_FLAG_VIRTUAL_BUFFER);
+	if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
+		nss_warning("%p: Virtual Rx packet unable to enqueue\n", nss_ctx);
+		return NSS_TX_FAILURE_QUEUE;
+	}
+
+	/*
+	 * Kick the NSS awake so it can process our new entry.
+	 */
+	nss_hal_send_interrupt(nss_ctx->nmap,
+				nss_ctx->h2n_desc_rings[NSS_IF_DATA_QUEUE_0].desc_ring.int_bit,
+				NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
+	NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
+	return NSS_TX_SUCCESS;
 }
 
 /*
@@ -95,50 +313,410 @@
 }
 
 /*
- * nss_create_virt_if()
+ * nss_tx_rx_virt_if_msg_init()
+ *	Initialize redir specific message structure.
  */
-void *nss_create_virt_if(struct net_device *netdev)
+static void nss_tx_rx_virt_if_msg_init(struct nss_tx_rx_virt_if_msg *nrim,
+					uint16_t if_num,
+					uint32_t type,
+					uint32_t len,
+					nss_tx_rx_virt_if_msg_callback_t cb,
+					struct nss_tx_rx_virt_if_handle *app_data)
 {
-	struct nss_redir_handle *handles;
+	nss_cmn_msg_init(&nrim->cm, if_num, type, len, (void *)cb, (void *)app_data);
+}
 
-	handles = (struct nss_redir_handle *)kzalloc(sizeof(struct nss_redir_handle), GFP_KERNEL);
-	if (!handles) {
-		nss_warning("%s: kzalloc failed\n", __func__);
+/*
+ * nss_tx_rx_virt_if_handle_create_sync()
+ *	Initialize redir handle which holds the if_num and stats per interface.
+ */
+static struct nss_tx_rx_virt_if_handle *nss_tx_rx_virt_if_handle_create(struct nss_ctx_instance *nss_ctx, int32_t if_num, int32_t *cmd_rsp)
+{
+	int32_t index;
+	struct nss_tx_rx_virt_if_handle *handle;
+
+	index = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
+
+	handle = (struct nss_tx_rx_virt_if_handle *)kzalloc(sizeof(struct nss_tx_rx_virt_if_handle),
+									GFP_KERNEL);
+	if (!handle) {
+		nss_warning("%p: handle memory alloc failed\n", nss_ctx);
+		*cmd_rsp = NSS_TX_RX_VIRT_IF_ALLOC_FAILURE;
 		goto error1;
 	}
 
-	handles->whandle = nss_wifi_if_create(netdev);
-	if (!handles->whandle) {
-		nss_warning("%s: nss_wifi_if creation failed\n", __func__);
+	handle->nss_ctx = nss_ctx;
+	handle->if_num = if_num;
+	handle->pvt = (struct nss_tx_rx_virt_if_pvt *)kzalloc(sizeof(struct nss_tx_rx_virt_if_pvt),
+								GFP_KERNEL);
+	if (!handle->pvt) {
+		nss_warning("%p: failure allocating memory for nss_tx_rx_virt_if_pvt\n", nss_ctx);
+		*cmd_rsp = NSS_TX_RX_VIRT_IF_ALLOC_FAILURE;
 		goto error2;
 	}
 
-	handles->vhandle = nss_virt_if_create(netdev);
-	if (!handles->vhandle) {
-		nss_warning("%s: nss_virt_if creation failed\n", __func__);
-		goto error3;
-	}
+	handle->cb = NULL;
+	handle->app_data = NULL;
 
-	return (void *)handles;
-error3:
-	nss_wifi_if_destroy(handles->whandle);
+	spin_lock_bh(&nss_tx_rx_virt_if_lock);
+	nss_tx_rx_virt_if_handles[index] = handle;
+	spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+
+	*cmd_rsp = NSS_VIRT_IF_SUCCESS;
+
+	return handle;
+
 error2:
-	kfree(handles);
+	kfree(handle);
 error1:
 	return NULL;
 }
 
 /*
+ * nss_tx_rx_virt_if_register_handler_sync()
+ * 	register msg handler for redir interface and initialize semaphore and completion.
+ */
+static uint32_t nss_tx_rx_virt_if_register_handler(struct nss_tx_rx_virt_if_handle *handle)
+{
+	uint32_t ret;
+	struct nss_tx_rx_virt_if_pvt *nrip = NULL;
+	int32_t if_num = handle->if_num;
+
+	ret = nss_core_register_handler(if_num, nss_tx_rx_virt_if_msg_handler, NULL);
+	if (ret != NSS_CORE_STATUS_SUCCESS) {
+		nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
+		return NSS_TX_RX_VIRT_IF_CORE_FAILURE;
+	}
+
+	nrip = handle->pvt;
+	if (!nrip->sem_init_done) {
+		sema_init(&nrip->sem, 1);
+		init_completion(&nrip->complete);
+		nrip->sem_init_done = 1;
+	}
+
+	return NSS_TX_RX_VIRT_IF_SUCCESS;
+}
+
+/*
+ * nss_tx_rx_virt_if_tx_msg()
+ */
+nss_tx_status_t nss_tx_rx_virt_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_tx_rx_virt_if_msg *nrim)
+{
+	int32_t status;
+	struct sk_buff *nbuf;
+	struct nss_cmn_msg *ncm = &nrim->cm;
+	struct nss_tx_rx_virt_if_msg *nrim2;
+
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("Interface could not be created as core not ready");
+		return NSS_TX_FAILURE;
+	}
+
+	/*
+	 * Sanity check the message
+	 */
+	if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
+		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
+		return NSS_TX_FAILURE;
+	}
+
+	if (ncm->type > NSS_TX_RX_VIRT_IF_MAX_MSG_TYPES) {
+		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
+		return NSS_TX_FAILURE;
+	}
+
+	if (ncm->len > sizeof(struct nss_tx_rx_virt_if_msg)) {
+		nss_warning("%p: invalid length: %d. Length of redir msg is %d",
+				nss_ctx, ncm->len, sizeof(struct nss_tx_rx_virt_if_msg));
+		return NSS_TX_FAILURE;
+	}
+
+	nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
+	if (unlikely(!nbuf)) {
+		NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
+		nss_warning("%p: redir interface %d: command allocation failed", nss_ctx, ncm->interface);
+		return NSS_TX_FAILURE;
+	}
+
+	nrim2 = (struct nss_tx_rx_virt_if_msg *)skb_put(nbuf, sizeof(struct nss_tx_rx_virt_if_msg));
+	memcpy(nrim2, nrim, sizeof(struct nss_tx_rx_virt_if_msg));
+
+	status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
+	if (status != NSS_CORE_STATUS_SUCCESS) {
+		dev_kfree_skb_any(nbuf);
+		nss_warning("%p: Unable to enqueue 'virtual interface' command\n", nss_ctx);
+		return NSS_TX_FAILURE;
+	}
+
+	nss_hal_send_interrupt(nss_ctx->nmap,
+				nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit,
+				NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
+
+	/*
+	 * The context returned is the redir interface # which is, essentially, the index into the if_ctx
+	 * array that is holding the net_device pointer
+	 */
+	return NSS_TX_SUCCESS;
+}
+
+/*
+ * nss_tx_rx_virt_if_tx_msg_sync
+ *	Send a message from HLOS to NSS synchronously.
+ */
+static nss_tx_status_t nss_tx_rx_virt_if_tx_msg_sync(struct nss_tx_rx_virt_if_handle *handle,
+							struct nss_tx_rx_virt_if_msg *nvim)
+{
+	nss_tx_status_t status;
+	int ret = 0;
+	struct nss_tx_rx_virt_if_pvt *nrip = handle->pvt;
+	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+
+	down(&nrip->sem);
+
+	status = nss_tx_rx_virt_if_tx_msg(nss_ctx, nvim);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_tx_rx_virt_if_msg failed\n", nss_ctx);
+		up(&nrip->sem);
+		return status;
+	}
+
+	ret = wait_for_completion_timeout(&nrip->complete,
+						msecs_to_jiffies(NSS_TX_RX_VIRT_IF_TX_TIMEOUT));
+	if (!ret) {
+		nss_warning("%p: redir_if tx failed due to timeout\n", nss_ctx);
+		nrip->response = NSS_TX_FAILURE;
+	}
+
+	status = nrip->response;
+	up(&nrip->sem);
+
+	return status;
+}
+
+/*
+ * nss_tx_rx_virt_if_handle_destroy()
+ *	Destroy the redir handle either due to request from user or due to error, synchronously.
+ */
+static int nss_tx_rx_virt_if_handle_destroy(struct nss_tx_rx_virt_if_handle *handle)
+{
+	nss_tx_status_t status;
+	int32_t if_num = handle->if_num;
+	int32_t index = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
+	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+
+	status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
+		return status;
+	}
+
+	spin_lock_bh(&nss_tx_rx_virt_if_lock);
+	nss_tx_rx_virt_if_handles[index] = NULL;
+	spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+
+	kfree(handle->pvt);
+	kfree(handle);
+
+	return status;
+}
+
+/*
+ * nss_create_virt_if()
+ *	Create a virtual interface synchronously.
+ */
+void *nss_create_virt_if(struct net_device *netdev)
+{
+	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
+	struct nss_tx_rx_virt_if_msg nrim;
+	struct nss_tx_rx_virt_if_create_msg *nrcm;
+	uint32_t ret;
+	struct nss_tx_rx_virt_if_handle *handle = NULL;
+	int32_t if_num;
+
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
+		return NULL;
+	}
+
+	if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
+	if (if_num < 0) {
+		nss_warning("%p: failure allocating redir if\n", nss_ctx);
+		return NULL;
+	}
+
+	handle = nss_tx_rx_virt_if_handle_create(nss_ctx, if_num, &ret);
+	if (!handle) {
+		nss_warning("%p:redir_if handle creation failed ret %d\n", nss_ctx, ret);
+		nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
+		return NULL;
+	}
+
+	/* Initializes the semaphore and also sets the msg handler for if_num */
+	ret = nss_tx_rx_virt_if_register_handler(handle);
+	if (ret != NSS_VIRT_IF_SUCCESS) {
+		nss_warning("%p: Registration handler failed reason: %d\n", nss_ctx, ret);
+		goto error;
+	}
+
+	nss_tx_rx_virt_if_msg_init(&nrim, handle->if_num, NSS_TX_RX_VIRT_IF_TX_CREATE_MSG,
+				sizeof(struct nss_tx_rx_virt_if_create_msg), nss_tx_rx_virt_if_callback, handle);
+
+	nrcm = &nrim.msg.if_create;
+	nrcm->flags = 0;
+	memcpy(nrcm->mac_addr, netdev->dev_addr, ETH_ALEN);
+
+	ret = nss_tx_rx_virt_if_tx_msg_sync(handle, &nrim);
+	if (ret != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_tx_rx_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
+		goto error;
+	}
+
+	spin_lock_bh(&nss_top_main.lock);
+	if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
+		nss_top_main.subsys_dp_register[handle->if_num].ndev = netdev;
+	}
+	spin_unlock_bh(&nss_top_main.lock);
+
+	/*
+	 * Hold a reference to the net_device
+	 */
+	dev_hold(netdev);
+
+	/*
+	 * The context returned is the handle interface # which contains all the info related to
+	 * the interface if_num.
+	 */
+
+	return (void*)handle;
+
+error:
+	nss_tx_rx_virt_if_handle_destroy(handle);
+	return NULL;
+}
+
+/*
  * nss_destroy_virt_if()
+ *	Destroy a virtual interface synchronously.
  */
 nss_tx_status_t nss_destroy_virt_if(void *ctx)
 {
-	struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
+	struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
+	nss_tx_status_t status;
+	struct net_device *dev;
+	int32_t if_num;
+	struct nss_ctx_instance *nss_ctx;
+	uint32_t ret;
 
-	nss_wifi_if_destroy(handle->whandle);
-	nss_virt_if_destroy(handle->vhandle);
+	if (!handle) {
+		nss_warning("handle is NULL\n");
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
 
-	return NSS_TX_SUCCESS;
+	if_num = handle->if_num;
+	nss_ctx = handle->nss_ctx;
+
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
+		return NSS_TX_FAILURE_NOT_READY;
+	}
+
+	spin_lock_bh(&nss_top_main.lock);
+	if (!nss_top_main.subsys_dp_register[if_num].ndev) {
+		spin_unlock_bh(&nss_top_main.lock);
+		nss_warning("%p: Unregister redir interface %d: no context\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	dev = nss_top_main.subsys_dp_register[if_num].ndev;
+	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+	spin_unlock_bh(&nss_top_main.lock);
+	dev_put(dev);
+
+	status = nss_tx_rx_virt_if_handle_destroy(handle);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: handle destroy failed for if_num %d\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE;
+	}
+
+	ret = nss_core_unregister_handler(if_num);
+	if (ret != NSS_CORE_STATUS_SUCCESS) {
+		nss_warning("%p: Not able to unregister handler for redir_if interface %d with NSS core\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	return status;
+}
+
+/*
+ * nss_tx_rx_virt_if_copy_stats()
+ *	Copy stats from the redir_if handle to buffer(line)
+ */
+int32_t nss_tx_rx_virt_if_copy_stats(int32_t if_num, int i, char *line)
+{
+	int32_t bytes = 0;
+	struct nss_tx_rx_virt_if_stats *stats;
+	int32_t ifnum;
+	uint32_t len = 80;
+	struct nss_tx_rx_virt_if_handle *handle = NULL;
+
+	if (if_num < 0) {
+		nss_warning("invalid if_num\n");
+		return 0;
+	}
+
+	ifnum = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
+
+	spin_lock_bh(&nss_tx_rx_virt_if_lock);
+	if (!nss_tx_rx_virt_if_handles[ifnum]) {
+		spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+		goto end;
+	}
+
+	handle = nss_tx_rx_virt_if_handles[ifnum];
+	spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+
+	stats = &handle->stats;
+
+	switch (i) {
+	case 0:
+		bytes = scnprintf(line, len, "rx_packets=%d\n",
+					stats->node_stats.rx_packets);
+		break;
+
+	case 1:
+		bytes = scnprintf(line, len, "rx_bytes=%d\n",
+					stats->node_stats.rx_bytes);
+		break;
+
+	case 2:
+		bytes = scnprintf(line, len, "rx_dropped=%d\n",
+					stats->node_stats.rx_dropped);
+		break;
+
+	case 3:
+		bytes = scnprintf(line, len, "tx_packets=%d\n",
+					stats->node_stats.tx_packets);
+		break;
+
+	case 4:
+		bytes = scnprintf(line, len, "tx_bytes=%d\n",
+					stats->node_stats.tx_bytes);
+		break;
+
+	case 5:
+		bytes = scnprintf(line, len, "tx_enqueue_failed=%d\n",
+						stats->tx_enqueue_failed);
+		break;
+
+	case 6:
+		bytes = scnprintf(line, len, "shaper_enqueue_failed=%d\n",
+						stats->shaper_enqueue_failed);
+		break;
+	}
+
+end:
+	return bytes;
 }
 
 EXPORT_SYMBOL(nss_tx_virt_if_rxbuf);
@@ -147,4 +725,3 @@
 EXPORT_SYMBOL(nss_destroy_virt_if);
 EXPORT_SYMBOL(nss_register_virt_if);
 EXPORT_SYMBOL(nss_unregister_virt_if);
-
diff --git a/nss_virt_if.c b/nss_virt_if.c
index 9b53f8d..92b80e8 100644
--- a/nss_virt_if.c
+++ b/nss_virt_if.c
@@ -23,19 +23,19 @@
 #include <net/arp.h>
 
 #define NSS_VIRT_IF_TX_TIMEOUT			3000 /* 3 Seconds */
-#define NSS_VIRT_IF_INDEX_OFFSET(if_num)	(if_num-NSS_DYNAMIC_IF_START)
+#define NSS_VIRT_IF_GET_INDEX(if_num)	(if_num-NSS_DYNAMIC_IF_START)
 
 extern int nss_ctl_redirect;
 
 /*
  * Data structure that holds the virtual interface context.
  */
-static struct nss_virt_if_handle *virt_handle[NSS_MAX_DYNAMIC_INTERFACES];
+static struct nss_virt_if_handle *nss_virt_if_handle_t[NSS_MAX_DYNAMIC_INTERFACES];
 
 /*
  * Spinlock to protect the global data structure virt_handle.
  */
-DEFINE_SPINLOCK(virt_if_lock);
+DEFINE_SPINLOCK(nss_virt_if_lock);
 
 /*
  * nss_virt_if_stats_sync()
@@ -84,23 +84,22 @@
 		return nss_if_msg_handler(nss_ctx, ncm, app_data);
 	}
 
-	if (((!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) &&
-		(!NSS_IS_IF_TYPE(VIRTUAL, ncm->interface)))) {
+	if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
 		nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
 		return;
 	}
 
-	if_num = NSS_VIRT_IF_INDEX_OFFSET(ncm->interface);
+	if_num = NSS_VIRT_IF_GET_INDEX(ncm->interface);
 
-	spin_lock_bh(&virt_if_lock);
-	if (!virt_handle[if_num]) {
-		spin_unlock_bh(&virt_if_lock);
+	spin_lock_bh(&nss_virt_if_lock);
+	if (!nss_virt_if_handle_t[if_num]) {
+		spin_unlock_bh(&nss_virt_if_lock);
 		nss_warning("%p: virt_if handle is NULL\n", nss_ctx);
 		return;
 	}
 
-	handle = virt_handle[if_num];
-	spin_unlock_bh(&virt_if_lock);
+	handle = nss_virt_if_handle_t[if_num];
+	spin_unlock_bh(&nss_virt_if_lock);
 
 	switch (nvim->cm.type) {
 	case NSS_VIRT_IF_STATS_SYNC_MSG:
@@ -157,6 +156,586 @@
 }
 
 /*
+ * nss_virt_if_tx_msg_sync
+ *	Send a message from HLOS to NSS synchronously.
+ */
+static nss_tx_status_t nss_virt_if_tx_msg_sync(struct nss_virt_if_handle *handle,
+							struct nss_virt_if_msg *nvim)
+{
+	nss_tx_status_t status;
+	int ret = 0;
+	struct nss_virt_if_pvt *nwip = handle->pvt;
+	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+
+	down(&nwip->sem);
+
+	status = nss_virt_if_tx_msg(nss_ctx, nvim);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_virt_if_msg failed\n", nss_ctx);
+		up(&nwip->sem);
+		return status;
+	}
+
+	ret = wait_for_completion_timeout(&nwip->complete,
+						msecs_to_jiffies(NSS_VIRT_IF_TX_TIMEOUT));
+	if (!ret) {
+		nss_warning("%p: virt_if tx failed due to timeout\n", nss_ctx);
+		nwip->response = NSS_TX_FAILURE;
+	}
+
+	status = nwip->response;
+	up(&nwip->sem);
+
+	return status;
+}
+
+/*
+ * nss_virt_if_msg_init()
+ *	Initialize virt specific message structure.
+ */
+static void nss_virt_if_msg_init(struct nss_virt_if_msg *nvim,
+					uint16_t if_num,
+					uint32_t type,
+					uint32_t len,
+					nss_virt_if_msg_callback_t cb,
+					struct nss_virt_if_handle *app_data)
+{
+	nss_cmn_msg_init(&nvim->cm, if_num, type, len, (void *)cb, (void *)app_data);
+}
+
+/*
+ * nss_virt_if_register_handler()
+ * 	register msg handler for virtual interface.
+ */
+static uint32_t nss_virt_if_register_handler(struct nss_virt_if_handle *handle)
+{
+	uint32_t ret;
+	int32_t if_num = handle->if_num;
+
+	ret = nss_core_register_handler(if_num, nss_virt_if_msg_handler, NULL);
+	if (ret != NSS_CORE_STATUS_SUCCESS) {
+		nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
+		return NSS_VIRT_IF_CORE_FAILURE;
+	}
+
+	return NSS_VIRT_IF_SUCCESS;
+}
+
+/*
+ * nss_virt_if_handle_destroy_cb()
+ *	Callback to handle the response of destroy message.
+ */
+static void nss_virt_if_handle_destroy_cb(void *app_data, struct nss_dynamic_interface_msg *ndim)
+{
+	nss_virt_if_msg_callback_t cb;
+	void *data;
+	uint32_t index;
+	struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)app_data;
+
+	cb = handle->cb;
+	data = handle->app_data;
+
+	if (ndim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("%p: Received NACK from DI\n", handle->nss_ctx);
+		goto callback;
+	}
+
+	index = NSS_VIRT_IF_GET_INDEX(handle->if_num);
+	spin_lock_bh(&nss_virt_if_lock);
+	nss_virt_if_handle_t[index] = NULL;
+	spin_unlock_bh(&nss_virt_if_lock);
+
+	kfree(handle);
+callback:
+	if (!cb) {
+		nss_warning("callback is NULL\n");
+		return;
+	}
+
+	cb(data, &ndim->cm);
+}
+
+/*
+ * nss_virt_if_handle_destroy()
+ *	Destroy the virt handle either due to request from WLAN or due to error.
+ */
+static int nss_virt_if_handle_destroy(struct nss_virt_if_handle *handle)
+{
+	nss_tx_status_t status;
+	int32_t if_num = handle->if_num;
+	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+	struct nss_dynamic_interface_msg ndim;
+	struct nss_dynamic_interface_dealloc_node_msg *ndid;
+
+	nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,
+				sizeof(struct nss_dynamic_interface_dealloc_node_msg), nss_virt_if_handle_destroy_cb, (void *)handle);
+
+	ndid = &ndim.msg.dealloc_node;
+	ndid->type = NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR;
+	ndid->if_num = if_num;
+
+	/*
+	 * Send an asynchronous message to the firmware.
+	 */
+	status = nss_dynamic_interface_tx(nss_ctx, &ndim);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
+		return status;
+	}
+
+	return status;
+}
+
+/*
+ * nss_virt_if_handle_destroy_sync()
+ *	Destroy the virt handle either due to request from user or due to error, synchronously.
+ */
+static int nss_virt_if_handle_destroy_sync(struct nss_virt_if_handle *handle)
+{
+	nss_tx_status_t status;
+	int32_t if_num = handle->if_num;
+	int32_t index = NSS_VIRT_IF_GET_INDEX(if_num);
+	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+
+	status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
+		return status;
+	}
+
+	spin_lock_bh(&nss_virt_if_lock);
+	nss_virt_if_handle_t[index] = NULL;
+	spin_unlock_bh(&nss_virt_if_lock);
+
+	kfree(handle->pvt);
+	kfree(handle);
+
+	return status;
+}
+
+/*
+ * nss_virt_if_handle_create_cb()
+ *	Callback to handle the response from dynamic interface for an alloc node msg.
+ */
+static void nss_virt_if_handle_create_cb(void *app_data, struct nss_dynamic_interface_msg *ndim)
+{
+	struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)app_data;
+	nss_virt_if_msg_callback_t cb;
+	struct nss_virt_if_msg nvim;
+	struct nss_virt_if_create_msg *nvcm;
+	void *data;
+	int32_t if_num;
+	uint32_t index;
+	int ret;
+
+	cb = handle->cb;
+	data = handle->app_data;
+
+	if (ndim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("%p: received NACK from NSS %d\n", handle->nss_ctx, ndim->cm.response);
+		kfree(handle);
+		goto fail;
+	}
+
+	if_num = ndim->msg.alloc_node.if_num;
+
+	spin_lock_bh(&nss_virt_if_lock);
+	handle->if_num = if_num;
+	index = NSS_VIRT_IF_GET_INDEX(if_num);
+	nss_virt_if_handle_t[index] = handle;
+	spin_unlock_bh(&nss_virt_if_lock);
+
+	/* Register the msg handler for if_num */
+	ret = nss_virt_if_register_handler(handle);
+	if (ret != NSS_VIRT_IF_SUCCESS) {
+		nss_warning("%p: Registration handler failed reason: %d\n", handle->nss_ctx, ret);
+		nss_virt_if_handle_destroy(handle);
+		goto fail;
+	}
+
+	/*
+	 * Send virt_if message to the Firmware to copy the netdev's macaddr
+	 */
+	nss_virt_if_msg_init(&nvim, handle->if_num, NSS_VIRT_IF_TX_CREATE_MSG,
+				sizeof(struct nss_virt_if_create_msg), NULL, NULL);
+
+	nvcm = &nvim.msg.if_create;
+	nvcm->flags = 0;
+	memcpy(nvcm->mac_addr, handle->ndev->dev_addr, ETH_ALEN);
+
+	ret = nss_virt_if_tx_msg(handle->nss_ctx, &nvim);
+	if (ret != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_virt_if_tx_msg failed %u\n", handle->nss_ctx, ret);
+		nss_virt_if_handle_destroy(handle);
+		goto fail;
+	}
+
+	spin_lock_bh(&nss_top_main.lock);
+	if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
+		nss_top_main.subsys_dp_register[handle->if_num].ndev = handle->ndev;
+	}
+	spin_unlock_bh(&nss_top_main.lock);
+
+	/*
+	 * Hold a reference to the net_device
+	 */
+	dev_hold(handle->ndev);
+
+	/*
+	 * The context returned is the handle which contains all the info related to
+	 * the interface if_num.
+	 */
+
+fail:
+	if (!cb) {
+		nss_warning("cb is NULL\n");
+		return;
+	}
+
+	cb(data, &ndim->cm);
+}
+
+/*
+ * nss_virt_if_handle_create()
+ *	Create and initialize virt_if handle.
+ */
+static struct nss_virt_if_handle *nss_virt_if_handle_create(struct nss_ctx_instance *nss_ctx,
+							struct net_device *ndev,
+							nss_virt_if_msg_callback_t cb,
+							void *app_data,
+							int *cmd_rsp)
+{
+	struct nss_virt_if_handle *handle;
+
+	handle = (struct nss_virt_if_handle *)kzalloc(sizeof(struct nss_virt_if_handle),
+									GFP_ATOMIC);
+	if (!handle) {
+		nss_warning("%p: handle memory alloc failed\n", nss_ctx);
+		*cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
+		goto error;
+	}
+
+	/*
+	 * Save the callback & appdata of the user. The callback will be invoked from
+	 * nss_virt_if_handle_create_cb.
+	 */
+	handle->nss_ctx = nss_ctx;
+	handle->ndev = ndev;
+	handle->cb = cb;
+	handle->app_data = app_data;
+
+	*cmd_rsp = NSS_VIRT_IF_SUCCESS;
+
+	return handle;
+
+error:
+	return NULL;
+}
+
+/*
+ * nss_virt_if_handle_create_sync()
+ *	Initialize virt handle which holds the if_num and stats per interface.
+ */
+static struct nss_virt_if_handle *nss_virt_if_handle_create_sync(struct nss_ctx_instance *nss_ctx, int32_t if_num, int32_t *cmd_rsp)
+{
+	int32_t index;
+	struct nss_virt_if_handle *handle;
+
+	index = NSS_VIRT_IF_GET_INDEX(if_num);
+
+	handle = (struct nss_virt_if_handle *)kzalloc(sizeof(struct nss_virt_if_handle),
+									GFP_KERNEL);
+	if (!handle) {
+		nss_warning("%p: handle memory alloc failed\n", nss_ctx);
+		*cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
+		goto error1;
+	}
+
+	handle->nss_ctx = nss_ctx;
+	handle->if_num = if_num;
+	handle->pvt = (struct nss_virt_if_pvt *)kzalloc(sizeof(struct nss_virt_if_pvt),
+								GFP_KERNEL);
+	if (!handle->pvt) {
+		nss_warning("%p: failure allocating memory for nss_virt_if_pvt\n", nss_ctx);
+		*cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
+		goto error2;
+	}
+
+	handle->cb = NULL;
+	handle->app_data = NULL;
+
+	spin_lock_bh(&nss_virt_if_lock);
+	nss_virt_if_handle_t[index] = handle;
+	spin_unlock_bh(&nss_virt_if_lock);
+
+	*cmd_rsp = NSS_VIRT_IF_SUCCESS;
+
+	return handle;
+
+error2:
+	kfree(handle);
+error1:
+	return NULL;
+}
+
+/*
+ * nss_virt_if_register_handler_sync()
+ * 	register msg handler for virtual interface and initialize semaphore and completion.
+ */
+static uint32_t nss_virt_if_register_handler_sync(struct nss_virt_if_handle *handle)
+{
+	uint32_t ret;
+	struct nss_virt_if_pvt *nvip = NULL;
+	int32_t if_num = handle->if_num;
+
+	ret = nss_core_register_handler(if_num, nss_virt_if_msg_handler, NULL);
+	if (ret != NSS_CORE_STATUS_SUCCESS) {
+		nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
+		return NSS_VIRT_IF_CORE_FAILURE;
+	}
+
+	nvip = handle->pvt;
+	if (!nvip->sem_init_done) {
+		sema_init(&nvip->sem, 1);
+		init_completion(&nvip->complete);
+		nvip->sem_init_done = 1;
+	}
+
+	return NSS_VIRT_IF_SUCCESS;
+}
+
+/*
+ * nss_virt_if_create()
+ *	Create a virtual interface and associate it with the netdev, asynchronously.
+ */
+int nss_virt_if_create(struct net_device *netdev, nss_virt_if_msg_callback_t cb, void *app_data)
+{
+	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
+	struct nss_dynamic_interface_msg ndim;
+	struct nss_dynamic_interface_alloc_node_msg *ndia;
+	int ret;
+	struct nss_virt_if_handle *handle = NULL;
+
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
+		return NSS_VIRT_IF_CORE_FAILURE;
+	}
+
+	/*
+	 * Create the virt_if handle and associate the cb and app_data with it.
+	 */
+	handle = nss_virt_if_handle_create(nss_ctx, netdev, cb, app_data, &ret);
+	if (!handle) {
+		nss_warning("%p:virt_if handle create failed ret %d\n", nss_ctx, ret);
+		return ret;
+	}
+
+	ndia = &ndim.msg.alloc_node;
+	ndia->type = NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR;
+
+	/*
+	 * Construct a dynamic interface message and send it to the firmware.
+	 */
+	nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_ALLOC_NODE,
+				sizeof(struct nss_dynamic_interface_alloc_node_msg), nss_virt_if_handle_create_cb, (void *)handle);
+
+	ret = nss_dynamic_interface_tx(nss_ctx, &ndim);
+	if (ret != NSS_TX_SUCCESS) {
+		nss_warning("%p: failure allocating virt if\n", nss_ctx);
+		ret = NSS_VIRT_IF_DYNAMIC_IF_FAILURE;
+		kfree(handle);
+		return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(nss_virt_if_create);
+
+/*
+ * nss_virt_if_create_sync()
+ *	Create a virt interface, synchronously and associate it with the netdev
+ */
+struct nss_virt_if_handle *nss_virt_if_create_sync(struct net_device *netdev)
+{
+	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
+	struct nss_virt_if_msg nvim;
+	struct nss_virt_if_create_msg *nvcm;
+	uint32_t ret;
+	struct nss_virt_if_handle *handle = NULL;
+	int32_t if_num;
+
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
+		return NULL;
+	}
+
+	if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
+	if (if_num < 0) {
+		nss_warning("%p: failure allocating virt if\n", nss_ctx);
+		return NULL;
+	}
+
+	handle = nss_virt_if_handle_create_sync(nss_ctx, if_num, &ret);
+	if (!handle) {
+		nss_warning("%p:virt_if handle creation failed ret %d\n", nss_ctx, ret);
+		nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
+		return NULL;
+	}
+
+	/* Initializes the semaphore and also sets the msg handler for if_num */
+	ret = nss_virt_if_register_handler_sync(handle);
+	if (ret != NSS_VIRT_IF_SUCCESS) {
+		nss_warning("%p: Registration handler failed reason: %d\n", nss_ctx, ret);
+		goto error;
+	}
+
+	nss_virt_if_msg_init(&nvim, handle->if_num, NSS_VIRT_IF_TX_CREATE_MSG,
+				sizeof(struct nss_virt_if_create_msg), nss_virt_if_callback, handle);
+
+	nvcm = &nvim.msg.if_create;
+	nvcm->flags = 0;
+	memcpy(nvcm->mac_addr, netdev->dev_addr, ETH_ALEN);
+
+	ret = nss_virt_if_tx_msg_sync(handle, &nvim);
+	if (ret != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
+		goto error;
+	}
+
+	spin_lock_bh(&nss_top_main.lock);
+	if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
+		nss_top_main.subsys_dp_register[handle->if_num].ndev = netdev;
+	}
+	spin_unlock_bh(&nss_top_main.lock);
+
+	/*
+	 * Hold a reference to the net_device
+	 */
+	dev_hold(netdev);
+
+	/*
+	 * The context returned is the handle interface # which contains all the info related to
+	 * the interface if_num.
+	 */
+
+	return handle;
+
+error:
+	nss_virt_if_handle_destroy_sync(handle);
+	return NULL;
+}
+EXPORT_SYMBOL(nss_virt_if_create_sync);
+
+/*
+ * nss_virt_if_destroy()
+ *	Destroy the virt interface associated with the interface number, by sending
+ * sending an asynchronous message to dynamic interface.
+ */
+nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle, nss_virt_if_msg_callback_t cb, void *app_data)
+{
+	nss_tx_status_t status;
+	struct net_device *dev;
+	int32_t if_num;
+	struct nss_ctx_instance *nss_ctx;
+	uint32_t ret;
+
+	if (!handle) {
+		nss_warning("handle is NULL\n");
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	if_num = handle->if_num;
+	nss_ctx = handle->nss_ctx;
+	handle->cb = cb;
+	handle->app_data = app_data;
+
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
+		return NSS_TX_FAILURE_NOT_READY;
+	}
+
+	spin_lock_bh(&nss_top_main.lock);
+	if (!nss_top_main.subsys_dp_register[if_num].ndev) {
+		spin_unlock_bh(&nss_top_main.lock);
+		nss_warning("%p: Unregister virt interface %d: no context\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	dev = nss_top_main.subsys_dp_register[if_num].ndev;
+	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+	spin_unlock_bh(&nss_top_main.lock);
+	dev_put(dev);
+
+	status = nss_virt_if_handle_destroy(handle);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: handle destroy tx failed %d\n", nss_ctx, status);
+		return NSS_TX_FAILURE;
+	}
+
+	ret = nss_core_unregister_handler(if_num);
+	if (ret != NSS_CORE_STATUS_SUCCESS) {
+		nss_warning("Not able to unregister handler for virt_if interface %d with NSS core\n", if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	return status;
+}
+EXPORT_SYMBOL(nss_virt_if_destroy);
+
+/*
+ * nss_virt_if_destroy_sync()
+ *	Destroy the virt interface associated with the interface number, synchronously.
+ */
+nss_tx_status_t nss_virt_if_destroy_sync(struct nss_virt_if_handle *handle)
+{
+	nss_tx_status_t status;
+	struct net_device *dev;
+	int32_t if_num;
+	struct nss_ctx_instance *nss_ctx;
+	uint32_t ret;
+
+	if (!handle) {
+		nss_warning("handle is NULL\n");
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	if_num = handle->if_num;
+	nss_ctx = handle->nss_ctx;
+
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
+		return NSS_TX_FAILURE_NOT_READY;
+	}
+
+	spin_lock_bh(&nss_top_main.lock);
+	if (!nss_top_main.subsys_dp_register[if_num].ndev) {
+		spin_unlock_bh(&nss_top_main.lock);
+		nss_warning("%p: Unregister virt interface %d: no context\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	dev = nss_top_main.subsys_dp_register[if_num].ndev;
+	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+	spin_unlock_bh(&nss_top_main.lock);
+	dev_put(dev);
+
+	status = nss_virt_if_handle_destroy_sync(handle);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: handle destroy failed for if_num %d\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE;
+	}
+
+	ret = nss_core_unregister_handler(if_num);
+	if (ret != NSS_CORE_STATUS_SUCCESS) {
+		nss_warning("%p: Not able to unregister handler for virt_if interface %d with NSS core\n", nss_ctx, if_num);
+		return NSS_TX_FAILURE_BAD_PARAM;
+	}
+
+	return status;
+}
+EXPORT_SYMBOL(nss_virt_if_destroy_sync);
+
+/*
  * nss_virt_if_tx_buf()
  *	HLOS interface has received a packet which we redirect to the NSS, if appropriate to do so.
  */
@@ -175,7 +754,7 @@
 		return NSS_TX_FAILURE_NOT_SUPPORTED;
 	}
 
-	nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num) || NSS_IS_IF_TYPE(VIRTUAL, if_num));
+	nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num));
 	nss_trace("%p: Virtual Rx packet, if_num:%d, skb:%p", nss_ctx, if_num, skb);
 
 	/*
@@ -226,268 +805,6 @@
 EXPORT_SYMBOL(nss_virt_if_tx_buf);
 
 /*
- * nss_virt_if_tx_msg_sync
- *	Send a message from HLOS to NSS synchronously.
- */
-static nss_tx_status_t nss_virt_if_tx_msg_sync(struct nss_virt_if_handle *handle,
-							struct nss_virt_if_msg *nvim)
-{
-	nss_tx_status_t status;
-	int ret = 0;
-	struct nss_virt_if_pvt *nwip = handle->pvt;
-	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
-
-	down(&nwip->sem);
-
-	status = nss_virt_if_tx_msg(nss_ctx, nvim);
-	if (status != NSS_TX_SUCCESS) {
-		nss_warning("%p: nss_virt_if_msg failed\n", nss_ctx);
-		up(&nwip->sem);
-		return status;
-	}
-
-	ret = wait_for_completion_timeout(&nwip->complete,
-						msecs_to_jiffies(NSS_VIRT_IF_TX_TIMEOUT));
-	if (!ret) {
-		nss_warning("%p: virt_if tx failed due to timeout\n", nss_ctx);
-		nwip->response = NSS_TX_FAILURE;
-	}
-
-	status = nwip->response;
-	up(&nwip->sem);
-
-	return status;
-}
-
-/*
- * nss_virt_if_handle_destroy()
- *	Destroy the virt handle either due to request from WLAN or due to error.
- */
-static int nss_virt_if_handle_destroy(struct nss_virt_if_handle *handle)
-{
-	nss_tx_status_t status;
-	int32_t if_num = handle->if_num;
-	int32_t index = NSS_VIRT_IF_INDEX_OFFSET(if_num);
-	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
-
-	spin_lock_bh(&virt_if_lock);
-	virt_handle[index] = NULL;
-	spin_unlock_bh(&virt_if_lock);
-
-	status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
-	if (status != NSS_TX_SUCCESS) {
-		nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
-		return status;
-	}
-
-	kfree(handle->pvt);
-	kfree(handle);
-
-	return status;
-}
-
-/*
- * nss_virt_if_handle_init()
- *	Initialize virt handle which holds the if_num and stats per interface.
- */
-static struct nss_virt_if_handle *nss_virt_if_handle_create(struct nss_ctx_instance *nss_ctx, int32_t *cmd_rsp)
-{
-	int32_t index;
-	int32_t if_num = 0;
-	struct nss_virt_if_handle *handle;
-
-	if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
-	if (if_num < 0) {
-		nss_warning("%p: failure allocating virt if\n", nss_ctx);
-		*cmd_rsp = NSS_VIRT_IF_DYNAMIC_IF_FAILURE;
-		return NULL;
-	}
-
-	index = NSS_VIRT_IF_INDEX_OFFSET(if_num);
-
-	handle = (struct nss_virt_if_handle *)kzalloc(sizeof(struct nss_virt_if_handle),
-									GFP_KERNEL);
-	if (!handle) {
-		nss_warning("%p: handle memory alloc failed\n", nss_ctx);
-		*cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
-		goto error1;
-	}
-
-	handle->nss_ctx = nss_ctx;
-	handle->if_num = if_num;
-	handle->pvt = (struct nss_virt_if_pvt *)kzalloc(sizeof(struct nss_virt_if_pvt),
-								GFP_KERNEL);
-	if (!handle->pvt) {
-		nss_warning("%p: failure allocating memory for nss_virt_if_pvt\n", nss_ctx);
-		*cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
-		goto error2;
-	}
-
-	handle->cb = NULL;
-	handle->app_data = NULL;
-
-	spin_lock_bh(&virt_if_lock);
-	virt_handle[index] = handle;
-	spin_unlock_bh(&virt_if_lock);
-
-	*cmd_rsp = NSS_VIRT_IF_SUCCESS;
-
-	return handle;
-
-error2:
-	kfree(handle);
-error1:
-	nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
-	return NULL;
-}
-
-/* nss_virt_if_msg_init()
- *	Initialize virt specific message structure.
- */
-static void nss_virt_if_msg_init(struct nss_virt_if_msg *nvim,
-					uint16_t if_num,
-					uint32_t type,
-					uint32_t len,
-					nss_virt_if_msg_callback_t cb,
-					struct nss_virt_if_handle *app_data)
-{
-	nss_cmn_msg_init(&nvim->cm, if_num, type, len, (void *)cb, (void *)app_data);
-}
-
-/*
- * nss_virt_if_register_handler()
- * 	register handler for statically allocated virtual interface on NSS with NSS core.
- */
-static uint32_t nss_virt_if_register_handler(struct nss_virt_if_handle *handle)
-{
-	uint32_t ret;
-	struct nss_virt_if_pvt *nvip = NULL;
-	int32_t if_num = handle->if_num;
-
-	ret = nss_core_register_handler(if_num, nss_virt_if_msg_handler, NULL);
-	if (ret != NSS_CORE_STATUS_SUCCESS) {
-		nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
-		return NSS_VIRT_IF_CORE_FAILURE;
-	}
-
-	nvip = handle->pvt;
-	if (!nvip->sem_init_done) {
-		sema_init(&nvip->sem, 1);
-		init_completion(&nvip->complete);
-		nvip->sem_init_done = 1;
-	}
-
-	return NSS_VIRT_IF_SUCCESS;
-}
-
-/*
- * nss_virt_if_create()
- *	Create a virt interface and associate it with the netdev
- */
-struct nss_virt_if_handle *nss_virt_if_create(struct net_device *netdev)
-{
-	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
-	struct nss_virt_if_msg nvim;
-	struct nss_virt_if_create_msg *nvcm;
-	uint32_t ret;
-	struct nss_virt_if_handle *handle = NULL;
-
-	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
-		nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
-		return NULL;
-	}
-
-	handle = nss_virt_if_handle_create(nss_ctx, &ret);
-	if (!handle) {
-		nss_warning("%p:virt_if handle creation failed ret %d\n", nss_ctx, ret);
-		return NULL;
-	}
-
-	/* Initializes the semaphore and also sets the msg handler for if_num */
-	ret = nss_virt_if_register_handler(handle);
-	if (ret != NSS_VIRT_IF_SUCCESS) {
-		nss_warning("%p: Registration handler failed reason: %d\n", nss_ctx, ret);
-		goto error;
-	}
-
-	nss_virt_if_msg_init(&nvim, handle->if_num, NSS_VIRT_IF_TX_CREATE_MSG,
-				sizeof(struct nss_virt_if_create_msg), nss_virt_if_callback, handle);
-
-	nvcm = &nvim.msg.if_create;
-	nvcm->flags = 0;
-	memcpy(nvcm->mac_addr, netdev->dev_addr, ETH_ALEN);
-
-	ret = nss_virt_if_tx_msg_sync(handle, &nvim);
-	if (ret != NSS_TX_SUCCESS) {
-		nss_warning("%p: nss_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
-		goto error;
-	}
-
-	spin_lock_bh(&nss_top_main.lock);
-	if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
-		nss_top_main.subsys_dp_register[handle->if_num].ndev = netdev;
-	}
-	spin_unlock_bh(&nss_top_main.lock);
-
-	/*
-	 * Hold a reference to the net_device
-	 */
-	dev_hold(netdev);
-
-	/*
-	 * The context returned is the handle interface # which contains all the info related to
-	 * the interface if_num.
-	 */
-
-	return handle;
-
-error:
-	nss_virt_if_handle_destroy(handle);
-	return NULL;
-}
-EXPORT_SYMBOL(nss_virt_if_create);
-
-/*
- * nss_virt_if_destroy()
- *	Destroy the virt interface associated with the interface number.
- */
-nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle)
-{
-	nss_tx_status_t status;
-	struct net_device *dev;
-	int32_t if_num;
-	struct nss_ctx_instance *nss_ctx;
-
-	if (!handle) {
-		nss_warning("nss_virt_if_destroy handle is NULL\n");
-		return NSS_TX_FAILURE_BAD_PARAM;
-	}
-
-	if_num = handle->if_num;
-	nss_ctx = handle->nss_ctx;
-
-	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
-		nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
-		return NSS_TX_FAILURE_NOT_READY;
-	}
-
-	spin_lock_bh(&nss_top_main.lock);
-	if (!nss_top_main.subsys_dp_register[if_num].ndev) {
-		spin_unlock_bh(&nss_top_main.lock);
-		nss_warning("%p: Unregister virt interface %d: no context\n", nss_ctx, if_num);
-		return NSS_TX_FAILURE_BAD_PARAM;
-	}
-
-	dev = nss_top_main.subsys_dp_register[if_num].ndev;
-	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
-	spin_unlock_bh(&nss_top_main.lock);
-	dev_put(dev);
-
-	status = nss_virt_if_handle_destroy(handle);
-	return status;
-}
-EXPORT_SYMBOL(nss_virt_if_destroy);
-/*
  * nss_virt_if_tx_msg()
  */
 nss_tx_status_t nss_virt_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_virt_if_msg *nvim)
@@ -505,7 +822,7 @@
 	/*
 	 * Sanity check the message
 	 */
-	if (((!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) && (!NSS_IS_IF_TYPE(VIRTUAL, ncm->interface)))) {
+	if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
 		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
 		return NSS_TX_FAILURE;
 	}
@@ -560,7 +877,7 @@
 	int32_t if_num;
 
 	if (!handle) {
-		nss_warning("nss_virt_if_register handle is NULL\n");
+		nss_warning("handle is NULL\n");
 		return;
 	}
 
@@ -581,7 +898,7 @@
 	int32_t if_num;
 
 	if (!handle) {
-		nss_warning("nss_virt_if_unregister handle is NULL\n");
+		nss_warning("handle is NULL\n");
 		return;
 	}
 
@@ -609,20 +926,20 @@
 	struct nss_virt_if_handle *handle = NULL;
 
 	if (if_num < 0) {
-		nss_warning("nss_virt_if_copy_stats invalid if_num\n");
-		return bytes;
+		nss_warning("invalid if_num\n");
+		return 0;
 	}
 
-	ifnum = NSS_VIRT_IF_INDEX_OFFSET(if_num);
+	ifnum = NSS_VIRT_IF_GET_INDEX(if_num);
 
-	spin_lock_bh(&virt_if_lock);
-	if (!virt_handle[ifnum]) {
-		spin_unlock_bh(&virt_if_lock);
+	spin_lock_bh(&nss_virt_if_lock);
+	if (!nss_virt_if_handle_t[ifnum]) {
+		spin_unlock_bh(&nss_virt_if_lock);
 		goto end;
 	}
 
-	handle = virt_handle[ifnum];
-	spin_unlock_bh(&virt_if_lock);
+	handle = nss_virt_if_handle_t[ifnum];
+	spin_unlock_bh(&nss_virt_if_lock);
 
 	stats = &handle->stats;
 
@@ -671,10 +988,8 @@
  * nss_virt_if_get_interface_num()
  * Get interface number for a virtual interface
  */
-int32_t nss_virt_if_get_interface_num(void *ctx)
+int32_t nss_virt_if_get_interface_num(struct nss_virt_if_handle *handle)
 {
-	struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)ctx;
-
 	if (!handle) {
 		nss_warning("virt_if handle is NULL\n");
 		return -1;