Merge "Set DMA direction to TO_DEVICE for Tx completions"
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index 6549a84..9d34dbb 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -75,7 +75,7 @@
 #define NSS_MAX_VIRTUAL_INTERFACES 16
 #define NSS_MAX_TUNNEL_INTERFACES 4
 #define NSS_MAX_SPECIAL_INTERFACES 24
-#define NSS_MAX_DYNAMIC_INTERFACES 3
+#define NSS_MAX_DYNAMIC_INTERFACES 8
 
 /**
  * Start of individual interface groups
@@ -369,7 +369,6 @@
 #define NSS_IPV6_CREATE_FLAG_VLAN_MARKING 0x10
 					/** Rule for VLAN marking */
 
-
 /**
  * Structure to be used while sending an IPv6 flow/connection destroy rule.
  */
diff --git a/exports/nss_dynamic_interface.h b/exports/nss_dynamic_interface.h
index c82a3b3..79d8582 100644
--- a/exports/nss_dynamic_interface.h
+++ b/exports/nss_dynamic_interface.h
@@ -29,6 +29,7 @@
 	NSS_DYNAMIC_INTERFACE_TYPE_NONE = 0,
 	NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR = 1,	/* GRE_REDIR Interface type */
 	NSS_DYNAMIC_INTERFACE_TYPE_CAPVAPV1 = 2,	/* CAPVAPV1 Interface type */
+	NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD = 3,		/* TUN6RD Interface type */
 	NSS_DYNAMIC_INTERFACE_TYPE_MAX
 };
 
@@ -51,4 +52,13 @@
  */
 extern nss_tx_status_t nss_dynamic_interface_dealloc_node(int if_num, enum nss_dynamic_interface_type type);
 
+/**
+ * @brief The inferface number belong to the dynamic interface
+ *
+ * @param if_num interface number of dynamic interface
+ *
+ * @return bool true or false
+ */
+bool nss_is_dynamic_interface(int if_num);
+
 #endif /* __NSS_DYNAMIC_INTERFACE_H*/
diff --git a/exports/nss_ipsec.h b/exports/nss_ipsec.h
index e5061af..b94bc3a 100644
--- a/exports/nss_ipsec.h
+++ b/exports/nss_ipsec.h
@@ -27,7 +27,7 @@
  * refer http://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml
  * for the full list
  */
-#define NSS_IPSEC_ARPHRD_IPSEC 0x31	/**< iana.org ARP Hardware type for IPsec tunnel*/
+#define NSS_IPSEC_ARPHRD_IPSEC 31	/**< iana.org ARP Hardware type for IPsec tunnel*/
 #define NSS_IPSEC_MAX_SA 256 		/**< maximum SAs supported */
 
 #if (~(NSS_IPSEC_MAX_SA - 1) & (NSS_IPSEC_MAX_SA >> 1))
@@ -106,11 +106,12 @@
 
 	uint8_t cipher_algo;		/**< Cipher algorithm */
 	uint8_t auth_algo;		/**< Authentication algorithm */
-	uint8_t esp_seq_skip;		/**< Skip ESP sequence number */
+	uint8_t nat_t_req;		/**< NAT-T required */
 	uint8_t esp_icv_len;		/**< ESP trailers ICV length to apply */
 
-	uint8_t nat_t_req;		/**< NAT-T required */
-	uint8_t res[3];			/**< Reserve bytes for alignment */
+	uint8_t esp_seq_skip;		/**< Skip ESP sequence number */
+	uint8_t esp_tail_skip;		/**< Skip ESP trailer */
+	uint8_t res[2];			/**< Reserve bytes for alignment */
 };
 
 /*
@@ -192,6 +193,16 @@
 extern nss_tx_status_t nss_ipsec_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_ipsec_msg *msg);
 
 /**
+ * @brief send an IPsec process request
+ *
+ * @param os_buf Data buffer
+ * @param if_num NSS interface number
+ *
+ * @return Status
+ */
+extern nss_tx_status_t nss_ipsec_tx_buf(struct sk_buff *os_buf, uint32_t if_num);
+
+/**
  * @brief register a event callback handler with HLOS driver
  *
  * @param if_num[IN] receive events from this interface (Encap, Decap or C2C)
diff --git a/exports/nss_ipsecmgr.h b/exports/nss_ipsecmgr.h
index f53f4b2..7bbfe5b 100644
--- a/exports/nss_ipsecmgr.h
+++ b/exports/nss_ipsecmgr.h
@@ -42,6 +42,8 @@
 
 #define NSS_IPSECMGR_TUN_MTU(x) (x - NSS_IPSECMGR_TUN_MAX_HDR_LEN)
 
+#define NSS_IPSECMGR_NATT_PORT_DATA 4500
+
 /**
  * @brief Definition of an IPsec encapsulation rule for an add operation
  */
@@ -67,7 +69,8 @@
 	uint8_t esp_icv_len;		/**< ESP trailer's ICV length */
 
 	uint8_t esp_seq_skip;		/**< Skip ESP sequence number in header*/
-	uint8_t res[3];			/**< reserve for 4-byte alignment */
+	uint8_t esp_tail_skip;		/**< Skip ESP trailer*/
+	uint8_t res[2];			/**< reserve for 4-byte alignment */
 };
 
 /**
@@ -100,6 +103,10 @@
 	uint8_t auth_algo;		/**< Authentication algorithm */
 	uint8_t esp_icv_len;		/**< ESP trailer's ICV length */
 	uint8_t nat_t_req;		/**< Remove NAT-T header */
+
+	uint8_t esp_seq_skip;		/**< Skip ESP sequence number in header*/
+	uint8_t esp_tail_skip;		/**< Skip ESP trailer*/
+	uint8_t res[2];			/**< reserve for 4-byte alignment */
 };
 
 /**
diff --git a/exports/nss_ipv4.h b/exports/nss_ipv4.h
index 24a7da4..595593a 100644
--- a/exports/nss_ipv4.h
+++ b/exports/nss_ipv4.h
@@ -36,6 +36,7 @@
 	NSS_IPV4_RX_ESTABLISH_RULE_MSG,		/**< IPv4 establish rule message */
 	NSS_IPV4_RX_CONN_STATS_SYNC_MSG,	/**< IPv4 connection stats sync message */
 	NSS_IPV4_RX_NODE_STATS_SYNC_MSG,	/**< IPv4 generic statistics sync message */
+	NSS_IPV4_TX_CONN_CFG_RULE_MSG,		/**< IPv4 number of connections supported rule message */
 	NSS_IPV4_MAX_MSG_TYPES,			/**< IPv4 message max type number */
 };
 
@@ -187,6 +188,14 @@
 };
 
 /**
+ * The IPv4 rule number of supported connections sub-message structure.
+ */
+struct nss_ipv4_rule_conn_cfg_msg {
+	uint32_t num_conn;	/**< Number of supported IPv4 connections */
+};
+
+
+/**
  * The NSS IPv4 rule establish structure.
  */
 struct nss_ipv4_rule_establish {
@@ -373,6 +382,7 @@
 		struct nss_ipv4_rule_establish rule_establish;	/**< Message: rule establish confirmation */
 		struct nss_ipv4_conn_sync conn_stats;	/**< Message: connection stats sync */
 		struct nss_ipv4_node_sync node_stats;	/**< Message: node stats sync */
+		struct nss_ipv4_rule_conn_cfg_msg rule_conn_cfg;	/**< Message: rule connections supported */
 	} msg;
 };
 
@@ -422,4 +432,18 @@
  */
 extern void nss_ipv4_register_handler(void);
 
+/**
+ * @brief IPv4 sysctl register
+ *
+ * @return None
+ */
+extern void nss_ipv4_register_sysctl(void);
+
+/**
+ * @brief IPv4 sysctl unregister
+ *
+ * @return None
+ */
+extern void nss_ipv4_unregister_sysctl(void);
+
 #endif /* __NSS_IPV4_H */
diff --git a/exports/nss_ipv6.h b/exports/nss_ipv6.h
index e08513a..7535e66 100644
--- a/exports/nss_ipv6.h
+++ b/exports/nss_ipv6.h
@@ -36,6 +36,7 @@
 	NSS_IPV6_RX_ESTABLISH_RULE_MSG,		/**< IPv6 establish rule message */
 	NSS_IPV6_RX_CONN_STATS_SYNC_MSG,	/**< IPv6 connection stats sync message */
 	NSS_IPV6_RX_NODE_STATS_SYNC_MSG,	/**< IPv6 generic statistics sync message */
+	NSS_IPV6_TX_CONN_CFG_RULE_MSG,		/**< IPv6 connection cfg rule message */
 	NSS_IPV6_MAX_MSG_TYPES,
 };
 
@@ -225,6 +226,13 @@
 };
 
 /**
+ * The IPv6 rule conn cfgsub-message structure.
+ */
+struct nss_ipv6_rule_conn_cfg_msg {
+	uint32_t num_conn;	/**< Holds number of supported connections in IPv6 */
+};
+
+/**
  * The NSS IPv6 rule establish structure.
  */
 struct nss_ipv6_rule_establish {
@@ -344,6 +352,7 @@
 		struct nss_ipv6_rule_establish rule_establish;	/**< Message: rule establish confirmation */
 		struct nss_ipv6_conn_sync conn_stats;		/**< Message: stats sync */
 		struct nss_ipv6_node_sync node_stats;		/**< Message: node stats sync */
+		struct nss_ipv6_rule_conn_cfg_msg rule_conn_cfg;/**< Message: rule conn cfg */
 	} msg;
 };
 
@@ -392,4 +401,20 @@
  * @return none
  */
 extern void nss_ipv6_register_handler(void);
+
+/**
+ * @brief IPv4 sysctl register
+ *
+ * @return None
+ */
+extern void nss_ipv6_register_sysctl(void);
+
+/**
+ * @brief IPv4 sysctl unregister
+ *
+ * @return None
+ */
+extern void nss_ipv6_unregister_sysctl(void);
+
+
 #endif /* __NSS_IPV6_H */
diff --git a/exports/nss_tun6rd.h b/exports/nss_tun6rd.h
index cf58fa1..98b9bea 100644
--- a/exports/nss_tun6rd.h
+++ b/exports/nss_tun6rd.h
@@ -30,50 +30,51 @@
  * 6rd tunnel request/response types
  */
 enum nss_tun6rd_metadata_types {
-	NSS_TUN6RD_TX_IF_CREATE,
-	NSS_TUN6RD_TX_IF_DESTROY,
+	NSS_TUN6RD_ATTACH_PNODE,
 	NSS_TUN6RD_RX_STATS_SYNC,
+	NSS_TUN6RD_ADD_UPDATE_PEER,
 	NSS_TUN6RD_MAX,
 };
 
 /**
  * 6rd tunnel configuration message structure
  */
-struct nss_tun6rd_create_msg {
-	uint32_t prefix[4];	/* 6rd prefix */
-	uint32_t relay_prefix;	/* Relay prefix */
-	uint16_t prefixlen;	/* 6rd prefix len */
-	uint16_t relay_prefixlen;/* Relay prefix length*/
+struct nss_tun6rd_attach_tunnel_msg {
+	uint32_t prefix[4];		/* 6rd prefix */
+	uint32_t relay_prefix;		/* Relay prefix */
+	uint16_t prefixlen;		/* 6rd prefix len */
+	uint16_t relay_prefixlen;	/* Relay prefix length*/
 	uint32_t saddr;		/* Tunnel source address */
 	uint32_t daddr;		/* Tunnel destination addresss */
-	uint8_t  tos;		/* Tunnel tos field */
-	uint8_t  ttl;		/* Tunnel ttl field */
-	uint16_t reserved;	/* Reserved field */
-};
-
-/**
- * 6rd tunnel interface down message structure
- */
-struct nss_tun6rd_destroy_msg {
-	uint32_t prefix[4];	/* Place holder */
+	uint8_t  tos;			/* Tunnel tos field */
+	uint8_t  ttl;			/* Tunnel ttl field */
+	uint16_t reserved;		/* Reserved field */
 };
 
 /**
  * 6rd tunnel statistics sync message structure.
  */
-struct nss_tun6rd_stats_sync_msg {
-	struct nss_cmn_node_stats node_stats;
+struct nss_tun6rd_sync_stats_msg {
+	struct nss_cmn_node_stats node_stats;	/* Node statstics*/
+};
+
+/**
+ * 6rd tunnel peer addr.
+ */
+struct nss_tun6rd_set_peer_msg {
+	uint32_t ipv6_address[4];	/* The peer's ipv6 addr*/
+	uint32_t dest;			/* The peer's ipv4 addr*/
 };
 
 /**
  * Message structure to send/receive 6rd tunnel messages
  */
 struct nss_tun6rd_msg {
-	struct nss_cmn_msg cm;		/* Message Header */
+	struct nss_cmn_msg cm;					/* Message Header */
 	union {
-		struct nss_tun6rd_create_msg tun6rd_create;	/* Message: Create 6rd tunnel */
-		struct nss_tun6rd_destroy_msg tun6rd_destroy;	/* Message: Destroy 6rd tunnel */
-		struct nss_tun6rd_stats_sync_msg stats_sync;	/* Message: interface stats sync */
+		struct nss_tun6rd_attach_tunnel_msg tunnel;	/* Message: Attach 6rd tunnel */
+		struct nss_tun6rd_sync_stats_msg stats;	/* Message: interface stats sync */
+		struct nss_tun6rd_set_peer_msg peer;		/* Message: add/update peer */
 	} msg;
 };
 
@@ -98,10 +99,17 @@
 extern nss_tx_status_t nss_tun6rd_tx(struct nss_ctx_instance *nss_ctx, struct nss_tun6rd_msg *msg);
 
 /**
+ * @brief Get the tun6rd context used in the nss_tun6rd_tx
+ *
+ * @return struct nss_ctx_instance *NSS context
+ */
+extern struct nss_ctx_instance *nss_tun6rd_get_context(void);
+
+/**
  * @brief Callback to receive 6rd tunnel data
  *
  * @param app_data Application context of the message
- * @param os_buf  Pointer to data buffer
+ * @param os_buf Pointer to data buffer
  *
  * @return void
  */
@@ -118,7 +126,7 @@
  * @return nss_ctx_instance* NSS context
  */
 extern struct nss_ctx_instance *nss_register_tun6rd_if(uint32_t if_num, nss_tun6rd_callback_t tun6rd_callback,
-							nss_tun6rd_msg_callback_t msg_callback, struct net_device *netdev);
+					nss_tun6rd_msg_callback_t msg_callback, struct net_device *netdev);
 
 /**
  * @brief Unregister 6rd tunnel interface with NSS
diff --git a/nss_connmgr_tun6rd.c b/nss_connmgr_tun6rd.c
index 2a52087..801dc43 100644
--- a/nss_connmgr_tun6rd.c
+++ b/nss_connmgr_tun6rd.c
@@ -31,6 +31,7 @@
 #include <net/ipip.h>
 #include <linux/if_arp.h>
 #include <nss_api_if.h>
+#include <nss_dynamic_interface.h>
 
 /*
  * NSS tun6rd debug macros
@@ -38,46 +39,40 @@
 #if (NSS_TUN6RD_DEBUG_LEVEL < 1)
 #define nss_tun6rd_assert(fmt, args...)
 #else
-#define nss_tun6d_assert(c) if (!(c)) { BUG_ON(!(c)); }
+#define nss_tun6rd_assert(c) if (!(c)) { BUG_ON(!(c)); }
 #endif
 
-#if (NSS_TUN6RD_DEBUG_LEVEL < 2)
-#define nss_tun6rd_error(fmt, args...)
+#if defined(CONFIG_DYNAMIC_DEBUG)
+/*
+ * Compile messages for dynamic enable/disable
+ */
+#define nss_tun6rd_warning(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define nss_tun6rd_info(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define nss_tun6rd_trace(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #else
-#define nss_tun6rd_error(fmt, args...) printk(KERN_WARNING "nss tun6rd:"fmt, ##args)
+
+/*
+ * Statically compile messages at different levels
+ */
+#if (NSS_TUN6RD_DEBUG_LEVEL < 2)
+#define nss_tun6rd_warning(s, ...)
+#else
+#define nss_tun6rd_warning(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #endif
 
 #if (NSS_TUN6RD_DEBUG_LEVEL < 3)
-#define nss_tun6rd_warning(fmt, args...)
+#define nss_tun6rd_info(s, ...)
 #else
-#define nss_tun6rd_warning(fmt, args...) printk(KERN_WARNING "nss tun6rd:"fmt, ##args)
+#define nss_tun6rd_info(s, ...)   pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #endif
 
 #if (NSS_TUN6RD_DEBUG_LEVEL < 4)
-#define nss_tun6rd_info(fmt, args...)
+#define nss_tun6rd_trace(s, ...)
 #else
-#define nss_tun6rd_info(fmt, args...) printk(KERN_INFO "nss tun6rd :"fmt, ##args)
+#define nss_tun6rd_trace(s, ...)  pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
 #endif
-
-#if (NSS_TUN6RD_DEBUG_LEVEL < 5)
-#define nss_tun6rd_trace(fmt, args...)
-#else
-#define nss_tun6rd_trace(fmt, args...) printk(KERN_DEBUG "nss tun6rd :"fmt, ##args)
 #endif
 
-void nss_tun6rd_exception(void *ctx, void *buf, __attribute__((unused)) struct napi_struct *napi);
-void nss_tun6rd_event_receive(void *ctx, struct nss_tun6rd_msg *msg);
-
-/*
- * 6rd tunnel host instance
- */
-struct nss_tun6rd_tunnel{
-	struct nss_ctx_instance *nss_ctx;
-	uint32_t if_num;
-	struct net_device *netdev;
-	uint32_t device_up;
-};
-
 /*
  * 6rd tunnel stats
  */
@@ -88,45 +83,106 @@
 	uint32_t tx_bytes;	/* Number of transmitted bytes */
 };
 
+/*
+ * nss_tun6rd_update_dev_stats
+ *	Update the Dev stats received from NetAp
+ */
+static void nss_tun6rd_update_dev_stats(struct net_device *dev,
+					struct nss_tun6rd_sync_stats_msg *sync_stats)
+{
+	struct nss_tun6rd_stats stats;
 
-struct nss_tun6rd_tunnel g_tun6rd;
+	stats.rx_packets = sync_stats->node_stats.rx_packets;
+	stats.rx_bytes = sync_stats->node_stats.rx_bytes;
+	stats.tx_packets = sync_stats->node_stats.tx_packets;
+	stats.tx_bytes = sync_stats->node_stats.tx_bytes;
+
+	ipip6_update_offload_stats(dev, (void *)&stats);
+}
 
 /*
- * Internal function
+ * nss_tun6rd_event_receive()
+ *	Event Callback to receive events from NSS
  */
-static int
-nss_tun6rd_dev_event(struct notifier_block  *nb,
-			unsigned long event,
-			void  *dev);
+static void nss_tun6rd_event_receive(void *if_ctx, struct nss_tun6rd_msg *tnlmsg)
+{
+	struct net_device *netdev = if_ctx;
+
+	switch (tnlmsg->cm.type) {
+	case NSS_TUN6RD_RX_STATS_SYNC:
+		nss_tun6rd_update_dev_stats(netdev, (struct nss_tun6rd_sync_stats_msg *)&tnlmsg->msg.stats);
+		break;
+
+	default:
+		nss_tun6rd_info("Unknown Event from NSS\n");
+		break;
+	}
+}
 
 /*
- * Linux Net device Notifier
+ * nss_tun6rd_exception()
+ *	Exception handler registered to NSS driver
  */
-struct notifier_block nss_tun6rd_notifier = {
-	.notifier_call = nss_tun6rd_dev_event,
-};
+static void nss_tun6rd_exception(void *ctx, void *buf, __attribute__((unused)) struct napi_struct *napi)
+{
+	struct net_device *dev = (struct net_device *)ctx;
+	struct sk_buff *skb = (struct sk_buff *)buf;
+	const struct iphdr *iph;
+
+	skb->dev = dev;
+	nss_tun6rd_info("received - %d bytes name %s ver %x\n",
+			skb->len,dev->name,skb->data[0]);
+
+	iph = (const struct iphdr *)skb->data;
+
+	/*
+	 * Packet after Decap/Encap Did not find the Rule.
+	 */
+	if (iph->version != 4) {
+		skb->protocol = htons(ETH_P_IPV6);
+	} else {
+		if (iph->protocol == IPPROTO_IPV6) {
+			skb_pull(skb, sizeof(struct iphdr));
+			skb->protocol = htons(ETH_P_IPV6);
+			skb_reset_network_header(skb);
+			skb->pkt_type = PACKET_HOST;
+			skb->ip_summed = CHECKSUM_NONE;
+			dev_queue_xmit(skb);
+			return;
+		}
+		skb->protocol = htons(ETH_P_IP);
+	}
+
+	skb_reset_network_header(skb);
+	skb->pkt_type = PACKET_HOST;
+	skb->skb_iif = dev->ifindex;
+	skb->ip_summed = CHECKSUM_NONE;
+	netif_receive_skb(skb);
+}
 
 /*
  * nss_tun6rd_dev_up()
  *	6RD Tunnel device i/f up handler
  */
-void nss_tun6rd_dev_up( struct net_device * netdev)
+static int nss_tun6rd_dev_up(struct net_device *netdev)
 {
 	struct ip_tunnel *tunnel;
 	struct ip_tunnel_6rd_parm *ip6rd;
 	const struct iphdr  *tiph;
 	struct nss_tun6rd_msg tun6rdmsg;
-	struct nss_tun6rd_create_msg *tun6rdcfg;
+	struct nss_tun6rd_attach_tunnel_msg *tun6rdcfg;
+	uint32_t if_number;
 	nss_tx_status_t status;
+	struct nss_ctx_instance *nss_ctx;
 
 	/*
 	 * Validate netdev for ipv6-in-ipv4  Tunnel
 	 */
-	if (netdev->type != ARPHRD_SIT ) {
-		return;
+	if (netdev->type != ARPHRD_SIT) {
+		return NOTIFY_BAD;
 	}
 
-	tunnel = (struct ip_tunnel*)netdev_priv(netdev);
+	tunnel = (struct ip_tunnel *)netdev_priv(netdev);
 	ip6rd =  &tunnel->ip6rd;
 
 	/*
@@ -139,16 +195,14 @@
 	if ((ip6rd->prefixlen == 0 )
 			|| (ip6rd->relay_prefixlen > 32)
 			|| (ip6rd->prefixlen
-				+ (32 - ip6rd->relay_prefixlen) > 64)){
+				+ (32 - ip6rd->relay_prefixlen) > 64)) {
 
-		nss_tun6rd_error("Invalid 6rd argument prefix len %d     \
-				relayprefix len %d \n",
+		nss_tun6rd_warning("Invalid 6rd argument prefix len %d relayprefix len %d \n",
 				ip6rd->prefixlen,ip6rd->relay_prefixlen);
-		return;
+		return NOTIFY_BAD;
 	}
 
-	nss_tun6rd_info(" Valid 6rd Tunnel Prefix %x %x %x %x  \n        \
-			prefix len %d  relay_prefix %d relay_prefixlen %d \n",
+	nss_tun6rd_info("Valid 6rd Tunnel Prefix %x %x %x %x\n Prefix len %d relay_prefix %d relay_prefixlen %d \n",
 			ip6rd->prefix.s6_addr32[0],ip6rd->prefix.s6_addr32[1],
 			ip6rd->prefix.s6_addr32[2],ip6rd->prefix.s6_addr32[3],
 			ip6rd->prefixlen, ip6rd->relay_prefix,
@@ -158,41 +212,42 @@
 	 * Find the Tunnel device IP header info
 	 */
 	tiph = &tunnel->parms.iph ;
-	nss_tun6rd_trace(" Tunnel Param srcaddr %x daddr %x ttl %d tos %x\n",
+	nss_tun6rd_trace("Tunnel Param srcaddr %x daddr %x ttl %d tos %x\n",
 			tiph->saddr, tiph->daddr,tiph->ttl,tiph->tos);
 
-	if(tiph->saddr == 0) {
-		nss_tun6rd_error("Tunnel src address not configured  %x\n",
+	if (tiph->saddr == 0) {
+		nss_tun6rd_warning("Tunnel src address not configured %x\n",
 				tiph->saddr);
-		return;
+		return NOTIFY_BAD;
 	}
 
-	if (tiph->daddr == 0) {
-		nss_tun6rd_error("Tunnel dest address not configured  %x\n",
-				tiph->daddr);
-		return;
+	if_number = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
+	if (-1 == if_number) {
+		nss_tun6rd_warning("Request interface number failed\n");
+		return NOTIFY_BAD;
 	}
 
 	/*
 	 * Register 6rd tunnel with NSS
 	 */
-	g_tun6rd.nss_ctx = nss_register_tun6rd_if(g_tun6rd.if_num,
+	nss_ctx = nss_register_tun6rd_if(if_number,
 				nss_tun6rd_exception,
 				nss_tun6rd_event_receive,
 				netdev);
-	if (g_tun6rd.nss_ctx == NULL) {
-		nss_tun6rd_trace("nss_register_tun6rd_if Failed \n");
-		return;
+	if (!nss_ctx) {
+		status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
+		if (status != NSS_TX_SUCCESS) {
+			nss_tun6rd_warning("Unable to dealloc the node[%d] in the NSS fw!\n", if_number);
+		}
+		nss_tun6rd_trace("nss_register_tun6rd_if failed \n");
+		return NOTIFY_BAD;
 	}
 
-	nss_tun6rd_trace("nss_register_tun6rd_if Success \n");
-
 	/*
 	 * Prepare The Tunnel configuration parameter to send to nss
 	 */
 	memset(&tun6rdmsg, 0, sizeof(struct nss_tun6rd_msg));
-	tun6rdcfg = &tun6rdmsg.msg.tun6rd_create;
-
+	tun6rdcfg = &tun6rdmsg.msg.tunnel;
 	tun6rdcfg->prefixlen = ip6rd->prefixlen;
 	tun6rdcfg->relay_prefix = ip6rd->relay_prefix;
 	tun6rdcfg->relay_prefixlen = ip6rd->relay_prefixlen;
@@ -205,61 +260,68 @@
 	tun6rdcfg->ttl = tiph->ttl;
 	tun6rdcfg->tos = tiph->tos;
 
-	nss_tun6rd_trace(" 6rd Tunnel info \n");
-	nss_tun6rd_trace(" saddr %x daddr %d ttl %x  tos %x \n",
+	nss_tun6rd_trace(" 6rd Tunnel info\n");
+	nss_tun6rd_trace(" saddr %x daddr %d ttl %x  tos %x\n",
 			tiph->saddr, tiph->daddr, tiph->ttl, tiph->tos);
-	nss_tun6rd_trace(" Prefix %x:%x:%x:%x  Prefix len %d \n",
+	nss_tun6rd_trace(" Prefix %x:%x:%x:%x  Prefix len %d\n",
 			ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
 			ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
 			ip6rd->prefixlen);
 	nss_tun6rd_trace("Relay Prefix %x Len %d\n",
 			ip6rd->relay_prefix, ip6rd->relay_prefixlen);
 
-	nss_tun6rd_trace("Sending 6rd tunnel i/f up command to NSS  %x \n",
-			(int)g_tun6rd.nss_ctx);
+	nss_tun6rd_trace("Sending 6rd tunnel i/f up command to NSS %x\n",
+			(int)nss_ctx);
 
 	/*
 	 * Send 6rd Tunnel UP command to NSS
 	 */
-	nss_cmn_msg_init(&tun6rdmsg.cm, NSS_TUN6RD_INTERFACE, NSS_TUN6RD_TX_IF_CREATE,
-			sizeof(struct nss_tun6rd_create_msg), NULL, NULL);
+	nss_cmn_msg_init(&tun6rdmsg.cm, if_number, NSS_TUN6RD_ATTACH_PNODE,
+			sizeof(struct nss_tun6rd_attach_tunnel_msg), NULL, NULL);
 
-	status = nss_tun6rd_tx(g_tun6rd.nss_ctx, &tun6rdmsg);
+	status = nss_tun6rd_tx(nss_ctx, &tun6rdmsg);
 	if (status != NSS_TX_SUCCESS) {
-		nss_tun6rd_error("Tunnel up command error %d \n", status);
-		return;
+		nss_unregister_tun6rd_if(if_number);
+		status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
+		if (status != NSS_TX_SUCCESS) {
+			nss_tun6rd_warning("Unable to dealloc the node[%d] in the NSS fw!\n", if_number);
+		}
+		nss_tun6rd_warning("Tunnel up command error %d\n", status);
+		return NOTIFY_BAD;
 	}
 
-	g_tun6rd.device_up = 1;
+	return NOTIFY_DONE;
 }
 
 /*
  * nss_tun6rd_dev_down()
  *	6RD Tunnel device i/f down handler
  */
-void nss_tun6rd_dev_down(struct net_device *netdev)
+static int nss_tun6rd_dev_down(struct net_device *netdev)
 {
 	struct ip_tunnel *tunnel;
 	struct ip_tunnel_6rd_parm *ip6rd;
-	struct nss_tun6rd_msg tun6rdmsg;
-	struct nss_tun6rd_destroy_msg *tun6rdcfg;
+	int32_t if_number;
 	nss_tx_status_t status;
 
 	/*
-	 * Check if tunnel 6rd is registered ?
-	 */
-	if (g_tun6rd.nss_ctx == NULL) {
-		return;
-	}
-
-	/*
 	 * Validate netdev for ipv6-in-ipv4  Tunnel
 	 */
-	if (netdev->type != ARPHRD_SIT ) {
-		return;
+	if (netdev->type != ARPHRD_SIT) {
+		return NOTIFY_BAD;
 	}
 
-	tunnel = (struct ip_tunnel*)netdev_priv(netdev);
+	/*
+	 * Check if tunnel 6rd is registered ?
+	 */
+	if_number = nss_cmn_get_interface_number_by_dev(netdev);
+	if (if_number < 0) {
+		nss_tun6rd_warning("Net device:%p is not registered \n",netdev);
+		return NOTIFY_BAD;
+	}
+
+
+	tunnel = (struct ip_tunnel *)netdev_priv(netdev);
 	ip6rd =  &tunnel->ip6rd;
 
 	/*
@@ -268,53 +330,27 @@
 	if ((ip6rd->prefixlen == 0 )
 			|| (ip6rd->relay_prefixlen > 32 )
 			|| (ip6rd->prefixlen
-				+ (32 - ip6rd->relay_prefixlen) > 64)){
+				+ (32 - ip6rd->relay_prefixlen) > 64)) {
 
-		nss_tun6rd_error("Invalid 6rd argument prefix len %d  \
-				relayprefix len %d \n",
+		nss_tun6rd_warning("Invalid 6rd argument prefix len %d relayprefix len %d \n",
 				ip6rd->prefixlen,ip6rd->relay_prefixlen);
-		return;
-	}
-
-	/*
-	 * Prepare The Tunnel configuration parameter to send to nss
-	 */
-	memset(&tun6rdmsg, 0, sizeof(struct nss_tun6rd_msg));
-	tun6rdcfg = &tun6rdmsg.msg.tun6rd_destroy;
-
-	tun6rdcfg->prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
-	tun6rdcfg->prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
-	tun6rdcfg->prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
-	tun6rdcfg->prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
-
-	nss_tun6rd_trace(" Prefix %x:%x:%x:%x  Prefix len %d \n",
-			ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
-			ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
-			ip6rd->prefixlen);
-
-	nss_tun6rd_trace("Sending Tunnle 6rd Down command %x \n",g_tun6rd.if_num);
-
-	/*
-	 * Send 6rd Tunnel DESTROY command to NSS
-	 */
-	nss_cmn_msg_init(&tun6rdmsg.cm, NSS_TUN6RD_INTERFACE, NSS_TUN6RD_TX_IF_DESTROY,
-			sizeof(struct nss_tun6rd_destroy_msg), NULL, NULL);
-
-	status = nss_tun6rd_tx(g_tun6rd.nss_ctx, &tun6rdmsg);
-	if (status != NSS_TX_SUCCESS) {
-		nss_tun6rd_error("Tunnel down command error %d \n", status);
-		return;
+		return NOTIFY_BAD;
 	}
 
 	/*
 	 * Un-Register 6rd tunnel with NSS
 	 */
-	nss_unregister_tun6rd_if(g_tun6rd.if_num);
-	g_tun6rd.nss_ctx = NULL;
-	g_tun6rd.device_up = 0;
-	return;
+	nss_unregister_tun6rd_if(if_number);
+	status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
+	if (status != NSS_TX_SUCCESS) {
+		nss_tun6rd_warning("Dealloc node failure\n");
+		return NOTIFY_BAD;
+	}
+
+	return NOTIFY_DONE;
 }
 
+
 /*
  * nss_tun6rd_dev_event()
  *	Net device notifier for 6rd module
@@ -324,23 +360,17 @@
 {
 	struct net_device *netdev = (struct net_device *)dev;
 
-	nss_tun6rd_trace("%s\n",__FUNCTION__);
 	switch (event) {
 	case NETDEV_UP:
-		nss_tun6rd_trace(" NETDEV_UP :event %lu name %s \n",
-				event,netdev->name);
-		nss_tun6rd_dev_up(netdev);
-		break;
+		nss_tun6rd_trace("NETDEV_UP: event %lu name %s\n", event, netdev->name);
+		return nss_tun6rd_dev_up(netdev);
 
 	case NETDEV_DOWN:
-		nss_tun6rd_trace(" NETDEV_DOWN :event %lu name %s \n",
-				event,netdev->name);
-		nss_tun6rd_dev_down(netdev);
-		break;
+		nss_tun6rd_trace("NETDEV_DOWN: event %lu name %s\n", event, netdev->name);
+		return nss_tun6rd_dev_down(netdev);
 
 	default:
-		nss_tun6rd_trace("Unhandled notifier dev %s  event %x  \n",
-				netdev->name,(int)event);
+		nss_tun6rd_trace("Unhandled notifier event %lu name %s\n",event, netdev->name);
 		break;
 	}
 
@@ -348,87 +378,12 @@
 }
 
 /*
- * nss_tun6rd_exception()
- *	Exception handler registered to NSS driver
+ * Linux Net device Notifier
  */
-void nss_tun6rd_exception(void *ctx, void *buf, __attribute__((unused)) struct napi_struct *napi)
-{
-	struct net_device *dev = (struct net_device *)ctx;
-	struct sk_buff *skb = (struct sk_buff *)buf;
-	const struct iphdr *iph;
+struct notifier_block nss_tun6rd_notifier = {
+	.notifier_call = nss_tun6rd_dev_event,
+};
 
-	skb->dev = dev;
-	nss_tun6rd_info("received - %d bytes name %s ver %x \n",
-			skb->len,dev->name,skb->data[0]);
-
-	iph = (const struct iphdr *)skb->data;
-
-	/*
-	 * Packet after Decap/Encap Did not find the Rule.
-	 */
-	if (iph->version == 4) {
-		if(iph->protocol == IPPROTO_IPV6){
-			skb_pull(skb, sizeof(struct iphdr));
-			skb->protocol = htons(ETH_P_IPV6);
-			skb_reset_network_header(skb);
-			skb->pkt_type = PACKET_HOST;
-			skb->ip_summed = CHECKSUM_NONE;
-			dev_queue_xmit(skb);
-			return;
-		}
-		skb->protocol = htons(ETH_P_IP);
-	} else {
-		skb->protocol = htons(ETH_P_IPV6);
-	}
-
-	skb_reset_network_header(skb);
-	skb->pkt_type = PACKET_HOST;
-	skb->skb_iif = dev->ifindex;
-	skb->ip_summed = CHECKSUM_NONE;
-	netif_receive_skb(skb);
-}
-
-/*
- *  nss_tun6rd_update_dev_stats
- *	Update the Dev stats received from NetAp
- */
-static void nss_tun6rd_update_dev_stats(struct net_device *dev,
-					struct nss_tun6rd_stats_sync_msg *sync_stats)
-{
-	struct nss_tun6rd_stats stats;
-	void *ptr;
-
-	stats.rx_packets = sync_stats->node_stats.rx_packets;
-	stats.rx_bytes = sync_stats->node_stats.rx_bytes;
-	stats.tx_packets = sync_stats->node_stats.tx_packets;
-	stats.tx_bytes = sync_stats->node_stats.tx_bytes;
-
-	ptr = (void *)&stats;
-	ipip6_update_offload_stats(dev, ptr);
-}
-
-/**
- * @brief Event Callback to receive events from NSS
- * @param[in] pointer to net device context
- * @param[in] pointer to buffer
- * @return Returns void
- */
-void nss_tun6rd_event_receive(void *if_ctx, struct nss_tun6rd_msg *tnlmsg)
-{
-	struct net_device *netdev = NULL;
-	netdev = (struct net_device *)if_ctx;
-
-	switch (tnlmsg->cm.type) {
-	case NSS_TUN6RD_RX_STATS_SYNC:
-		nss_tun6rd_update_dev_stats(netdev, (struct nss_tun6rd_stats_sync_msg *)&tnlmsg->msg.stats_sync);
-		break;
-
-	default:
-		nss_tun6rd_info("%s: Unknown Event from NSS",
-			      __FUNCTION__);
-		break;
-	}
-}
 
 /*
  * nss_tun6rd_init_module()
@@ -442,11 +397,6 @@
 	register_netdevice_notifier(&nss_tun6rd_notifier);
 	nss_tun6rd_trace("Netdev Notifier registerd \n");
 
-	g_tun6rd.if_num = NSS_TUN6RD_INTERFACE;
-	g_tun6rd.netdev = NULL;
-	g_tun6rd.device_up = 0;
-	g_tun6rd.nss_ctx = NULL;
-
 	return 0;
 }
 
@@ -456,7 +406,6 @@
  */
 void __exit nss_tun6rd_exit_module(void)
 {
-
 	unregister_netdevice_notifier(&nss_tun6rd_notifier);
 	nss_tun6rd_info("module unloaded\n");
 }
diff --git a/nss_dynamic_interface.c b/nss_dynamic_interface.c
index 6b35852..ced3dea 100644
--- a/nss_dynamic_interface.c
+++ b/nss_dynamic_interface.c
@@ -336,5 +336,15 @@
 	di.current_if_num = -1;
 }
 
+/*
+ * nss_is_dynamic_interface()
+ *	Judge it is a valid dynamic interface
+ */
+bool nss_is_dynamic_interface(int if_num)
+{
+	return (if_num >= NSS_DYNAMIC_IF_START && if_num < NSS_SPECIAL_IF_START);
+}
+
 EXPORT_SYMBOL(nss_dynamic_interface_alloc_node);
 EXPORT_SYMBOL(nss_dynamic_interface_dealloc_node);
+EXPORT_SYMBOL(nss_is_dynamic_interface);
diff --git a/nss_hlos_if.h b/nss_hlos_if.h
index ec70158..1251ce8 100755
--- a/nss_hlos_if.h
+++ b/nss_hlos_if.h
@@ -22,6 +22,15 @@
 #ifndef __NSS_HLOS_IF_H
 #define __NSS_HLOS_IF_H
 
+#define MIN_NUM_CONN 			256	/**< MIN  Connection shared between IPv4 and IPv6 */
+#define MAX_TOTAL_NUM_CONN_IPV4_IPV6	8196	/**< MAX Connection shared between IPv4 and IPv6 */
+
+/*
+ * Variables used for sysctl updates.
+ */
+extern int nss_ipv4_conn_cfg;
+extern int nss_ipv6_conn_cfg;
+
 /*
  * Request/Response types
  */
diff --git a/nss_init.c b/nss_init.c
index 4d04bdd..1a6e56b 100755
--- a/nss_init.c
+++ b/nss_init.c
@@ -370,7 +370,6 @@
 
 	if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
 		nss_top->tun6rd_handler_id = nss_dev->id;
-		nss_tun6rd_register_handler();
 	}
 
 	if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
@@ -829,30 +828,29 @@
 		.data                   = &nss_ctl_redirect,
 		.maxlen                 = sizeof(int),
 		.mode                   = 0644,
-		.proc_handler   = proc_dointvec,
+		.proc_handler   	= proc_dointvec,
 	},
 	{
 		.procname               = "debug",
 		.data                   = &nss_ctl_debug,
 		.maxlen                 = sizeof(int),
 		.mode                   = 0644,
-		.proc_handler   = &nss_debug_handler,
+		.proc_handler   	= &nss_debug_handler,
 	},
 	{
 		.procname               = "coredump",
 		.data                   = &nss_cmd_buf.coredump,
 		.maxlen                 = sizeof(int),
 		.mode                   = 0644,
-		.proc_handler   = &nss_coredump_handler,
+		.proc_handler   	= &nss_coredump_handler,
 	},
 	{
 		.procname               = "rps",
 		.data                   = &nss_rps_cfg,
 		.maxlen                 = sizeof(int),
 		.mode                   = 0644,
-		.proc_handler   = &nss_rpscfg_handler,
+		.proc_handler   	= &nss_rpscfg_handler,
 	},
-
 	{ }
 };
 
@@ -921,6 +919,12 @@
 	nss_dev_header = register_sysctl_table(nss_root);
 
 	/*
+	 * Registering sysctl for ipv4/6 specific config.
+	 */
+	nss_ipv4_register_sysctl();
+	nss_ipv6_register_sysctl();
+
+	/*
 	 * Setup Runtime Sample values
 	 */
 	nss_runtime_samples.freq_scale[0].frequency = 	NSS_FREQ_110;
@@ -980,6 +984,12 @@
 	if (nss_dev_header)
 		unregister_sysctl_table(nss_dev_header);
 
+	/*
+	 * Unregister ipv4/6 specific sysctl
+	 */
+	nss_ipv4_unregister_sysctl();
+	nss_ipv6_unregister_sysctl();
+
 	platform_driver_unregister(&nss_driver);
 }
 
diff --git a/nss_ipsec.c b/nss_ipsec.c
index e27535b..85ee3c0 100644
--- a/nss_ipsec.c
+++ b/nss_ipsec.c
@@ -229,6 +229,43 @@
 EXPORT_SYMBOL(nss_ipsec_tx_msg);
 
 /*
+ * nss_ipsec_tx_buf
+ * 	Send data packet for ipsec processing
+ */
+nss_tx_status_t nss_ipsec_tx_buf(struct sk_buff *os_buf, uint32_t if_num)
+{
+	int32_t status;
+	struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.ipsec_handler_id];
+	uint16_t int_bit = nss_ctx->h2n_desc_rings[NSS_IF_DATA_QUEUE_0].desc_ring.int_bit;
+
+	nss_trace("%p: IPsec If Tx packet, id:%d, data=%p", nss_ctx, if_num, os_buf->data);
+
+	NSS_VERIFY_CTX_MAGIC(nss_ctx);
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: 'IPsec If Tx' packet dropped as core not ready", nss_ctx);
+		return NSS_TX_FAILURE_NOT_READY;
+	}
+
+	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 'IPsec If Tx' packet\n", nss_ctx);
+		if (status == NSS_CORE_STATUS_FAILURE_QUEUE) {
+			return NSS_TX_FAILURE_QUEUE;
+		}
+
+		return NSS_TX_FAILURE;
+	}
+
+	/*
+	 * Kick the NSS awake so it can process our new entry.
+	 */
+	nss_hal_send_interrupt(nss_ctx->nmap, 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_ipsec_tx_buf);
+
+/*
  **********************************
  Register APIs
  **********************************
diff --git a/nss_ipsecmgr.c b/nss_ipsecmgr.c
index 6f486ec..3145789 100644
--- a/nss_ipsecmgr.c
+++ b/nss_ipsecmgr.c
@@ -28,7 +28,6 @@
 #include <nss_ipsec.h>
 #include "nss_ipsecmgr.h"
 
-
 #if defined(CONFIG_DYNAMIC_DEBUG)
 /*
  * Compile messages for dynamic enable/disable
@@ -67,9 +66,9 @@
 
 /* NSS IPsec entry state */
 enum nss_ipsecmgr_entry_state {
-	NSS_IPSECMGR_ENTRY_STATE_INIT = 0,	/* init state of the entry */
-	NSS_IPSECMGR_ENTRY_STATE_VALID = 1,	/* entry is valid */
-	NSS_IPSECMGR_ENTRY_STATE_INVALID = 2,	/* entry is invalid */
+	NSS_IPSECMGR_ENTRY_STATE_INIT = 0,		/* init state of the entry */
+	NSS_IPSECMGR_ENTRY_STATE_VALID = 1,		/* entry is valid */
+	NSS_IPSECMGR_ENTRY_STATE_INVALID = 2,		/* entry is invalid */
 	NSS_IPSECMGR_ENTRY_STATE_MAX
 };
 
@@ -182,6 +181,7 @@
 	 */
 	data->cipher_algo = encap->cipher_algo;
 	data->esp_seq_skip = (encap->esp_seq_skip == 1);
+	data->esp_tail_skip = (encap->esp_tail_skip == 1);
 
 	data->esp_icv_len = encap->esp_icv_len;
 	data->auth_algo = encap->auth_algo;
@@ -216,11 +216,17 @@
 	data->cipher_algo = decap->cipher_algo;
 
 	data->esp_icv_len = decap->esp_icv_len;
+	data->esp_seq_skip = (decap->esp_seq_skip == 1);
+	data->esp_tail_skip = (decap->esp_tail_skip == 1);
 	data->auth_algo = decap->auth_algo;
 
 	data->crypto_index = decap->crypto_index;
 
 	data->nat_t_req = decap->nat_t_req;
+	if (data->nat_t_req) {
+		sel->dst_port = NSS_IPSECMGR_NATT_PORT_DATA;
+	}
+
 	data->window_size = decap->window_size;
 }
 
@@ -713,11 +719,87 @@
  */
 static netdev_tx_t nss_ipsecmgr_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	nss_ipsecmgr_warn("tunnel transmit not implemented, freeing the skb\n");
+	uint32_t if_num;
+	struct iphdr *inner_ip;
+	struct nss_ipsecmgr_priv *priv;
+	struct nss_ipsecmgr_tbl *encap;
 
-	dev_kfree_skb_any(skb);
+	if_num = NSS_IPSEC_ENCAP_IF_NUMBER;
+	priv = netdev_priv(dev);
+	encap = &priv->encap;
+
+	if (skb_is_nonlinear(skb)) {
+		nss_ipsecmgr_error("%p: NSS IPSEC does not support fragments %p\n", priv->nss_ctx, skb);
+		goto fail;
+	}
+
+	/*
+	 * Check if skb is shared
+	 */
+	if (unlikely(skb_shared(skb))) {
+		nss_ipsecmgr_error("%p: Shared skb is not supported: %p\n", priv->nss_ctx, skb);
+		goto fail;
+	}
+
+	/*
+	 * Check the packet head room & tail room
+	 */
+	if (unlikely(skb_headroom(skb) < dev->needed_headroom)) {
+		nss_ipsecmgr_error("%p: Insufficient head room :%d in skb: %p\n", priv->nss_ctx, skb_headroom(skb), skb);
+		goto fail;
+	}
+
+	if (unlikely(skb_tailroom(skb) < dev->needed_tailroom)) {
+		nss_ipsecmgr_error("%p: Insufficient tail room:%d in skb: %p\n", priv->nss_ctx, skb_tailroom(skb), skb);
+		goto fail;
+	}
+
+	/*
+	 * Check if packet is given starting from network header
+	 */
+	if (skb->data != skb_network_header(skb)) {
+		nss_ipsecmgr_error("%p: 'Skb data is not starting from IP header", priv->nss_ctx);
+		goto fail;
+	}
+
+	inner_ip = (struct iphdr *)ip_hdr(skb);
+
+	/*
+	 * Validate if packet has ip options
+	 */
+	if ((inner_ip->version != IPVERSION) || (inner_ip->ihl != 5)) {
+		nss_ipsecmgr_error("%p: Unsupported IP header ipver: 0x%x iphdr_len: 0x%x\n", priv->nss_ctx,
+						inner_ip->version, inner_ip->ihl);
+		goto fail;
+	}
+
+	/*
+	 * Check the TTL value
+	 */
+	if ((inner_ip->ttl == 0)) {
+		nss_ipsecmgr_error("%p: IP TTL is zero, unabled to transmit\n", priv->nss_ctx);
+		goto fail;
+	}
+
+	/*
+	 * Send the packet down
+	 */
+	if (nss_ipsec_tx_buf(skb, if_num) != 0) {
+		/*
+		 * TODO: NEED TO STOP THE QUEUE
+		 */
+		goto fail;
+	}
+
+	/*
+	 * Increment the tx count
+	 */
+	encap->total_tx++;
 
 	return NETDEV_TX_OK;
+
+fail:
+	return NETDEV_TX_BUSY;
 }
 
 /*
@@ -1001,7 +1083,6 @@
 		nss_ipsecmgr_error("Unknown rule type(%d) for Del operation\n", type);
 		return false;
 	}
-
 	return nss_ipsecmgr_op_send(dev, &nim, if_num, NSS_IPSEC_MSG_TYPE_DEL_RULE);
 }
 EXPORT_SYMBOL(nss_ipsecmgr_sa_del);
diff --git a/nss_ipv4.c b/nss_ipv4.c
index 05bdea3..68d28b9 100644
--- a/nss_ipv4.c
+++ b/nss_ipv4.c
@@ -18,6 +18,7 @@
  * nss_ipv4.c
  *	NSS IPv4 APIs
  */
+#include <linux/sysctl.h>
 #include <linux/ppp_channel.h>
 #include "nss_tx_rx_common.h"
 
@@ -25,6 +26,8 @@
 extern void nss_rx_metadata_ipv4_create_response(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *nim);
 extern void nss_rx_ipv4_sync(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_conn_sync *nirs);
 
+int nss_ipv4_conn_cfg __read_mostly = 4096;
+
 /*
  * nss_ipv4_driver_conn_sync_update()
  *	Update driver specific information from the messsage.
@@ -300,7 +303,153 @@
 	}
 }
 
+/*
+ * nss_ipv4_conn_cfg_callback()
+ *	call back function for the ipv6 connection configuration handler
+ */
+static void nss_ipv4_conn_cfg_callback(void *app_data, struct nss_if_msg *nim)
+{
+
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("IPv4 connection configuration failed with error: %d\n", nim->cm.error);
+		return;
+	}
+
+	nss_info("IPv4 connection configuration success: %d\n", nim->cm.error);
+}
+
+/*
+ * nss_ipv4_conn_cfg_handler()
+ *	Sets the number of connections for IPv4
+ */
+static int nss_ipv4_conn_cfg_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
+	struct nss_ipv4_msg nim;
+	struct nss_ipv4_rule_conn_cfg_msg *nirccm;
+	nss_tx_status_t nss_tx_status;
+	int ret = 1;
+	uint32_t sum_of_conn = nss_ipv4_conn_cfg + nss_ipv6_conn_cfg;
+
+	/*
+	 * The input should be power of 2.
+	 * Input for ipv4 and ipv6 sum togther should not exceed 8k
+	 * Min. value should be at leat 256 connections. This is the
+	 * minimum connections we will support for each of them.
+	 */
+	if ((nss_ipv4_conn_cfg & (nss_ipv4_conn_cfg - 1)) ||
+		(sum_of_conn > MAX_TOTAL_NUM_CONN_IPV4_IPV6) ||
+		(nss_ipv4_conn_cfg < MIN_NUM_CONN)) {
+		nss_warning("%p: input supported connections (%d) does not adhere\
+				specifications\n1) not power of 2,\n2) is less than \
+				min val: %d, OR\n 	IPv4/6 total exceeds %d\n",
+				nss_ctx,
+				nss_ipv4_conn_cfg,
+				MIN_NUM_CONN,
+				MAX_TOTAL_NUM_CONN_IPV4_IPV6);
+		return ret;
+	}
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+
+	if (ret) {
+		return ret;
+	}
+
+	if ((!write)) {
+		nss_warning("%p: IPv4 supported connections write failed: %d\n", nss_ctx, nss_ipv4_conn_cfg);
+		return ret;
+	}
+
+
+	nss_info("%p: IPv4 supported connections: %d\n", nss_ctx, nss_ipv4_conn_cfg);
+
+	nss_cmn_msg_init(&nim.cm, NSS_IPV4_RX_INTERFACE, NSS_IPV4_TX_CONN_CFG_RULE_MSG,
+	sizeof(struct nss_ipv4_rule_conn_cfg_msg), nss_ipv4_conn_cfg_callback, NULL);
+
+	nirccm = &nim.msg.rule_conn_cfg;
+	nirccm->num_conn = htonl(nss_ipv4_conn_cfg);
+	nss_tx_status = nss_ipv4_tx(nss_ctx, &nim);
+
+	if (nss_tx_status != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_tx error setting IPv4 Connections: %d\n",
+							nss_ctx,
+							nss_ipv4_conn_cfg);
+	}
+	return ret;
+}
+
+static ctl_table nss_ipv4_table[] = {
+	{
+		.procname               = "ipv4_conn",
+		.data                   = &nss_ipv4_conn_cfg,
+		.maxlen                 = sizeof(int),
+		.mode                   = 0644,
+		.proc_handler   	= &nss_ipv4_conn_cfg_handler,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv4_dir[] = {
+	{
+		.procname               = "ipv4cfg",
+		.mode                   = 0555,
+		.child                  = nss_ipv4_table,
+	},
+	{ }
+};
+
+
+static ctl_table nss_ipv4_root_dir[] = {
+	{
+		.procname		= "nss",
+		.mode			= 0555,
+		.child			= nss_ipv4_dir,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv4_root[] = {
+	{
+		.procname		= "dev",
+		.mode			= 0555,
+		.child			= nss_ipv4_root_dir,
+	},
+	{ }
+};
+
+static struct ctl_table_header *nss_ipv4_header;
+
+/*
+ * nss_ipv4_register_sysctl()
+ *	Register sysctl specific to ipv4
+ */
+void nss_ipv4_register_sysctl(void)
+{
+	/*
+	 * Register sysctl table.
+	 */
+	nss_ipv4_header = register_sysctl_table(nss_ipv4_root);
+}
+
+/*
+ * nss_ipv4_unregister_sysctl()
+ *	Unregister sysctl specific to ipv4
+ */
+void nss_ipv4_unregister_sysctl(void)
+{
+	/*
+	 * Unregister sysctl table.
+	 */
+	if (nss_ipv4_header) {
+		unregister_sysctl_table(nss_ipv4_header);
+	}
+}
+
 EXPORT_SYMBOL(nss_ipv4_tx);
 EXPORT_SYMBOL(nss_ipv4_notify_register);
 EXPORT_SYMBOL(nss_ipv4_notify_unregister);
 EXPORT_SYMBOL(nss_ipv4_get_mgr);
+EXPORT_SYMBOL(nss_ipv4_register_sysctl);
+EXPORT_SYMBOL(nss_ipv4_unregister_sysctl);
diff --git a/nss_ipv6.c b/nss_ipv6.c
index 94bfc81..3b51486 100644
--- a/nss_ipv6.c
+++ b/nss_ipv6.c
@@ -25,6 +25,8 @@
 extern void nss_rx_metadata_ipv6_create_response(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_msg *nim);
 extern void nss_rx_ipv6_sync(struct nss_ctx_instance *nss_ctx, struct nss_ipv6_conn_sync *nirs);
 
+int nss_ipv6_conn_cfg __read_mostly = 4096;
+
 /*
  * nss_ipv6_driver_conn_sync_update()
  *	Update driver specific information from the messsage.
@@ -300,8 +302,153 @@
 	}
 }
 
+/*
+ * nss_ipv6_conn_cfg_callback()
+ *	call back function for the ipv6 connection configuration handler
+ */
+static void nss_ipv6_conn_cfg_callback(void *app_data, struct nss_if_msg *nim)
+{
+	if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("IPv6 connection configuration failed with error: %d\n", nim->cm.error);
+		return;
+	}
+
+	nss_info("IPv6 connection configuration success: %d\n", nim->cm.error);
+}
+
+
+/*
+ * nss_ipv6_conn_cfg_handler()
+ *	Sets the number of connections for IPv6
+ */
+static int nss_ipv6_conn_cfg_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct nss_top_instance *nss_top = &nss_top_main;
+	struct nss_ctx_instance *nss_ctx = &nss_top->nss[0];
+	struct nss_ipv6_msg nim;
+	struct nss_ipv6_rule_conn_cfg_msg *nirccm;
+	nss_tx_status_t nss_tx_status;
+	int ret = 1;
+	uint32_t sum_of_conn = nss_ipv4_conn_cfg + nss_ipv6_conn_cfg;
+
+	/*
+	 * Specifications for input
+	 * 1) The input should be power of 2.
+	 * 2) Input for ipv4 and ipv6 sum togther should not exceed 8k
+	 * 3) Min. value should be at leat 256 connections. This is the
+	 * minimum connections we will support for each of them.
+	 */
+	if ((nss_ipv6_conn_cfg & (nss_ipv6_conn_cfg - 1)) ||
+		(sum_of_conn > MAX_TOTAL_NUM_CONN_IPV4_IPV6) ||
+		(nss_ipv6_conn_cfg < MIN_NUM_CONN)) {
+		nss_warning("%p: input supported connections (%d) does not adhere\
+				specifications\n1) not power of 2,\n2) is less than \
+				min val: %d, OR\n 	IPv4/6 total exceeds %d\n",
+				nss_ctx,
+				nss_ipv6_conn_cfg,
+				MIN_NUM_CONN,
+				MAX_TOTAL_NUM_CONN_IPV4_IPV6);
+		return ret;
+	}
+
+	ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+
+	if (ret) {
+		return ret;
+	}
+
+	if (!write) {
+		nss_warning("%p: IPv6 supported connections write failed: %d\n", nss_ctx, nss_ipv6_conn_cfg);
+		return ret;
+	}
+
+	nss_info("%p: IPv6 supported connections: %d\n", nss_ctx, nss_ipv6_conn_cfg);
+
+	nss_cmn_msg_init(&nim.cm, NSS_IPV6_RX_INTERFACE, NSS_IPV6_TX_CONN_CFG_RULE_MSG,
+		sizeof(struct nss_ipv6_rule_conn_cfg_msg), nss_ipv6_conn_cfg_callback, NULL);
+
+	nirccm = &nim.msg.rule_conn_cfg;
+	nirccm->num_conn = htonl(nss_ipv6_conn_cfg);
+	nss_tx_status = nss_ipv6_tx(nss_ctx, &nim);
+
+	if (nss_tx_status != NSS_TX_SUCCESS) {
+		nss_warning("%p: nss_tx error setting IPv6 Connections: %d\n",
+						nss_ctx,
+						nss_ipv6_conn_cfg);
+	}
+	return ret;
+}
+
+static ctl_table nss_ipv6_table[] = {
+	{
+		.procname               = "ipv6_conn",
+		.data                   = &nss_ipv6_conn_cfg,
+		.maxlen                 = sizeof(int),
+		.mode                   = 0644,
+		.proc_handler   	= &nss_ipv6_conn_cfg_handler,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv6_dir[] = {
+	{
+		.procname               = "ipv6cfg",
+		.mode                   = 0555,
+		.child                  = nss_ipv6_table,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv6_root_dir[] = {
+	{
+		.procname		= "nss",
+		.mode			= 0555,
+		.child			= nss_ipv6_dir,
+	},
+	{ }
+};
+
+static ctl_table nss_ipv6_root[] = {
+	{
+		.procname		= "dev",
+		.mode			= 0555,
+		.child			= nss_ipv6_root_dir,
+	},
+	{ }
+};
+
+static struct ctl_table_header *nss_ipv6_header;
+
+/*
+ * nss_ipv6_register_sysctl()
+ *	Register sysctl specific to ipv4
+ */
+void nss_ipv6_register_sysctl(void)
+{
+	/*
+	 * Register sysctl table.
+	 */
+	nss_ipv6_header = register_sysctl_table(nss_ipv6_root);
+}
+
+/*
+ * nss_ipv6_unregister_sysctl()
+ *	Unregister sysctl specific to ipv4
+ */
+void nss_ipv6_unregister_sysctl(void)
+{
+	/*
+	 * Unregister sysctl table.
+	 */
+	if (nss_ipv6_header) {
+		unregister_sysctl_table(nss_ipv6_header);
+	}
+}
+
 EXPORT_SYMBOL(nss_ipv6_tx);
 EXPORT_SYMBOL(nss_ipv6_notify_register);
 EXPORT_SYMBOL(nss_ipv6_notify_unregister);
 EXPORT_SYMBOL(nss_ipv6_get_mgr);
 EXPORT_SYMBOL(nss_ipv6_register_handler);
+EXPORT_SYMBOL(nss_ipv6_register_sysctl);
+EXPORT_SYMBOL(nss_ipv6_unregister_sysctl);
diff --git a/nss_qdisc/Makefile b/nss_qdisc/Makefile
index 4051a0e..ec25d0d 100755
--- a/nss_qdisc/Makefile
+++ b/nss_qdisc/Makefile
@@ -22,4 +22,5 @@
 			nss_prio.o \
 			nss_bf.o \
 			nss_wrr.o \
-			nss_htb.o
+			nss_htb.o \
+			nss_blackhole.o
diff --git a/nss_qdisc/nss_blackhole.c b/nss_qdisc/nss_blackhole.c
new file mode 100644
index 0000000..6a4e753
--- /dev/null
+++ b/nss_qdisc/nss_blackhole.c
@@ -0,0 +1,253 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2014, 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+#include "nss_qdisc.h"
+
+/*
+ * nss_blackhole private qdisc structure
+ */
+struct nss_blackhole_sched_data {
+	struct nss_qdisc nq;	/* Common base class for all nss qdiscs */
+	u8 set_default;		/* Flag to set qdisc as default qdisc for enqueue */
+};
+
+/*
+ * nss_blackhole_enqueue()
+ *	Enqueue API for nss blackhole qdisc.
+ */
+static int nss_blackhole_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	return nss_qdisc_enqueue(skb, sch);
+}
+
+/*
+ * nss_blackhole_dequeue()
+ * 	Dequeue API for nss blackhole qdisc.
+ */
+static struct sk_buff *nss_blackhole_dequeue(struct Qdisc *sch)
+{
+	return nss_qdisc_dequeue(sch);
+}
+
+/*
+ * nss_blackhole_drop()
+ *	The following function drops a packet from HLOS queue.
+ *
+ * Note, this does not drop packets from queues in the NSS. We do not support that.
+ */
+static unsigned int nss_blackhole_drop(struct Qdisc *sch)
+{
+	nss_qdisc_info("%s: qdisc %x dropping\n", __func__, sch->handle);
+	return nss_qdisc_drop(sch);
+}
+
+/*
+ * nss_blackhole_reset()
+ *	Resets the nss blackhole qdisc.
+ */
+static void nss_blackhole_reset(struct Qdisc *sch)
+{
+	nss_qdisc_info("%s: qdisc %x resetting\n", __func__, sch->handle);
+	nss_qdisc_reset(sch);
+}
+
+/*
+ * nss_blackhole_destroy()
+ *	Destroys the nss blackhole qdisc.
+ */
+static void nss_blackhole_destroy(struct Qdisc *sch)
+{
+	struct nss_qdisc *nq = (struct nss_qdisc *)qdisc_priv(sch);
+
+	/*
+	 * Stop the polling of basic stats
+	 */
+	nss_qdisc_stop_basic_stats_polling(nq);
+
+	nss_qdisc_info("%s: destroying qdisc %x\n", __func__, sch->handle);
+	nss_qdisc_destroy(nq);
+}
+
+/*
+ * nss_blackhole policy structure
+ */
+static const struct nla_policy nss_blackhole_policy[TCA_NSSBLACKHOLE_MAX + 1] = {
+	[TCA_NSSBLACKHOLE_PARMS] = { .len = sizeof(struct tc_nssblackhole_qopt) },
+};
+
+/*
+ * nss_blackhole_change()
+ *	Function call used to configure the parameters of the nss blackhole qdisc.
+ */
+static int nss_blackhole_change(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct nss_blackhole_sched_data *q;
+	struct nlattr *na[TCA_NSSBLACKHOLE_MAX + 1];
+	struct tc_nssblackhole_qopt *qopt;
+	int err;
+	struct nss_if_msg nim;
+
+	q = qdisc_priv(sch);
+
+	if (opt == NULL) {
+		return -EINVAL;
+	}
+
+	err = nla_parse_nested(na, TCA_NSSBLACKHOLE_MAX, opt, nss_blackhole_policy);
+	if (err < 0)
+		return err;
+
+	if (na[TCA_NSSBLACKHOLE_PARMS] == NULL)
+		return -EINVAL;
+
+	qopt = nla_data(na[TCA_NSSBLACKHOLE_PARMS]);
+
+	/*
+	 * Required for basic stats display
+	 */
+	sch->limit = 0;
+
+	q->set_default = qopt->set_default;
+	nss_qdisc_info("%s: qdisc set_default = %u\n", __func__, qopt->set_default);
+
+	/*
+	 * Underneath nss_bloackhole uses a fifo in the NSS. This is why we are sending down a configuration
+	 * message to a fifo node. There are no blackhole shaper in the NSS as yet.
+	 *
+	 * Note: We simply set the limit of fifo to zero to get the blackhole behavior.
+	 */
+	nim.msg.shaper_configure.config.msg.shaper_node_config.qos_tag = q->nq.qos_tag;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.fifo_param.limit = 0;
+	nim.msg.shaper_configure.config.msg.shaper_node_config.snc.fifo_param.drop_mode = NSS_SHAPER_FIFO_DROP_MODE_TAIL;
+	if (nss_qdisc_configure(&q->nq, &nim, NSS_SHAPER_CONFIG_TYPE_FIFO_CHANGE_PARAM) < 0) {
+		nss_qdisc_error("%s: qdisc %x configuration failed\n", __func__, sch->handle);
+		return -EINVAL;
+	}
+
+	/*
+	 * There is nothing we need to do if the qdisc is not
+	 * set as default qdisc.
+	 */
+	if (q->set_default == 0)
+		return 0;
+
+	/*
+	 * Set this qdisc to be the default qdisc for enqueuing packets.
+	 */
+	if (nss_qdisc_set_default(&q->nq) < 0) {
+		nss_qdisc_error("%s: qdisc %x set_default failed\n", __func__, sch->handle);
+		return -EINVAL;
+	}
+
+	nss_qdisc_info("%s: qdisc %x set as default\n", __func__, q->nq.qos_tag);
+	return 0;
+}
+
+/*
+ * nss_blackhole_init()
+ *	Initializes a nss blackhole qdisc.
+ */
+static int nss_blackhole_init(struct Qdisc *sch, struct nlattr *opt)
+{
+	struct nss_qdisc *nq = qdisc_priv(sch);
+
+	if (opt == NULL)
+		return -EINVAL;
+
+	nss_qdisc_info("%s: qdisc %x initializing\n", __func__, sch->handle);
+	nss_blackhole_reset(sch);
+
+	if (nss_qdisc_init(sch, nq, NSS_SHAPER_NODE_TYPE_FIFO, 0) < 0)
+		return -EINVAL;
+
+	nss_qdisc_info("%s: qdisc %x initialized with parent %x\n", __func__, sch->handle, sch->parent);
+	if (nss_blackhole_change(sch, opt) < 0) {
+		nss_qdisc_destroy(nq);
+		return -EINVAL;
+	}
+
+	/*
+	 * Start the stats polling timer
+	 */
+	nss_qdisc_start_basic_stats_polling(nq);
+
+	return 0;
+}
+
+/*
+ * nss_blackhole_dump()
+ *	Dumps qdisc parameters for nss blackhole.
+ */
+static int nss_blackhole_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+	struct nss_blackhole_sched_data *q;
+	struct nlattr *opts = NULL;
+	struct tc_nssblackhole_qopt opt;
+
+	nss_qdisc_info("%s: qdisc %x dumping!\n", __func__, sch->handle);
+
+	q = qdisc_priv(sch);
+	if (q == NULL) {
+		return -1;
+	}
+
+	opt.set_default = q->set_default;
+
+	opts = nla_nest_start(skb, TCA_OPTIONS);
+	if (opts == NULL) {
+		goto nla_put_failure;
+	}
+	if (nla_put(skb, TCA_NSSBLACKHOLE_PARMS, sizeof(opt), &opt))
+		goto nla_put_failure;
+
+	return nla_nest_end(skb, opts);
+
+nla_put_failure:
+	nla_nest_cancel(skb, opts);
+	return -EMSGSIZE;
+}
+
+/*
+ * nss_blackhole_peek()
+ *	Peeks the first packet in queue for this qdisc.
+ *
+ * Note: This just peeks at the first packet in what is present in HLOS. This does not
+ * perform an actual peak into the queue in the NSS. Given the async delay between
+ * the processors, there is less use in implementing this function.
+ */
+static struct sk_buff *nss_blackhole_peek(struct Qdisc *sch)
+{
+	nss_qdisc_info("%s: qdisc %x peeked\n", __func__, sch->handle);
+	return nss_qdisc_peek(sch);
+}
+
+/*
+ * Registration structure for nss blackhole qdisc
+ */
+struct Qdisc_ops nss_blackhole_qdisc_ops __read_mostly = {
+	.id		=	"nssblackhole",
+	.priv_size	=	sizeof(struct nss_blackhole_sched_data),
+	.enqueue	=	nss_blackhole_enqueue,
+	.dequeue	=	nss_blackhole_dequeue,
+	.peek		=	nss_blackhole_peek,
+	.drop		=	nss_blackhole_drop,
+	.init		=	nss_blackhole_init,
+	.reset		=	nss_blackhole_reset,
+	.destroy	=	nss_blackhole_destroy,
+	.change		=	nss_blackhole_change,
+	.dump		=	nss_blackhole_dump,
+	.owner		=	THIS_MODULE,
+};
diff --git a/nss_qdisc/nss_blackhole.h b/nss_qdisc/nss_blackhole.h
new file mode 100644
index 0000000..58dce8b
--- /dev/null
+++ b/nss_qdisc/nss_blackhole.h
@@ -0,0 +1,17 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2014, 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+extern struct Qdisc_ops nss_blackhole_qdisc_ops;
diff --git a/nss_qdisc/nss_fifo.c b/nss_qdisc/nss_fifo.c
index 4b873c4..7f4ab45 100644
--- a/nss_qdisc/nss_fifo.c
+++ b/nss_qdisc/nss_fifo.c
@@ -177,7 +177,7 @@
 
 	return nla_nest_end(skb, opts);
 
-nla_put_failure:		
+nla_put_failure:
 	nla_nest_cancel(skb, opts);
 	return -EMSGSIZE;
 }
diff --git a/nss_qdisc/nss_qdisc.c b/nss_qdisc/nss_qdisc.c
index 84bea64..7eaff17 100644
--- a/nss_qdisc/nss_qdisc.c
+++ b/nss_qdisc/nss_qdisc.c
@@ -24,6 +24,7 @@
 #include "nss_wrr.h"
 #include "nss_wfq.h"
 #include "nss_htb.h"
+#include "nss_blackhole.h"
 
 void *nss_qdisc_ctx;			/* Shaping context for nss_qdisc */
 wait_queue_head_t nss_qdics_wq;			/* Wait queue used to wait on responses from the NSS */
@@ -1014,7 +1015,11 @@
 
 	INIT_HLIST_NODE(&nq->hnode);
 	hash = nss_qdisc_gen_hash(nq->qos_tag);
+
+	spin_lock_bh(&nq_root->lock);
 	hlist_add_head(&nq->hnode, &nq_root->hash[hash]);
+	spin_unlock_bh(&nq_root->lock);
+
 	nss_qdisc_trace("%s: added qdisc %x to root %x's hash at index %u\n",
 				__func__, nq->qos_tag, nq_root->qos_tag, hash);
 }
@@ -1023,10 +1028,17 @@
  * nss_qdisc_root_hash_remove()
  *	Removes nss qdisc from root hash.
  */
-static inline void nss_qdisc_root_hash_remove(struct nss_qdisc *nq)
+static inline void nss_qdisc_root_hash_remove(struct nss_qdisc *nq_root, struct nss_qdisc *nq)
 {
 	nss_qdisc_trace("%s: deleting qdisc %x from root hash\n", __func__, nq->qos_tag);
+
+	/*
+	 * We need to hold the root lock since that is the node
+	 * that maintains the hash list.
+	 */
+	spin_lock_bh(&nq_root->lock);
 	hlist_del(&nq->hnode);
+	spin_unlock_bh(&nq_root->lock);
 }
 
 /*
@@ -1051,6 +1063,7 @@
 	/*
 	 * Parse through the list to find a match.
 	 */
+	spin_lock_bh(&nq_root->lock);
 	hlist_for_each_entry(nq, n, &nq_root->hash[hash], hnode) {
 
 		/*
@@ -1069,17 +1082,23 @@
 		 * more likely that we find our match at the head.
 		 */
 		if (likely(head)) {
+			spin_unlock_bh(&nq_root->lock);
 			return nq;
 		}
 
 		/*
 		 * If the match was not at the head, we detach and attach it
-		 * back at the front/head.
+		 * back at the front/head. These helper functions need to be
+		 * called outside the lock.
 		 */
-		nss_qdisc_root_hash_remove(nq);
+		spin_unlock_bh(&nq_root->lock);
+		nss_qdisc_root_hash_remove(nq_root, nq);
 		nss_qdisc_root_hash_insert(nq_root, nq);
+
 		return nq;
 	}
+
+	spin_unlock_bh(&nq_root->lock);
 	return NULL;
 }
 
@@ -1681,14 +1700,15 @@
 		}
 
 		/*
+		 * Free allocated hash table at root
+		 */
+		nss_qdisc_root_hash_free(nq);
+
+		/*
 		 * Begin by freeing the root shaper node
 		 */
 		nss_qdisc_root_cleanup_free_node(nq);
 
-		/*
-		 * Free allocated hash table at root
-		 */
-		nss_qdisc_root_hash_free(nq);
 	} else {
 		/*
 		 * Begin by removing ourselves from the root hash.
@@ -1696,10 +1716,7 @@
 		 */
 		struct Qdisc *root = qdisc_root(nq->qdisc);
 		struct nss_qdisc *nq_root = qdisc_priv(root);
-		spin_lock_bh(&nq_root->lock);
-		nss_qdisc_root_hash_remove(nq);
-		spin_unlock_bh(&nq_root->lock);
-
+		nss_qdisc_root_hash_remove(nq_root, nq);
 		nss_qdisc_child_cleanup_free_node(nq);
 	}
 
@@ -1737,6 +1754,12 @@
 	int msg_type;
 
 	/*
+	 * Initialize locks
+	 */
+	spin_lock_init(&nq->bounce_protection_lock);
+	spin_lock_init(&nq->lock);
+
+	/*
 	 * Record our qdisc and type in the private region for handy use
 	 */
 	nq->qdisc = sch;
@@ -2385,6 +2408,11 @@
 		return ret;
 	nss_qdisc_info("nsshtb registered");
 
+	ret = register_qdisc(&nss_blackhole_qdisc_ops);
+	if (ret != 0)
+		return ret;
+	nss_qdisc_info("nssblackhole registered");
+
 	ret = register_netdevice_notifier(&nss_qdisc_device_notifier);
 	if (ret != 0)
 		return ret;
@@ -2422,6 +2450,9 @@
 	unregister_qdisc(&nss_htb_qdisc_ops);
 	nss_qdisc_info("nsshtb unregistered\n");
 
+	unregister_qdisc(&nss_blackhole_qdisc_ops);
+	nss_qdisc_info("nssblackhole unregistered\n");
+
 	unregister_netdevice_notifier(&nss_qdisc_device_notifier);
 }
 
diff --git a/nss_tun6rd.c b/nss_tun6rd.c
index b4d83d0..705f041 100644
--- a/nss_tun6rd.c
+++ b/nss_tun6rd.c
@@ -24,9 +24,11 @@
 {
 	struct nss_tun6rd_msg *ntm = (struct nss_tun6rd_msg *)ncm;
 	void *ctx;
+
 	nss_tun6rd_msg_callback_t cb;
 
-	BUG_ON(ncm->interface != NSS_TUN6RD_INTERFACE);
+	BUG_ON(!nss_is_dynamic_interface(ncm->interface));
+
 	/*
 	 * Is this a valid request/response packet?
 	 */
@@ -77,7 +79,6 @@
 	cb(ctx, ntm);
 }
 
-
 /*
  * nss_tun6rd_tx()
  * 	Transmit a tun6rd message to NSSFW
@@ -98,7 +99,7 @@
 	/*
 	 * Sanity check the message
 	 */
-	if (ncm->interface != NSS_TUN6RD_INTERFACE) {
+	if (!nss_is_dynamic_interface(ncm->interface)) {
 		nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
 		return NSS_TX_FAILURE;
 	}
@@ -151,17 +152,26 @@
 /*
  * nss_register_tun6rd_if()
  */
-struct nss_ctx_instance *nss_register_tun6rd_if(uint32_t if_num,
-                                nss_tun6rd_callback_t tun6rd_callback,
-                                nss_tun6rd_msg_callback_t event_callback, struct net_device *netdev)
+struct nss_ctx_instance *nss_register_tun6rd_if(uint32_t if_num, nss_tun6rd_callback_t tun6rd_callback,
+			nss_tun6rd_msg_callback_t event_callback, struct net_device *netdev)
 {
-        nss_assert((if_num >= NSS_MAX_VIRTUAL_INTERFACES) && (if_num < NSS_MAX_NET_INTERFACES));
+	nss_assert((if_num >=  NSS_DYNAMIC_IF_START) && (if_num < NSS_SPECIAL_IF_START));
 
-        nss_top_main.if_ctx[if_num] = netdev;
-        nss_top_main.if_rx_callback[if_num] = tun6rd_callback;
-        nss_top_main.tun6rd_msg_callback = event_callback;
+	nss_top_main.if_ctx[if_num] = netdev;
+	nss_top_main.if_rx_callback[if_num] = tun6rd_callback;
+	nss_top_main.tun6rd_msg_callback = event_callback;
 
-        return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.tun6rd_handler_id];
+	nss_core_register_handler(if_num, nss_tun6rd_handler, NULL);
+
+	return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.tun6rd_handler_id];
+}
+
+/*
+ * nss_get_tun6rd_context()
+ */
+struct nss_ctx_instance * nss_tun6rd_get_context()
+{
+	return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.tun6rd_handler_id];
 }
 
 /*
@@ -169,22 +179,16 @@
  */
 void nss_unregister_tun6rd_if(uint32_t if_num)
 {
-        nss_assert((if_num >= NSS_MAX_VIRTUAL_INTERFACES) && (if_num < NSS_MAX_NET_INTERFACES));
+	nss_assert(nss_is_dynamic_interface(ncm->interface));
 
-        nss_top_main.if_rx_callback[if_num] = NULL;
-        nss_top_main.if_ctx[if_num] = NULL;
-        nss_top_main.tun6rd_msg_callback = NULL;
+	nss_top_main.if_rx_callback[if_num] = NULL;
+	nss_top_main.if_ctx[if_num] = NULL;
+	nss_top_main.tun6rd_msg_callback = NULL;
+
+	nss_core_unregister_handler(if_num);
 }
 
-/*
- * nss_tun6rd_register_handler()
- */
-void nss_tun6rd_register_handler()
-{
-	nss_core_register_handler(NSS_TUN6RD_INTERFACE, nss_tun6rd_handler, NULL);
-}
-
-
+EXPORT_SYMBOL(nss_tun6rd_get_context);
 EXPORT_SYMBOL(nss_tun6rd_tx);
 EXPORT_SYMBOL(nss_register_tun6rd_if);
 EXPORT_SYMBOL(nss_unregister_tun6rd_if);
diff --git a/nss_tx_rx_common.h b/nss_tx_rx_common.h
index 9d155bd..9e29a30 100644
--- a/nss_tx_rx_common.h
+++ b/nss_tx_rx_common.h
@@ -69,7 +69,6 @@
 extern void nss_ipv4_register_handler(void);
 extern void nss_ipv6_register_handler(void);
 extern void nss_n2h_register_handler(void);
-extern void nss_tun6rd_register_handler(void);
 extern void nss_tunipip6_register_handler(void);
 extern void nss_pppoe_register_handler(void);
 extern void nss_core_freq_register_handler(void);