[qca-nss-drv] Migrate virt_if to dynamic interface

Migrate virt_if to dynamic interfaces and add stats support.

Change-Id: I310fad03a09c496d627b65797d8d9bc4a4d263ba
Signed-off-by: Sundarajan Srinivasan <sundaraj@codeaurora.org>
diff --git a/exports/nss_virt_if.h b/exports/nss_virt_if.h
index f0b51f6..6ea97fd 100644
--- a/exports/nss_virt_if.h
+++ b/exports/nss_virt_if.h
@@ -46,40 +46,107 @@
 	NSS_VIRT_IF_BSHAPER_CONFIG = NSS_IF_BSHAPER_CONFIG,
 	NSS_VIRT_IF_TX_CREATE_MSG = NSS_IF_MAX_MSG_TYPES + 1,
 	NSS_VIRT_IF_TX_DESTROY_MSG,
+	NSS_VIRT_IF_STATS_SYNC_MSG,
 	NSS_VIRT_IF_MAX_MSG_TYPES,
 };
 
 /**
+ * virt_if error types
+ */
+enum nss_virt_if_error_types {
+	NSS_VIRT_IF_SUCCESS,			/*< Success */
+	NSS_VIRT_IF_CORE_FAILURE,		/*< nss core failure */
+	NSS_VIRT_IF_ALLOC_FAILURE,		/*< Memory allocation failure */
+	NSS_VIRT_IF_DYNAMIC_IF_FAILURE,		/*< Dynamic interface failure */
+	NSS_VIRT_IF_MSG_TX_FAILURE,		/*< Message transmission failure */
+	NSS_VIRT_IF_REG_FAILURE,		/*< Registration failure */
+	NSS_VIRT_IF_CORE_NOT_INITIALIZED,	/*< NSS core not intialized */
+};
+
+/**
+ * Structure which contains stats received from NSS.
+ */
+struct nss_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_virt_if_create {
-	uint32_t flags;			/**> Interface flags */
-	uint8_t mac_addr[ETH_ALEN];	/**> MAC address */
+struct nss_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_virt_if_destroy {
-	int32_t reserved;		/**> place holder */
+struct nss_virt_if_destroy_msg {
+	int32_t reserved;		/**< place holder */
 };
 
 /**
  * Message structure to send/receive virtual interface commands
  */
 struct nss_virt_if_msg {
-	struct nss_cmn_msg cm;				/**> Message Header */
+	struct nss_cmn_msg cm;
+				/**< Message Header */
 	union {
 		union nss_if_msgs if_msgs;
-		struct nss_virt_if_create if_create;	/**> Message: create virt if rule */
-		struct nss_virt_if_destroy if_destroy;	/**> Message: destroy virt if rule */
+		struct nss_virt_if_create_msg if_create;
+				/**< Message: create virt if rule */
+		struct nss_virt_if_destroy_msg if_destroy;
+				/**< Message: destroy virt if rule */
+		struct nss_virt_if_stats stats;
+				/**< Message: stats */
 	} msg;
 };
 
+/*
+ * Private data structure for virt_if interface
+ */
+struct nss_virt_if_pvt {
+	struct semaphore sem;
+	struct completion complete;
+	int response;
+	int sem_init_done;
+};
+
 typedef void (*nss_virt_if_data_callback_t)(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi);
 typedef void (*nss_virt_if_msg_callback_t)(void *app_data, struct nss_cmn_msg *msg);
 
 /**
+ * Context for WLAN to NSS communication
+ */
+struct nss_virt_if_handle {
+	struct nss_ctx_instance *nss_ctx;	/*< NSS context */
+	int32_t if_num;				/*< interface number */
+	struct nss_virt_if_pvt *pvt;		/*< Private data structure */
+	struct nss_virt_if_stats stats;		/*< virt_if stats */
+	atomic_t refcnt;			/*< Reference count */
+	nss_virt_if_msg_callback_t cb;		/*< callback */
+	void *app_data;				/*< app_data to be passed to callback */
+};
+
+/**
+ * @brief Create a virtual interface
+ *
+ * @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(struct net_device *netdev);
+
+/**
+ * @brief Destroy the virtual interface associated with the if_num
+ *
+ * @param handle virtual interface handle (provided during dynamic_interface allocation)
+ * @return command Tx status
+ */
+extern nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle);
+
+/**
  * @brief Send message to virtual interface
  *
  * @param nss_ctx NSS context (provided during registration)
@@ -90,35 +157,46 @@
 extern nss_tx_status_t nss_virt_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_virt_if_msg *nvim);
 
 /**
- * @brief Forward virtual interface packets
+ * @brief Forward virtual interface packets to NSS
  *
- * @param nss_ctx NSS context (provided during registration)
- * @param if_num Interface number (provided during dynamic interface allocation)
+ * @param handle virtual interface handle (provided during registration)
  * @param skb HLOS data buffer (sk_buff in Linux)
  *
  * @return command Tx status
  */
-extern nss_tx_status_t nss_virt_if_tx_rxbuf(struct nss_ctx_instance *nss_ctx, int32_t if_num, struct sk_buff *skb);
-
+extern nss_tx_status_t nss_virt_if_tx_buf(struct nss_virt_if_handle *handle,
+						struct sk_buff *skb);
 
 /**
  * @brief Register Virtual Interface with NSS driver
  *
- * @param if_num Interface number (provied during dynamic_interface allocation)
+ * @param handle virtual interface handle(provided during dynamic_interface allocation)
  * @param data_callback Callback handler for virtual data packets
- * @param msg_callback Callback handler for virtual interface messages
- * @param if_ctx netdevice structure of virtual interface
+ * @param netdev netdevice structure associated with WiFi
  *
  * @return command Tx status
  */
-extern struct nss_ctx_instance *nss_virt_if_register(uint32_t if_num, nss_virt_if_data_callback_t data_callback,
-							nss_virt_if_msg_callback_t msg_callback, struct net_device *if_ctx);
+extern void nss_virt_if_register(struct nss_virt_if_handle *handle,
+					nss_virt_if_data_callback_t data_callback,
+					struct net_device *netdev);
 
 
 /**
  * @brief Unregister virtual interface from NSS driver
  *
- * @param if_num Interface number (provied during dynamic_interface allocation)
+ * @param handle virtual interface handle
  */
-void nss_virt_if_unregister(uint32_t if_num);
+extern void nss_virt_if_unregister(struct nss_virt_if_handle *handle);
+
+/**
+ * @brief Get stats for virtual 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_virt_if_copy_stats(int32_t if_num, int i, char *line);
+
 #endif /* __NSS_VIRT_IF_H */
diff --git a/nss_core.h b/nss_core.h
index eaaf67b..35f57ac 100755
--- a/nss_core.h
+++ b/nss_core.h
@@ -670,6 +670,7 @@
 	struct dentry *logs_dentry;	/* NSS FW logs directory */
 	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 nss_ctx_instance nss[NSS_MAX_CORES];
 					/* NSS contexts */
 	/*
diff --git a/nss_stats.c b/nss_stats.c
index 8672b76..71fd9ac 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -1702,6 +1702,87 @@
 }
 
 /*
+ * nss_stats_virt_if_read()
+ *	Read virt_if statistics
+ */
+static ssize_t nss_stats_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_802_3_REDIR)
+			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_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)
@@ -1810,6 +1891,8 @@
 
 NSS_STATS_DECLARE_FILE_OPERATIONS(wifi_if)
 
+NSS_STATS_DECLARE_FILE_OPERATIONS(virt_if)
+
 /*
  * wifi_stats_ops
  */
@@ -2007,6 +2090,13 @@
 		return;
 	}
 
+	nss_top_main.virt_if_dentry = debugfs_create_file("virt_if", 0400,
+						nss_top_main.stats_dentry, &nss_top_main, &nss_stats_virt_if_ops);
+	if (unlikely(nss_top_main.virt_if_dentry == NULL)) {
+		nss_warning("Failed to create qca-nss-drv/stats/virt_if file in debugfs");
+		return;
+	}
+
 	nss_log_init();
 }
 
diff --git a/nss_tx_rx_common.h b/nss_tx_rx_common.h
index 7beb8e3..94a3c93 100644
--- a/nss_tx_rx_common.h
+++ b/nss_tx_rx_common.h
@@ -60,10 +60,18 @@
 #endif
 
 /*
+ * Handles associated with redir interfaces(virt_if & wifi_if).
+ * 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;
+};
+
+/*
  * CB handlers for variour interfaces
  */
 void nss_phys_if_register_handler(uint32_t if_num);
-extern void nss_virt_if_register_handler(void);
 extern void nss_crypto_register_handler(void);
 extern void nss_ipsec_register_handler(void);
 extern void nss_ipv4_register_handler(void);
diff --git a/nss_tx_rx_virt_if.c b/nss_tx_rx_virt_if.c
index 3779fa2..fc3eb2f 100644
--- a/nss_tx_rx_virt_if.c
+++ b/nss_tx_rx_virt_if.c
@@ -31,17 +31,12 @@
 				nss_virt_if_rx_callback_t rx_callback,
 				struct net_device *netdev)
 {
-	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.ipv4_handler_id];
-	int32_t if_num = (int32_t)ctx;
+	struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
 
-	nss_assert(NSS_IS_IF_TYPE(VIRTUAL, if_num));
+	nss_wifi_if_register(handle->whandle, rx_callback, netdev);
+	nss_virt_if_register(handle->vhandle, rx_callback, netdev);
 
-	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 nss_ctx;
+	return ctx;
 }
 
 /*
@@ -49,102 +44,25 @@
  */
 void nss_unregister_virt_if(void *ctx)
 {
-	int32_t if_num = (int32_t)ctx;
+	struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
 
-	nss_assert(NSS_IS_IF_TYPE(VIRTUAL, 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_wifi_if_unregister(handle->whandle);
+	nss_virt_if_unregister(handle->vhandle);
 }
 
 /*
  * nss_tx_virt_if_recvbuf()
  *	HLOS interface has received a packet which we redirect to the NSS, if appropriate to do so.
  */
-nss_tx_status_t nss_tx_virt_if_recvbuf(void *ctx, struct sk_buff *os_buf, uint32_t nwifi)
+nss_tx_status_t nss_tx_virt_if_recvbuf(void *ctx, struct sk_buff *skb, uint32_t nwifi)
 {
-	int32_t status;
-	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.ipv4_handler_id];
-	int32_t if_num = (int32_t)ctx;
-	uint32_t bufftype;
-	int32_t push_mac_header = 0;
-
-	if (unlikely(nss_ctl_redirect == 0)) {
-		return NSS_TX_FAILURE_NOT_ENABLED;
-	}
-
-	if (unlikely(os_buf->vlan_tci)) {
-		return NSS_TX_FAILURE_NOT_SUPPORTED;
-	}
-
-	nss_assert(NSS_IS_IF_TYPE(VIRTUAL, if_num));
-	nss_trace("%p: Virtual Rx packet, if_num:%d, skb:%p", nss_ctx, if_num, os_buf);
-
-	/*
-	 * 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(os_buf->len <= ETH_HLEN)) {
-		nss_warning("%p: Virtual Rx packet: %p too short", nss_ctx, os_buf);
-		return NSS_TX_FAILURE_TOO_SHORT;
-	}
-
-	if (unlikely(skb_shinfo(os_buf)->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, os_buf);
-		return NSS_TX_FAILURE_NOT_SUPPORTED;
-	}
+	struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
 
 	if (nwifi) {
-		bufftype = H2N_BUFFER_NATIVE_WIFI;
+		return nss_wifi_if_tx_buf(handle->whandle, skb);
 	} else {
-		bufftype = H2N_BUFFER_PACKET;
-
-		/*
-		 * NSS expects to see buffer from Ethernet header onwards.
-		 * If the wireless driver has called eth_type_trans to remove
-		 * the ethernet header, we need to push back the header
-		 */
-		if (unlikely((os_buf->data - skb_mac_header(os_buf)) == ETH_HLEN)) {
-			skb_push(os_buf, ETH_HLEN);
-			push_mac_header = 1;
-		}
+		return nss_virt_if_tx_buf(handle->vhandle, skb);
 	}
-
-	/*
-	 * Direct the buffer to the NSS
-	 */
-	status = nss_core_send_buffer(nss_ctx, if_num, os_buf, NSS_IF_DATA_QUEUE_0, bufftype, H2N_BIT_FLAG_VIRTUAL_BUFFER);
-	if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
-		nss_warning("%p: Virtual Rx packet unable to enqueue\n", nss_ctx);
-
-		if(unlikely(push_mac_header)) {
-			skb_pull(os_buf, ETH_HLEN);
-		}
-
-		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;
 }
 
 /*
@@ -181,67 +99,33 @@
  */
 void *nss_create_virt_if(struct net_device *netdev)
 {
-	struct nss_virt_if_msg nvim;
-	struct nss_virt_if_create *nvic;
-	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.ipv4_handler_id];
-	int32_t if_num;
+	struct nss_redir_handle *handles;
 
-	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
-		nss_warning("Interface could not be created as core not ready");
-		return NULL;
+	handles = (struct nss_redir_handle *)kzalloc(sizeof(struct nss_redir_handle), GFP_KERNEL);
+	if (!handles) {
+		nss_warning("%s: kzalloc failed\n", __func__);
+		goto error1;
 	}
 
-	/*
-	 * Check if net_device is Ethernet type
-	 */
-	if (netdev->type != ARPHRD_ETHER) {
-		nss_warning("%p:Register virtual interface %p: type incorrect: %d ", nss_ctx, netdev, netdev->type);
-		return NULL;
+	handles->whandle = nss_wifi_if_create(netdev);
+	if (!handles->whandle) {
+		nss_warning("%s: nss_wifi_if creation failed\n", __func__);
+		goto error2;
 	}
 
-	/*
-	 * Find a free virtual interface
-	 */
-	spin_lock_bh(&nss_top_main.lock);
-	for (if_num = NSS_VIRTUAL_IF_START; if_num < NSS_VIRTUAL_IF_START + NSS_MAX_VIRTUAL_INTERFACES; ++if_num) {
-		if (!nss_top_main.subsys_dp_register[if_num].ndev) {
-			/*
-			 * Use this redirection interface
-			 */
-			nss_top_main.subsys_dp_register[if_num].ndev = netdev;
-			break;
-		}
+	handles->vhandle = nss_virt_if_create(netdev);
+	if (!handles->vhandle) {
+		nss_warning("%s: nss_virt_if creation failed\n", __func__);
+		goto error3;
 	}
 
-	spin_unlock_bh(&nss_top_main.lock);
-	if (if_num == NSS_VIRTUAL_IF_START + NSS_MAX_VIRTUAL_INTERFACES) {
-		/*
-		 * No available virtual contexts
-		 */
-		nss_warning("%p:Register virtual interface %p: no contexts available:", nss_ctx, netdev);
-		return NULL;
-	}
-
-	nss_cmn_msg_init(&nvim.cm, if_num, NSS_VIRT_IF_TX_CREATE_MSG,
-			sizeof(struct nss_virt_if_create), NULL, NULL);
-
-	nvic = &nvim.msg.if_create;
-	nvic->flags = 0;
-	memcpy(nvic->mac_addr, netdev->dev_addr, ETH_ALEN);
-
-	(void)nss_virt_if_tx_msg(nss_ctx, &nvim);
-
-	/*
-	 * Hold a reference to the net_device
-	 */
-	dev_hold(netdev);
-	nss_info("%p:Registered virtual interface %d: context %p", nss_ctx, if_num, netdev);
-
-	/*
-	 * The context returned is the virtual interface # which is, essentially, the index into the if_ctx
-	 * array that is holding the net_device pointer
-	 */
-	return (void *)if_num;
+	return (void *)handles;
+error3:
+	nss_wifi_if_destroy(handles->whandle);
+error2:
+	kfree(handles);
+error1:
+	return NULL;
 }
 
 /*
@@ -249,39 +133,12 @@
  */
 nss_tx_status_t nss_destroy_virt_if(void *ctx)
 {
-	int32_t if_num;
-	struct nss_virt_if_msg nvim;
-	struct net_device *dev;
-	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.ipv4_handler_id];
+	struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
 
-	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
-		nss_warning("Interface could not be destroyed as core not ready");
-		return NSS_TX_FAILURE_NOT_READY;
-	}
+	nss_wifi_if_destroy(handle->whandle);
+	nss_virt_if_destroy(handle->vhandle);
 
-	if_num = (int32_t)ctx;
-	nss_assert(NSS_IS_IF_TYPE(VIRTUAL, if_num));
-
-	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 virtual interface %d: no context", nss_ctx, if_num);
-		return NSS_TX_FAILURE_BAD_PARAM;
-	}
-
-	/*
-	 * Set this context to NULL
-	 */
-	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);
-	nss_info("%p:Unregister virtual interface %d (%p)", nss_ctx, if_num, dev);
-	dev_put(dev);
-
-	nss_cmn_msg_init(&nvim.cm, if_num, NSS_VIRT_IF_TX_DESTROY_MSG,
-			sizeof(struct nss_virt_if_destroy), NULL, NULL);
-
-	return nss_virt_if_tx_msg(nss_ctx, &nvim);
+	return NSS_TX_SUCCESS;
 }
 
 EXPORT_SYMBOL(nss_tx_virt_if_rxbuf);
diff --git a/nss_virt_if.c b/nss_virt_if.c
index fa11efb..9b53f8d 100644
--- a/nss_virt_if.c
+++ b/nss_virt_if.c
@@ -22,15 +22,52 @@
 #include "nss_tx_rx_common.h"
 #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)
+
 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];
+
+/*
+ * Spinlock to protect the global data structure virt_handle.
+ */
+DEFINE_SPINLOCK(virt_if_lock);
+
+/*
+ * nss_virt_if_stats_sync()
+ *	Sync stats from the NSS FW
+ */
+static void nss_virt_if_stats_sync(struct nss_virt_if_handle *handle,
+					struct nss_virt_if_stats *nwis)
+{
+	struct nss_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_virt_if_msg_handler()
  *	Handle msg responses from the FW on virtual interfaces
  */
-static void nss_virt_if_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
+static void nss_virt_if_msg_handler(struct nss_ctx_instance *nss_ctx,
+					struct nss_cmn_msg *ncm,
+					__attribute__((unused))void *app_data)
 {
+	struct nss_virt_if_msg *nvim = (struct nss_virt_if_msg *)ncm;
+	int32_t if_num;
+
 	nss_virt_if_msg_callback_t cb;
+	struct nss_virt_if_handle *handle = NULL;
 
 	/*
 	 * Sanity check the message type
@@ -40,16 +77,6 @@
 		return;
 	}
 
-	if (((!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) && (!NSS_IS_IF_TYPE(VIRTUAL, ncm->interface)))) {
-		nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
-		return;
-	}
-
-	if (ncm->len > sizeof(struct nss_virt_if_msg)) {
-		nss_warning("%p: message length too big: %d", nss_ctx, ncm->len);
-		return;
-	}
-
 	/*
 	 * Messages value that are within the base class are handled by the base class.
 	 */
@@ -57,6 +84,30 @@
 		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)))) {
+		nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
+		return;
+	}
+
+	if_num = NSS_VIRT_IF_INDEX_OFFSET(ncm->interface);
+
+	spin_lock_bh(&virt_if_lock);
+	if (!virt_handle[if_num]) {
+		spin_unlock_bh(&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);
+
+	switch (nvim->cm.type) {
+	case NSS_VIRT_IF_STATS_SYNC_MSG:
+		nss_virt_if_stats_sync(handle, &nvim->msg.stats);
+		break;
+	}
+
 	/*
 	 * Log failures
 	 */
@@ -86,12 +137,35 @@
 }
 
 /*
- * nss_virt_if_tx_rxbuf()
+ * nss_virt_if_callback
+ *	Callback to handle the completion of NSS ->HLOS messages.
+ */
+static void nss_virt_if_callback(void *app_data, struct nss_cmn_msg *ncm)
+{
+	struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)app_data;
+	struct nss_virt_if_pvt *nvip = handle->pvt;
+
+	if (ncm->response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("%p: virt_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_virt_if_tx_buf()
  *	HLOS interface has received a packet which we redirect to the NSS, if appropriate to do so.
  */
-nss_tx_status_t nss_virt_if_tx_rxbuf(struct nss_ctx_instance *nss_ctx, int32_t if_num, struct sk_buff *skb)
+nss_tx_status_t nss_virt_if_tx_buf(struct nss_virt_if_handle *handle,
+						struct sk_buff *skb)
 {
 	int32_t status;
+	int32_t if_num = handle->if_num;
+	struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
 
 	if (unlikely(nss_ctl_redirect == 0)) {
 		return NSS_TX_FAILURE_NOT_ENABLED;
@@ -133,7 +207,8 @@
 	/*
 	 * 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);
+	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;
@@ -142,13 +217,277 @@
 	/*
 	 * 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_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;
 }
+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)
@@ -199,8 +538,9 @@
 		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);
+	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 virtual interface # which is, essentially, the index into the if_ctx
@@ -208,64 +548,45 @@
 	 */
 	return NSS_TX_SUCCESS;
 }
+EXPORT_SYMBOL(nss_virt_if_tx_msg);
 
 /*
  * nss_virt_if_register()
  */
-struct nss_ctx_instance *nss_virt_if_register(uint32_t if_num,
-						nss_virt_if_data_callback_t data_callback,
-						nss_virt_if_msg_callback_t msg_callback,
-						struct net_device *netdev)
+void nss_virt_if_register(struct nss_virt_if_handle *handle,
+				nss_virt_if_data_callback_t data_callback,
+				struct net_device *netdev)
 {
-	struct nss_ctx_instance *nss_ctx = NULL;
-	uint32_t ret;
+	int32_t if_num;
 
-	/*
-	 * Register handler for dynamically allocated virtual interface on NSS with nss core.
-	 */
-	if (NSS_IS_IF_TYPE(DYNAMIC, if_num)) {
-		ret = nss_core_register_handler(if_num, nss_virt_if_msg_handler, NULL);
-		if (ret != NSS_CORE_STATUS_SUCCESS) {
-			nss_warning("Failed to register message handler for virtual interface : %d", if_num);
-			return NULL;
-		}
+	if (!handle) {
+		nss_warning("nss_virt_if_register handle is NULL\n");
+		return;
 	}
 
-	nss_ctx = &nss_top_main.nss[nss_top_main.ipv4_handler_id];
+	if_num = handle->if_num;
 
-	/*
-	 * TODO: the use of if_ctx as a net_dev and forcing this
-	 * for the caller is not how app_data is typically handled.
-	 * Re-think this.
-	 */
 	nss_top_main.subsys_dp_register[if_num].ndev = netdev;
 	nss_top_main.subsys_dp_register[if_num].cb = data_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;
-
-	nss_top_main.if_rx_msg_callback[if_num] = msg_callback;
-
-	return nss_ctx;
 }
+EXPORT_SYMBOL(nss_virt_if_register);
 
 /*
  * nss_virt_if_unregister()
  */
-void nss_virt_if_unregister(uint32_t if_num)
+void nss_virt_if_unregister(struct nss_virt_if_handle *handle)
 {
-	uint32_t ret;
+	int32_t if_num;
 
-	/*
-	 * Un-register handler for dynamically allocated virtual interface on NSS with nss core.
-	 */
-	if (NSS_IS_IF_TYPE(DYNAMIC, if_num)) {
-		ret = nss_core_unregister_handler(if_num);
-		if (ret != NSS_CORE_STATUS_SUCCESS) {
-			nss_warning("Failed to register message handler for virtual interface : %d", if_num);
-			return;
-		}
+	if (!handle) {
+		nss_warning("nss_virt_if_unregister 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;
@@ -273,38 +594,92 @@
 
 	nss_top_main.if_rx_msg_callback[if_num] = NULL;
 }
+EXPORT_SYMBOL(nss_virt_if_unregister);
+
+/*
+ * nss_virt_if_copy_stats()
+ *	Copy stats from the virt_if handle to buffer(line)
+ */
+int32_t nss_virt_if_copy_stats(int32_t if_num, int i, char *line)
+{
+	int32_t bytes = 0;
+	struct nss_virt_if_stats *stats;
+	int32_t ifnum;
+	uint32_t len = 80;
+	struct nss_virt_if_handle *handle = NULL;
+
+	if (if_num < 0) {
+		nss_warning("nss_virt_if_copy_stats invalid if_num\n");
+		return bytes;
+	}
+
+	ifnum = NSS_VIRT_IF_INDEX_OFFSET(if_num);
+
+	spin_lock_bh(&virt_if_lock);
+	if (!virt_handle[ifnum]) {
+		spin_unlock_bh(&virt_if_lock);
+		goto end;
+	}
+
+	handle = virt_handle[ifnum];
+	spin_unlock_bh(&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;
+}
 
 /*
  * nss_virt_if_get_interface_num()
- *	Get interface number for a virtual interface
+ * Get interface number for a virtual interface
  */
-int32_t nss_virt_if_get_interface_num(void *if_ctx)
+int32_t nss_virt_if_get_interface_num(void *ctx)
 {
-	int32_t if_num = (int32_t)if_ctx;
-	nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num) || NSS_IS_IF_TYPE(VIRTUAL, if_num));
-	return if_num;
-}
+	struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)ctx;
 
-/*
- * nss_virt_if_register_handler()
- * 	register handler for statically allocated virtual interface on NSS with NSS core.
- */
-void nss_virt_if_register_handler(void)
-{
-	int i;
-	uint32_t ret;
-	int end = NSS_VIRTUAL_IF_START + NSS_MAX_VIRTUAL_INTERFACES;
-
-	for (i = NSS_VIRTUAL_IF_START; i < end; i++) {
-		ret = nss_core_register_handler(i, nss_virt_if_msg_handler, NULL);
-		if (ret != NSS_CORE_STATUS_SUCCESS) {
-			nss_warning("Failed to register message handler for virtual interface : %d", i);
-		}
+	if (!handle) {
+		nss_warning("virt_if handle is NULL\n");
+		return -1;
 	}
-}
 
-EXPORT_SYMBOL(nss_virt_if_tx_msg);
-EXPORT_SYMBOL(nss_virt_if_tx_rxbuf);
+	return handle->if_num;
+}
 EXPORT_SYMBOL(nss_virt_if_get_interface_num);
-EXPORT_SYMBOL(nss_virt_if_register);
-EXPORT_SYMBOL(nss_virt_if_unregister);