[qca-nss-clients] NSS DTLS Manager

- NSS DTLS (Datagram Transport Layer Security) client
  manager for DTLS v1.0/1.2.

Change-Id: Ic69acde0cc0108b5ee0dfec77d7d2854ab86e1dd
Signed-off-by: Tushar Mathur <tushar@codeaurora.org>
diff --git a/Makefile b/Makefile
index f4639db..71ebb8f 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,11 @@
 obj-y+= nss_qdisc/
 obj-y+= ipsecmgr/
 
+# DTLS manager
+ifneq ($(findstring 3.4, $(KERNELVERSION)),)
+obj-y+=dtls/
+endif
+
 # CAPWAP Manager
 ifneq ($(findstring 3.4, $(KERNELVERSION)),)
 obj-y+= capwapmgr/
diff --git a/dtls/Makefile b/dtls/Makefile
new file mode 100644
index 0000000..586fe01
--- /dev/null
+++ b/dtls/Makefile
@@ -0,0 +1,7 @@
+# Makefile for DTLS manager
+
+ccflags-y += $(NSS_CCFLAGS) -I$(obj)/../exports
+ccflags-y += -DNSS_DTLSMGR_DEBUG_LEVEL=0
+
+obj-m += qca-nss-dtlsmgr.o
+qca-nss-dtlsmgr-objs := nss_connmgr_dtls.o nss_connmgr_dtls_netdev.o
diff --git a/dtls/nss_connmgr_dtls.c b/dtls/nss_connmgr_dtls.c
new file mode 100644
index 0000000..5aadbee
--- /dev/null
+++ b/dtls/nss_connmgr_dtls.c
@@ -0,0 +1,1156 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2016, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_connmgr_dtls.c
+ *	NSS DTLS Manager
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/ipv6.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/atomic.h>
+
+#include <nss_api_if.h>
+#include <nss_dynamic_interface.h>
+
+#include "nss_connmgr_dtls.h"
+
+/*
+ * Global DTLS context
+ */
+static struct nss_dtlsmgr_ctx g_ctx;
+
+/*
+ * nss_dtlsmgr_session_insert()
+ *	Insert a DTLS session into global list of sessions.
+ *	Must be called with global context lock held.
+ */
+static bool nss_dtlsmgr_session_insert(struct nss_dtlsmgr_session *s)
+{
+	int32_t i;
+
+	assert_spin_locked(&g_ctx.lock);
+
+	for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
+		if (g_ctx.session[i] == NULL) {
+			g_ctx.session[i] = s;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/*
+ * nss_dtlsmgr_session_remove()
+ *	Remove a DTLS session from list of sessions.
+ *	Must be called with global context lock held.
+ */
+static struct nss_dtlsmgr_session *nss_dtlsmgr_session_remove(uint32_t sif)
+{
+	int32_t i;
+	struct nss_dtlsmgr_session *s;
+
+	assert_spin_locked(&g_ctx.lock);
+
+	for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
+		s = g_ctx.session[i];
+		if (!s)
+			continue;
+
+		nss_dtlsmgr_assert(s->magic == NSS_DTLSMGR_SESSION_MAGIC);
+		if (s->nss_dtls_if == sif) {
+			g_ctx.session[i] = NULL;
+			return s;
+		}
+	}
+
+	return NULL;
+}
+
+/*
+ * nss_dtlsmgr_session_find()
+ *	Find a DTLS session from list of sessions.
+ *	Must be called with global context lock held.
+ */
+static struct nss_dtlsmgr_session *nss_dtlsmgr_session_find(uint32_t sif)
+{
+	int32_t i;
+	struct nss_dtlsmgr_session *s;
+
+	assert_spin_locked(&g_ctx.lock);
+
+	for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
+		s = g_ctx.session[i];
+		if (!s)
+			continue;
+
+		nss_dtlsmgr_assert(s->magic == NSS_DTLSMGR_SESSION_MAGIC);
+		if (s->nss_dtls_if == sif)
+			return s;
+	}
+
+	return NULL;
+}
+
+/*
+ * nss_dtlsmgr_session_cleanup()
+ *	Cleanup DTLS session
+ */
+static void nss_dtlsmgr_session_cleanup(struct nss_dtlsmgr_session *ds)
+{
+	nss_crypto_status_t crypto_status;
+
+	nss_dtlsmgr_info("%p: DTLS session I/F %u cleanup\n",
+			 &g_ctx, ds->nss_dtls_if);
+
+	nss_dtls_unregister_if(ds->nss_dtls_if);
+
+	nss_dtlsmgr_netdev_destroy(ds);
+
+	nss_dynamic_interface_dealloc_node(ds->nss_dtls_if,
+					   NSS_DYNAMIC_INTERFACE_TYPE_DTLS);
+
+	crypto_status = nss_crypto_session_free(g_ctx.crypto_hdl,
+						ds->crypto_idx_encap);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_dtlsmgr_info("%p: dtls I/F:%u, unable to free crypto session id:%d\n",
+				 &g_ctx, ds->nss_dtls_if, ds->crypto_idx_encap);
+	}
+
+	crypto_status = nss_crypto_session_free(g_ctx.crypto_hdl,
+						ds->crypto_idx_decap);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_dtlsmgr_info("%p: dtls I/F:%u, unable to free crypto session id:%d\n",
+				 &g_ctx, ds->nss_dtls_if, ds->crypto_idx_decap);
+	}
+
+	if (ds->cidx_decap_pending != NSS_CRYPTO_MAX_IDXS) {
+		crypto_status = nss_crypto_session_free(g_ctx.crypto_hdl,
+							ds->cidx_decap_pending);
+		if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+			nss_dtlsmgr_info("%p: dtls I/F:%u, unable to free crypto session id:%d\n", &g_ctx, ds->nss_dtls_if, ds->cidx_decap_pending);
+		}
+	}
+
+	if (ds->cidx_encap_pending != NSS_CRYPTO_MAX_IDXS) {
+		crypto_status = nss_crypto_session_free(g_ctx.crypto_hdl,
+							ds->cidx_encap_pending);
+		if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+			nss_dtlsmgr_info("%p: dtls I/F:%u, unable to free crypto session id:%d\n", &g_ctx, ds->nss_dtls_if, ds->cidx_encap_pending);
+		}
+	}
+
+	ds->magic = 0;
+	kfree(ds);
+}
+
+/*
+ * nss_dtlsmgr_session_find_and_ref()
+ *	Find a DTLS session from list of sessions and
+ *	increments reference count. Must be called with
+ *	global context lock held.
+ */
+static struct nss_dtlsmgr_session *nss_dtlsmgr_session_find_and_ref(uint32_t sif)
+{
+	struct nss_dtlsmgr_session *s;
+
+	s = nss_dtlsmgr_session_find(sif);
+	if (atomic_inc_and_test(&s->ref)) {
+		nss_dtlsmgr_assert(false);
+	}
+
+	return s;
+}
+
+/*
+ * nss_dtlsmgr_session_ref_dec()
+ *	Decrement reference count of a DTLS session.
+ *	Perform session cleanup if reference count falls to zero.
+ */
+static void nss_dtlsmgr_session_ref_dec(struct nss_dtlsmgr_session *s)
+{
+	if (atomic_dec_and_test(&s->ref)) {
+		nss_dtlsmgr_session_cleanup(s);
+	}
+}
+
+/*
+ * nss_connmgr_dtls_data_receive()
+ *	Handler to receive packets from NSS.
+ */
+static void nss_connmgr_dtls_data_receive(struct net_device *dev,
+					  struct sk_buff *skb,
+					  struct napi_struct *napi)
+{
+	struct nss_dtlsmgr_netdev_priv *priv;
+	struct nss_dtlsmgr_session *s;
+	__be32 meta;
+
+	BUG_ON(dev == NULL);
+	BUG_ON(skb == NULL);
+
+	dev_hold(dev);
+	priv = netdev_priv(dev);
+	s = priv->s;
+
+	/*
+	 * Get DTLS metadata
+	 */
+	meta = *(__be32 *)skb->data;
+	meta = ntohl(meta);
+	if (NSS_DTLSMGR_METADATA_CTYPE(meta) != NSS_DTLSMGR_CTYPE_APP) {
+		nss_dtlsmgr_info("%p: Dropping non app dtls pkt\n", skb);
+		dev_kfree_skb_any(skb);
+		dev_put(dev);
+		return;
+	}
+
+	if (NSS_DTLSMGR_METADATA_ERROR(meta) != NSS_DTLSMGR_METADATA_ERROR_OK) {
+		nss_dtlsmgr_info("%p: Dropping error pkt\n", skb);
+		dev_kfree_skb_any(skb);
+		dev_put(dev);
+		return;
+	}
+
+	/*
+	 * Remove four bytes at start of
+	 * buffer containing the DTLS metadata.
+	 */
+	skb_pull(skb, NSS_DTLSMGR_METADATA_LEN);
+
+	skb_reset_network_header(skb);
+	skb->pkt_type = PACKET_HOST;
+	skb->skb_iif = dev->ifindex;
+	skb->dev = dev;
+	if (s->flags & NSS_DTLSMGR_IPV6_ENCAP)
+		skb->protocol = htons(ETH_P_IPV6);
+	else
+		skb->protocol = htons(ETH_P_IP);
+
+	netif_receive_skb(skb);
+	dev_put(dev);
+}
+
+/*
+ * nss_connmgr_dtls_event_receive()
+ *	Event Callback to receive events from NSS
+ */
+static void nss_connmgr_dtls_event_receive(void *if_ctx,
+					   struct nss_dtls_msg *tnlmsg)
+{
+	struct nss_dtlsmgr_session *ds = (struct nss_dtlsmgr_session *)if_ctx;
+	struct nss_dtlsmgr_session_stats_update stats;
+	struct nss_dtls_session_stats *msg_stats;
+
+	spin_lock(&g_ctx.lock);
+	ds = nss_dtlsmgr_session_find_and_ref(tnlmsg->cm.interface);
+	spin_unlock(&g_ctx.lock);
+
+	if (!ds) {
+		return;
+	}
+
+	switch (tnlmsg->cm.type) {
+	case NSS_DTLS_MSG_SESSION_STATS:
+		if (ds->stats_update_cb == NULL)
+			break;
+
+		memset(&stats, 0, sizeof(struct nss_dtlsmgr_session_stats_update));
+		msg_stats = &tnlmsg->msg.stats;
+
+		stats.tx_pkts = msg_stats->node_stats.tx_packets;
+		stats.rx_pkts = msg_stats->node_stats.rx_packets;
+		stats.rx_dropped = msg_stats->node_stats.rx_dropped;
+		stats.tx_auth_done = msg_stats->tx_auth_done;
+		stats.rx_auth_done = msg_stats->rx_auth_done;
+		stats.tx_cipher_done = msg_stats->tx_cipher_done;
+		stats.rx_cipher_done = msg_stats->rx_cipher_done;
+		stats.tx_cbuf_alloc_fail = msg_stats->tx_cbuf_alloc_fail;
+		stats.rx_cbuf_alloc_fail = msg_stats->rx_cbuf_alloc_fail;
+		stats.tx_cenqueue_fail = msg_stats->tx_cenqueue_fail;
+		stats.rx_cenqueue_fail = msg_stats->rx_cenqueue_fail;
+		stats.tx_dropped_hroom = msg_stats->tx_dropped_hroom;
+		stats.tx_dropped_troom = msg_stats->tx_dropped_troom;
+		stats.tx_forward_enqueue_fail = msg_stats->tx_forward_enqueue_fail;
+		stats.rx_forward_enqueue_fail = msg_stats->rx_forward_enqueue_fail;
+		stats.rx_invalid_version = msg_stats->rx_invalid_version;
+		stats.rx_invalid_epoch = msg_stats->rx_invalid_epoch;
+		stats.rx_malformed = msg_stats->rx_malformed;
+		stats.rx_cipher_fail = msg_stats->rx_cipher_fail;
+		stats.rx_auth_fail = msg_stats->rx_auth_fail;
+		stats.rx_capwap_classify_fail = msg_stats->rx_capwap_classify_fail;
+		stats.rx_replay_fail = msg_stats->rx_replay_fail;
+		stats.rx_replay_duplicate = msg_stats->rx_replay_duplicate;
+		stats.rx_replay_out_of_window = msg_stats->rx_replay_out_of_window;
+		stats.outflow_queue_full = msg_stats->outflow_queue_full;
+		stats.decap_queue_full = msg_stats->decap_queue_full;
+		stats.pbuf_alloc_fail = msg_stats->pbuf_alloc_fail;
+		stats.pbuf_copy_fail = msg_stats->pbuf_copy_fail;
+		stats.epoch = msg_stats->epoch;
+		stats.tx_seq_high = msg_stats->tx_seq_high;
+		stats.tx_seq_low = msg_stats->tx_seq_low;
+
+		ds->stats_update_cb(ds->nss_dtls_if, &stats);
+		break;
+
+	default:
+		nss_dtlsmgr_info("%p: Unknown Event from NSS\n", &g_ctx);
+		break;
+	}
+
+	nss_dtlsmgr_session_ref_dec(ds);
+}
+
+/*
+ * nss_dtlsmgr_get_cipher_iv_len()
+ *	Get cipher IV length.
+ */
+static uint32_t nss_dtlsmgr_get_cipher_iv_len(uint32_t cipher_algo)
+{
+	switch (cipher_algo) {
+	case NSS_CRYPTO_CIPHER_AES:
+		return NSS_CRYPTO_MAX_IVLEN_AES;
+
+	case NSS_CRYPTO_CIPHER_DES:
+		return NSS_CRYPTO_MAX_IVLEN_DES;
+
+	case NSS_CRYPTO_CIPHER_NULL:
+	default:
+		return NSS_CRYPTO_MAX_IVLEN_NULL;
+	}
+}
+
+/*
+ * nss_dtlsmgr_get_auth_hash_len()
+ *	Get auth hash length.
+ */
+static uint32_t nss_dtlsmgr_get_auth_hash_len(uint32_t auth_algo)
+{
+	switch (auth_algo) {
+	case NSS_CRYPTO_AUTH_SHA1_HMAC:
+		return NSS_CRYPTO_MAX_HASHLEN_SHA1;
+
+	case NSS_CRYPTO_AUTH_SHA256_HMAC:
+		return NSS_CRYPTO_MAX_HASHLEN_SHA256;
+
+	case NSS_CRYPTO_AUTH_NULL:
+	default:
+		return NSS_CRYPTO_MAX_HASHLEN;
+	}
+}
+
+/*
+ * nss_dtlsmgr_session_create_with_crypto()
+ *	Create DTLS session and associated crypto sessions.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_session_create_with_crypto(struct nss_dtlsmgr_session_create_config *in_data, struct nss_dtlsmgr_return_data *out_data)
+{
+	nss_crypto_status_t crypto_status;
+	struct nss_dtlsmgr_session *ds;
+	struct nss_crypto_params params;
+	struct nss_dtls_msg dtlsmsg;
+	int32_t i = 0;
+	struct nss_crypto_key cipher;
+	struct nss_crypto_key auth;
+	struct nss_dtls_session_configure *scfg;
+	nss_tx_status_t status;
+	enum nss_dtlsmgr_status ret = NSS_DTLSMGR_FAIL;
+	uint32_t features = 0;
+	uint32_t encap_iv_len = 0;
+	uint32_t decap_iv_len = 0;
+	uint32_t hash_len_encap = 0;
+	uint32_t hash_len_decap = 0;
+
+	if ((in_data->encap.ver != NSS_DTLSMGR_VERSION_1_0)
+	    && (in_data->encap.ver != NSS_DTLSMGR_VERSION_1_2)) {
+		nss_dtlsmgr_warn("%p: Invalid DTLS version\n", &g_ctx);
+		return NSS_DTLSMGR_INVALID_VERSION;
+	}
+
+	if ((in_data->encap.cipher_type >= NSS_CRYPTO_CIPHER_MAX)
+	    || (in_data->decap.cipher_type >= NSS_CRYPTO_CIPHER_MAX)) {
+		nss_dtlsmgr_warn("%p: Invalid cipher algorithm\n", &g_ctx);
+		return NSS_DTLSMGR_INVALID_CIPHER;
+	}
+
+	if ((in_data->encap.auth_type >= NSS_CRYPTO_AUTH_MAX)
+	    || (in_data->decap.auth_type >= NSS_CRYPTO_AUTH_MAX)) {
+		nss_dtlsmgr_warn("%p: Invalid auth algorithm\n", &g_ctx);
+		return NSS_DTLSMGR_INVALID_AUTH;
+	}
+
+	if ((in_data->encap.cipher_key == NULL)
+	    || (in_data->encap.auth_key == NULL)
+	    || (in_data->decap.cipher_key == NULL)
+	    || (in_data->decap.auth_key == NULL)) {
+		nss_dtlsmgr_warn("%p: Invalid cipher/auth key\n", &g_ctx);
+		return NSS_DTLSMGR_INVALID_KEY;
+	}
+
+	/*
+	 * Allocate memory for new dtls session
+	 */
+	ds = kzalloc(sizeof(struct nss_dtlsmgr_session), GFP_KERNEL);
+	if (!ds) {
+		nss_dtlsmgr_info("%p: DTLS client allocation failed\n", &g_ctx);
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	/*
+	 * Create crypto session for encap
+	 */
+	memset(&cipher, 0, sizeof(struct nss_crypto_key));
+	memset(&auth, 0, sizeof(struct nss_crypto_key));
+
+	cipher.algo = in_data->encap.cipher_type;
+	cipher.key_len = in_data->encap.cipher_key_len;
+	cipher.key = in_data->encap.cipher_key;
+	auth.algo = in_data->encap.auth_type;
+	auth.key_len = in_data->encap.auth_key_len;
+	auth.key = in_data->encap.auth_key;
+
+	crypto_status = nss_crypto_session_alloc(g_ctx.crypto_hdl, &cipher,
+						 &auth, &ds->crypto_idx_encap);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_dtlsmgr_info("%p: DTLS encap crypto alloc failed\n", &g_ctx);
+		ret = NSS_DTLSMGR_CRYPTO_FAILED;
+		goto dtls_crypto_encap_alloc_fail;
+	}
+
+	encap_iv_len = nss_dtlsmgr_get_cipher_iv_len(cipher.algo);
+	hash_len_encap = nss_dtlsmgr_get_auth_hash_len(auth.algo);
+
+	/*
+	 * Update crypto session for encap
+	 */
+	memset(&params, 0, sizeof(struct nss_crypto_params));
+	params.cipher_skip = NSS_DTLSMGR_HDR_LEN + encap_iv_len;
+	params.auth_skip = 0;
+	params.req_type |= (NSS_CRYPTO_REQ_TYPE_ENCRYPT
+			   | NSS_CRYPTO_REQ_TYPE_AUTH);
+	crypto_status = nss_crypto_session_update(g_ctx.crypto_hdl,
+						  ds->crypto_idx_encap,
+						  &params);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		ret = NSS_DTLSMGR_CRYPTO_FAILED;
+		goto dtls_crypto_decap_alloc_fail;
+	}
+
+	nss_dtlsmgr_info("%p: encap: auth_skip:%d cipher_skip:%d\n",
+			 &g_ctx, params.auth_skip, params.cipher_skip);
+
+	/*
+	 * Create crypto session for decap
+	 */
+	memset(&cipher, 0, sizeof(struct nss_crypto_key));
+	memset(&auth, 0, sizeof(struct nss_crypto_key));
+
+	cipher.algo = in_data->decap.cipher_type;
+	cipher.key_len = in_data->decap.cipher_key_len;
+	cipher.key = in_data->decap.cipher_key;
+	auth.algo = in_data->decap.auth_type;
+	auth.key_len = in_data->decap.auth_key_len;
+	auth.key = in_data->decap.auth_key;
+
+	crypto_status = nss_crypto_session_alloc(g_ctx.crypto_hdl,
+						 &cipher,
+						 &auth,
+						 &ds->crypto_idx_decap);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_dtlsmgr_info("%p: DTLS decap crypto alloc failed\n", &g_ctx);
+		ret = NSS_DTLSMGR_CRYPTO_FAILED;
+		goto dtls_crypto_decap_alloc_fail;
+	}
+
+	decap_iv_len = nss_dtlsmgr_get_cipher_iv_len(cipher.algo);
+	hash_len_decap = nss_dtlsmgr_get_auth_hash_len(auth.algo);
+
+	/* call nss_crypto_session_update() for decap session */
+	memset(&params, 0, sizeof(struct nss_crypto_params));
+	params.cipher_skip = NSS_DTLSMGR_HDR_LEN + decap_iv_len;
+	params.auth_skip = 0;
+	params.req_type |= (NSS_CRYPTO_REQ_TYPE_DECRYPT
+			   | NSS_CRYPTO_REQ_TYPE_AUTH);
+	crypto_status = nss_crypto_session_update(g_ctx.crypto_hdl,
+						  ds->crypto_idx_decap,
+						  &params);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		ret = NSS_DTLSMGR_CRYPTO_FAILED;
+		goto dtls_dynamic_if_alloc_fail;
+	}
+
+	nss_dtlsmgr_info("%p: decap: auth_skip:%d cipher_skip:%d\n",
+			 &g_ctx, params.auth_skip, params.cipher_skip);
+
+	/*
+	 * Allocate NSS dynamic interface
+	 */
+	ds->nss_dtls_if = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_DTLS);
+	if (ds->nss_dtls_if == -1) {
+		nss_dtlsmgr_info("%p: DTLS dynamic I/F alloc failed\n", &g_ctx);
+		goto dtls_dynamic_if_alloc_fail;
+	}
+
+	/*
+	 * Create netdevice
+	 */
+	if (nss_dtlsmgr_netdev_create(ds) != NSS_DTLSMGR_OK) {
+		nss_dtlsmgr_info("%p: DTLS netdev creation failed\n", &g_ctx);
+		goto dtls_netdev_create_fail;
+	}
+
+	/*
+	 * Register NSS DTLS I/F
+	 */
+	ds->nss_ctx = nss_dtls_register_if(ds->nss_dtls_if,
+					   nss_connmgr_dtls_data_receive,
+					   nss_connmgr_dtls_event_receive,
+					   ds->netdev, features,
+					   (void *)ds);
+	if (ds->nss_ctx == NULL) {
+		nss_dtlsmgr_info("%p: DTLS dynamic I/F register failed\n", &g_ctx);
+		goto dtls_dynamic_if_register_fail;
+	}
+
+	/*
+	 * Initialize DTLS manager session
+	 */
+	ds->magic = NSS_DTLSMGR_SESSION_MAGIC;
+	ds->flags = in_data->flags;
+	ds->ver = in_data->encap.ver;
+	ds->sport = in_data->encap.sport;
+	ds->dport = in_data->encap.dport;
+	ds->epoch = in_data->encap.epoch;
+	ds->ip_ttl = in_data->encap.ip_ttl;
+	ds->nss_app_if = in_data->decap.app_if;
+	ds->window_size = in_data->decap.replay_window_size;
+	ds->stats_update_cb = in_data->cb;
+	ds->cidx_encap_pending = NSS_CRYPTO_MAX_IDXS;
+	ds->cidx_decap_pending = NSS_CRYPTO_MAX_IDXS;
+	atomic_set(&ds->ref, 1);
+
+	if (ds->flags & NSS_DTLSMGR_IPV6_ENCAP) {
+		for (i = 0; i < 4 ; i++) {
+			ds->sip.ipv6[i] = in_data->encap.sip.ipv6[i];
+			ds->dip.ipv6[i] = in_data->encap.dip.ipv6[i];
+		}
+	} else {
+		ds->sip.ipv4 = in_data->encap.sip.ipv4;
+		ds->dip.ipv4 = in_data->encap.dip.ipv4;
+	}
+
+	/*
+	 * Insert session into DTLS manager list
+	 */
+	spin_lock_bh(&g_ctx.lock);
+	if (!nss_dtlsmgr_session_insert(ds)) {
+		spin_unlock_bh(&g_ctx.lock);
+		goto dtls_session_insert_fail;
+	}
+	spin_unlock_bh(&g_ctx.lock);
+
+	/*
+	 * Send DTLS configure message to NSS
+	 */
+	memset(&dtlsmsg, 0, sizeof(struct nss_dtls_msg));
+	nss_dtls_msg_init(&dtlsmsg, ds->nss_dtls_if,
+			  NSS_DTLS_MSG_SESSION_CONFIGURE,
+			  sizeof(struct nss_dtls_session_configure),
+			  NULL, NULL);
+
+	scfg = &dtlsmsg.msg.cfg;
+	scfg->ver = ds->ver;
+	scfg->flags = ds->flags;
+	scfg->crypto_idx_encap = ds->crypto_idx_encap;
+	scfg->crypto_idx_decap = ds->crypto_idx_decap;
+	scfg->iv_len_encap = encap_iv_len;
+	scfg->iv_len_decap = decap_iv_len;
+	scfg->hash_len_encap = hash_len_encap;
+	scfg->hash_len_decap = hash_len_decap;
+	scfg->cipher_algo_encap = in_data->encap.cipher_type;
+	scfg->cipher_algo_decap = in_data->decap.cipher_type;
+	scfg->auth_algo_encap = in_data->encap.auth_type;
+	scfg->auth_algo_decap = in_data->decap.auth_type;
+	scfg->nss_app_if = ds->nss_app_if;
+	scfg->sport = ds->sport;
+	scfg->dport = ds->dport;
+	scfg->epoch = ds->epoch;
+	scfg->window_size = ds->window_size;
+	scfg->oip_ttl = ds->ip_ttl;
+
+	if (ds->flags & NSS_DTLSMGR_IPV6_ENCAP) {
+		for (i = 0; i < 4; i++) {
+			scfg->sip[i] = ds->sip.ipv6[i];
+			scfg->dip[i] = ds->dip.ipv6[i];
+		}
+	} else {
+		scfg->sip[0] = ds->sip.ipv4;
+		scfg->dip[0] = ds->dip.ipv4;
+	}
+
+	status = nss_dtls_tx_msg_sync(ds->nss_ctx, &dtlsmsg);
+	if (status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_info("%p: DTLS cfg msg tx failed\n", &g_ctx);
+		goto dtls_msg_tx_fail;
+	}
+
+	/*
+	 * Initialize return parameters
+	 */
+	out_data->dtls_if = ds->nss_dtls_if;
+	out_data->mtu_adjust = NSS_DTLSMGR_HDR_LEN;
+	out_data->mtu_adjust += sizeof(struct udphdr);
+
+	if (ds->flags & NSS_DTLSMGR_IPV6_ENCAP)
+		out_data->mtu_adjust += sizeof(struct ipv6hdr);
+	else
+		out_data->mtu_adjust += sizeof(struct iphdr);
+
+	if (ds->flags & NSS_DTLSMGR_CAPWAP)
+		out_data->mtu_adjust += NSS_DTLSMGR_CAPWAPHDR_LEN;
+
+	out_data->mtu_adjust += ((encap_iv_len * 2) + hash_len_encap);
+
+	/*
+	 * Adjust MTU of netdev
+	 */
+	ds->netdev->mtu -= out_data->mtu_adjust;
+
+	nss_dtlsmgr_info("%p: NSS DTLS session I/F:%d(%s) created\n",
+			 &g_ctx, ds->nss_dtls_if, ds->netdev->name);
+
+	return NSS_DTLSMGR_OK;
+
+dtls_msg_tx_fail:
+	spin_lock_bh(&g_ctx.lock);
+	nss_dtlsmgr_session_remove(ds->nss_dtls_if);
+	spin_unlock_bh(&g_ctx.lock);
+
+dtls_session_insert_fail:
+	nss_dtls_unregister_if(ds->nss_dtls_if);
+
+dtls_dynamic_if_register_fail:
+	nss_dtlsmgr_netdev_destroy(ds);
+
+dtls_netdev_create_fail:
+	nss_dynamic_interface_dealloc_node(ds->nss_dtls_if,
+					   NSS_DYNAMIC_INTERFACE_TYPE_DTLS);
+
+dtls_dynamic_if_alloc_fail:
+	crypto_status = nss_crypto_session_free(g_ctx.crypto_hdl,
+						ds->crypto_idx_decap);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_dtlsmgr_info("%p: dtls I/F:%u, unable to free crypto session id:%d\n", &g_ctx, ds->nss_dtls_if, ds->crypto_idx_decap);
+	}
+
+dtls_crypto_decap_alloc_fail:
+	crypto_status = nss_crypto_session_free(g_ctx.crypto_hdl,
+						ds->crypto_idx_encap);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_dtlsmgr_info("%p: dtls I/F:%u, unable to free crypto session id:%d\n", &g_ctx, ds->nss_dtls_if, ds->crypto_idx_encap);
+	}
+
+dtls_crypto_encap_alloc_fail:
+	ds->magic = 0;
+	kfree(ds);
+	return ret;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_session_create_with_crypto);
+
+/*
+ * nss_dtlsmgr_session_destroy()
+ *	Destroy DTLS session
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_session_destroy(uint32_t dtls_if)
+{
+	struct nss_dtlsmgr_session *ds;
+	nss_tx_status_t nss_status;
+	struct nss_dtls_msg dtlsmsg;
+
+	/*
+	 * Search DTLS session in session list
+	 */
+	spin_lock_bh(&g_ctx.lock);
+	ds = nss_dtlsmgr_session_find(dtls_if);
+	spin_unlock_bh(&g_ctx.lock);
+
+	if (!ds) {
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	/*
+	 * Send DTLS session destroy command to FW
+	 */
+	memset(&dtlsmsg, 0, sizeof(struct nss_dtls_msg));
+	nss_dtls_msg_init(&dtlsmsg, (uint16_t)ds->nss_dtls_if,
+			  NSS_DTLS_MSG_SESSION_DESTROY, 0, NULL, NULL);
+
+	nss_status = nss_dtls_tx_msg_sync(ds->nss_ctx, &dtlsmsg);
+	if (nss_status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_warn("%p: Failed to send DTLS session destroy for I/F %u", &g_ctx, ds->nss_dtls_if);
+
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	spin_lock_bh(&g_ctx.lock);
+	ds = nss_dtlsmgr_session_remove(dtls_if);
+	spin_unlock_bh(&g_ctx.lock);
+
+	if (!ds) {
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	/*
+	 * Decrement reference count so as to drop it to zero
+	 */
+	nss_dtlsmgr_session_ref_dec(ds);
+
+	nss_dtlsmgr_info("%p: DTLS session I/F %u disabled\n", &g_ctx, dtls_if);
+
+	return NSS_DTLSMGR_OK;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_session_destroy);
+
+/*
+ * nss_dtlsmgr_rekey_rx_cipher_update()
+ *	Update pending Rx cipher of a DTLS session.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_rekey_rx_cipher_update(uint32_t dtls_if, struct nss_dtlsmgr_session_update_config *udata)
+{
+	struct nss_dtlsmgr_session *ds;
+	nss_tx_status_t nss_status;
+	nss_crypto_status_t crypto_status;
+	struct nss_dtls_msg dtlsmsg;
+	struct nss_dtls_session_cipher_update *update;
+	struct nss_crypto_key cipher;
+	struct nss_crypto_key auth;
+	struct nss_crypto_params params;
+	uint32_t decap_iv_len = 0;
+	uint32_t hash_len_decap = 0;
+
+	/*
+	 * Search DTLS session in session list
+	 */
+	spin_lock_bh(&g_ctx.lock);
+	ds = nss_dtlsmgr_session_find_and_ref(dtls_if);
+	spin_unlock_bh(&g_ctx.lock);
+
+	if (!ds) {
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	/*
+	 * Free any crypto session, for the decap pending cipher
+	 * state, allocated by a previous call to this API but
+	 * were subsequently not used for packet processing.
+	 */
+	if (ds->cidx_decap_pending != NSS_CRYPTO_MAX_IDXS) {
+		crypto_status = nss_crypto_session_free(g_ctx.crypto_hdl,
+							ds->cidx_decap_pending);
+		if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+			nss_dtlsmgr_info("%p: dtls I/F:%u, unable to free crypto session id:%d\n", &g_ctx, ds->nss_dtls_if, ds->cidx_decap_pending);
+		}
+
+		ds->cidx_decap_pending = NSS_CRYPTO_MAX_IDXS;
+	}
+
+	memset(&cipher, 0, sizeof(struct nss_crypto_key));
+	memset(&auth, 0, sizeof(struct nss_crypto_key));
+	cipher.algo = udata->cipher_type;
+	cipher.key_len = udata->cipher_key_len;
+	cipher.key = udata->cipher_key;
+	auth.algo = udata->auth_type;
+	auth.key_len = udata->auth_key_len;
+	auth.key = udata->auth_key;
+	crypto_status = nss_crypto_session_alloc(g_ctx.crypto_hdl,
+						 &cipher,
+						 &auth,
+						 &ds->cidx_decap_pending);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_dtlsmgr_info("%p: DTLS rekey decap crypto alloc failed\n", &g_ctx);
+		nss_dtlsmgr_session_ref_dec(ds);
+		return NSS_DTLSMGR_CRYPTO_FAILED;
+	}
+
+	decap_iv_len = nss_dtlsmgr_get_cipher_iv_len(cipher.algo);
+	hash_len_decap = nss_dtlsmgr_get_auth_hash_len(auth.algo);
+
+	/*
+	 * Update crypto session
+	 */
+	memset(&params, 0, sizeof(struct nss_crypto_params));
+	params.cipher_skip = NSS_DTLSMGR_HDR_LEN + decap_iv_len;
+	params.auth_skip = 0;
+	params.req_type |= (NSS_CRYPTO_REQ_TYPE_DECRYPT
+			   | NSS_CRYPTO_REQ_TYPE_AUTH);
+	crypto_status = nss_crypto_session_update(g_ctx.crypto_hdl,
+						  ds->cidx_decap_pending,
+						  &params);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_crypto_session_free(g_ctx.crypto_hdl,
+					ds->cidx_decap_pending);
+		ds->cidx_decap_pending = NSS_CRYPTO_MAX_IDXS;
+
+		nss_dtlsmgr_info("%p: DTLS rekey decap crypto update failed\n", &g_ctx);
+		nss_dtlsmgr_session_ref_dec(ds);
+		return NSS_DTLSMGR_CRYPTO_FAILED;
+	}
+
+	/*
+	 * Initialize DTLS session Rx cipher update message
+	 */
+	memset(&dtlsmsg, 0, sizeof(struct nss_dtls_msg));
+	update = &dtlsmsg.msg.cipher_update;
+	update->crypto_idx = ds->cidx_decap_pending;
+	update->iv_len = decap_iv_len;
+	update->hash_len = hash_len_decap;
+	update->cipher_algo = cipher.algo;
+	update->auth_algo = auth.algo;
+	update->epoch = udata->epoch;
+
+	nss_dtls_msg_init(&dtlsmsg, (uint16_t)ds->nss_dtls_if,
+			  NSS_DTLS_MSG_REKEY_DECAP_CIPHER_UPDATE,
+			  0, NULL, NULL);
+
+	/*
+	 * Send DTLS session Rx cipher update command to FW
+	 */
+	nss_status = nss_dtls_tx_msg_sync(ds->nss_ctx, &dtlsmsg);
+	if (nss_status != NSS_TX_SUCCESS) {
+		nss_crypto_session_free(g_ctx.crypto_hdl,
+					ds->cidx_decap_pending);
+		ds->cidx_decap_pending = NSS_CRYPTO_MAX_IDXS;
+		nss_dtlsmgr_session_ref_dec(ds);
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	nss_dtlsmgr_session_ref_dec(ds);
+	return NSS_DTLSMGR_OK;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_rekey_rx_cipher_update);
+
+/*
+ * nss_dtlsmgr_rekey_tx_cipher_update()
+ *	Update pending Tx cipher of a DTLS session.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_rekey_tx_cipher_update(uint32_t dtls_if, struct nss_dtlsmgr_session_update_config *udata)
+{
+	struct nss_dtlsmgr_session *ds;
+	nss_tx_status_t nss_status;
+	nss_crypto_status_t crypto_status;
+	struct nss_dtls_msg dtlsmsg;
+	struct nss_dtls_session_cipher_update *update;
+	struct nss_crypto_key cipher;
+	struct nss_crypto_key auth;
+	struct nss_crypto_params params;
+	uint32_t encap_iv_len = 0;
+	uint32_t hash_len_encap = 0;
+
+	/*
+	 * Search DTLS session in session list
+	 */
+	spin_lock_bh(&g_ctx.lock);
+	ds = nss_dtlsmgr_session_find_and_ref(dtls_if);
+	spin_unlock_bh(&g_ctx.lock);
+
+	if (!ds) {
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	/*
+	 * Free any crypto session, for the encap pending cipher
+	 * state, allocated by a previous call to this API but
+	 * were subsequently not used for packet processing.
+	 */
+	if (ds->cidx_encap_pending != NSS_CRYPTO_MAX_IDXS) {
+		crypto_status = nss_crypto_session_free(g_ctx.crypto_hdl,
+							ds->cidx_encap_pending);
+		if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+			nss_dtlsmgr_info("%p: dtls I/F:%u, unable to free crypto session id:%d\n", &g_ctx, ds->nss_dtls_if, ds->cidx_encap_pending);
+		}
+
+		ds->cidx_encap_pending = NSS_CRYPTO_MAX_IDXS;
+	}
+
+	memset(&cipher, 0, sizeof(struct nss_crypto_key));
+	memset(&auth, 0, sizeof(struct nss_crypto_key));
+	cipher.algo = udata->cipher_type;
+	cipher.key_len = udata->cipher_key_len;
+	cipher.key = udata->cipher_key;
+	auth.algo = udata->auth_type;
+	auth.key_len = udata->auth_key_len;
+	auth.key = udata->auth_key;
+	crypto_status = nss_crypto_session_alloc(g_ctx.crypto_hdl,
+						 &cipher,
+						 &auth,
+						 &ds->cidx_encap_pending);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_dtlsmgr_info("%p: DTLS rekey encap crypto alloc failed\n", &g_ctx);
+		nss_dtlsmgr_session_ref_dec(ds);
+		return NSS_DTLSMGR_CRYPTO_FAILED;
+	}
+
+	encap_iv_len = nss_dtlsmgr_get_cipher_iv_len(cipher.algo);
+	hash_len_encap = nss_dtlsmgr_get_auth_hash_len(auth.algo);
+
+	/* Update crypto session */
+	memset(&params, 0, sizeof(struct nss_crypto_params));
+	params.cipher_skip = NSS_DTLSMGR_HDR_LEN + encap_iv_len;
+	params.auth_skip = 0;
+	params.req_type |= (NSS_CRYPTO_REQ_TYPE_ENCRYPT
+			   | NSS_CRYPTO_REQ_TYPE_AUTH);
+	crypto_status = nss_crypto_session_update(g_ctx.crypto_hdl,
+						  ds->cidx_encap_pending,
+						  &params);
+	if (crypto_status != NSS_CRYPTO_STATUS_OK) {
+		nss_crypto_session_free(g_ctx.crypto_hdl,
+					ds->cidx_encap_pending);
+		ds->cidx_encap_pending = NSS_CRYPTO_MAX_IDXS;
+
+		nss_dtlsmgr_info("%p: DTLS rekey encap crypto update failed\n", &g_ctx);
+		nss_dtlsmgr_session_ref_dec(ds);
+		return NSS_DTLSMGR_CRYPTO_FAILED;
+	}
+
+	/*
+	 * Initialize DTLS session Tx cipher update message
+	 */
+	memset(&dtlsmsg, 0, sizeof(struct nss_dtls_msg));
+	update = &dtlsmsg.msg.cipher_update;
+	update->crypto_idx = ds->cidx_encap_pending;
+	update->iv_len = encap_iv_len;
+	update->hash_len = hash_len_encap;
+	update->cipher_algo = cipher.algo;
+	update->auth_algo = auth.algo;
+	update->epoch = udata->epoch;
+
+	nss_dtls_msg_init(&dtlsmsg, (uint16_t)ds->nss_dtls_if,
+			  NSS_DTLS_MSG_REKEY_ENCAP_CIPHER_UPDATE,
+			  0, NULL, NULL);
+
+	/*
+	 * Send DTLS session Rx cipher update command to FW
+	 */
+	nss_status = nss_dtls_tx_msg_sync(ds->nss_ctx, &dtlsmsg);
+	if (nss_status != NSS_TX_SUCCESS) {
+		nss_crypto_session_free(g_ctx.crypto_hdl,
+					ds->cidx_encap_pending);
+		ds->cidx_encap_pending = NSS_CRYPTO_MAX_IDXS;
+		nss_dtlsmgr_session_ref_dec(ds);
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	nss_dtlsmgr_session_ref_dec(ds);
+	return NSS_DTLSMGR_OK;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_rekey_tx_cipher_update);
+
+/*
+ * nss_dtlsmgr_rekey_rx_cipher_switch()
+ *	Set pending Rx cipher state of a DTLS session to current.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_rekey_rx_cipher_switch(uint32_t dtls_if)
+{
+	struct nss_dtlsmgr_session *ds;
+	nss_tx_status_t nss_status;
+	struct nss_dtls_msg dtlsmsg;
+
+	memset(&dtlsmsg, 0, sizeof(struct nss_dtls_msg));
+	nss_dtls_msg_init(&dtlsmsg, (uint16_t)dtls_if,
+			  NSS_DTLS_MSG_REKEY_DECAP_CIPHER_SWITCH,
+			  0, NULL, NULL);
+
+	/*
+	 * Search DTLS session in session list
+	 */
+	spin_lock_bh(&g_ctx.lock);
+	ds = nss_dtlsmgr_session_find_and_ref(dtls_if);
+	spin_unlock_bh(&g_ctx.lock);
+
+	if (!ds) {
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	/*
+	 * Send DTLS session Rx cipher switch command to FW
+	 */
+	nss_status = nss_dtls_tx_msg_sync(ds->nss_ctx, &dtlsmsg);
+	if (nss_status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_session_ref_dec(ds);
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	ds->crypto_idx_decap = ds->cidx_decap_pending;
+	ds->cidx_decap_pending = NSS_CRYPTO_MAX_IDXS;
+
+	nss_dtlsmgr_session_ref_dec(ds);
+	return NSS_DTLSMGR_OK;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_rekey_rx_cipher_switch);
+
+/*
+ * nss_dtlsmgr_rekey_tx_cipher_switch()
+ *	Set pending Tx cipher state of a DTLS session to current.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_rekey_tx_cipher_switch(uint32_t dtls_if)
+{
+	struct nss_dtlsmgr_session *ds;
+	nss_tx_status_t nss_status;
+	struct nss_dtls_msg dtlsmsg;
+
+	memset(&dtlsmsg, 0, sizeof(struct nss_dtls_msg));
+	nss_dtls_msg_init(&dtlsmsg, (uint16_t)dtls_if,
+			  NSS_DTLS_MSG_REKEY_ENCAP_CIPHER_SWITCH,
+			  0, NULL, NULL);
+
+	/*
+	 * Search DTLS session in session list
+	 */
+	spin_lock_bh(&g_ctx.lock);
+	ds = nss_dtlsmgr_session_find_and_ref(dtls_if);
+	spin_unlock_bh(&g_ctx.lock);
+
+	if (!ds) {
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	/*
+	 * Send DTLS session Tx cipher switch command to FW
+	 */
+	nss_status = nss_dtls_tx_msg_sync(ds->nss_ctx, &dtlsmsg);
+	if (nss_status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_session_ref_dec(ds);
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	ds->crypto_idx_encap = ds->cidx_encap_pending;
+	ds->cidx_encap_pending = NSS_CRYPTO_MAX_IDXS;
+
+	nss_dtlsmgr_session_ref_dec(ds);
+	return NSS_DTLSMGR_OK;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_rekey_tx_cipher_switch);
+
+/*
+ * nss_dtls_crypto_attach()
+ */
+static nss_crypto_user_ctx_t nss_dtls_crypto_attach(nss_crypto_handle_t crypto)
+{
+	struct nss_dtlsmgr_ctx *sc = &g_ctx;
+
+	sc->crypto_hdl = crypto;
+	nss_dtlsmgr_info("%p: DTLS client crypto attach\n", &g_ctx);
+	return (nss_crypto_user_ctx_t)sc;
+}
+
+/*
+ * nss_dtls_crypto_detach()
+ */
+static void nss_dtls_crypto_detach(nss_crypto_user_ctx_t uctx)
+{
+	struct nss_dtlsmgr_ctx *sc = NULL;
+
+	sc = (struct nss_dtlsmgr_ctx *)uctx;
+	nss_dtlsmgr_assert(sc == &g_ctx);
+
+	sc->crypto_hdl = NULL;
+	nss_dtlsmgr_info("%p: DTLS client crypto detach\n", &g_ctx);
+}
+
+/*
+ * nss_dtls_init_module()
+ */
+int __init nss_dtls_init_module(void)
+{
+	int32_t i;
+
+	nss_dtlsmgr_info("%p: NSS DTLS Manager\n", &g_ctx);
+
+	for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
+		g_ctx.session[i] = NULL;
+	}
+
+	spin_lock_init(&(g_ctx.lock));
+	nss_crypto_register_user(nss_dtls_crypto_attach,
+				 nss_dtls_crypto_detach,
+				 "nss-dtls");
+	return 0;
+}
+
+/*
+ * nss_dtls_destroy_all_sessions()
+ */
+static void nss_dtls_destroy_all_sessions(void)
+{
+	nss_tx_status_t nss_status;
+	struct nss_dtls_msg dtlsmsg;
+	struct nss_dtlsmgr_session *ds;
+	int32_t i;
+
+	for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
+		spin_lock_bh(&g_ctx.lock);
+		if (g_ctx.session[i] == NULL) {
+			spin_unlock_bh(&g_ctx.lock);
+			continue;
+		}
+
+		/*
+		 * Remove session from list of sessions
+		 */
+		ds = g_ctx.session[i];
+		g_ctx.session[i] = NULL;
+		spin_unlock_bh(&g_ctx.lock);
+
+		nss_dtlsmgr_assert(ds->magic == NSS_DTLSMGR_SESSION_MAGIC);
+
+		/*
+		 * Send DTLS session destroy command to FW
+		 */
+		memset(&dtlsmsg, 0, sizeof(struct nss_dtls_msg));
+		nss_dtls_msg_init(&dtlsmsg, (uint16_t)ds->nss_dtls_if,
+				  NSS_DTLS_MSG_SESSION_DESTROY, 0,
+				  NULL, NULL);
+
+		nss_status = nss_dtls_tx_msg_sync(ds->nss_ctx, &dtlsmsg);
+		if (nss_status != NSS_TX_SUCCESS)
+			nss_dtlsmgr_warn("%p: Failed to send DTLS session destroy for I/F %u\n", &g_ctx, ds->nss_dtls_if);
+
+		nss_dtlsmgr_session_ref_dec(ds);
+	}
+}
+
+/*
+ * nss_dtls_exit_module()
+ */
+void __exit nss_dtls_exit_module(void)
+{
+	nss_dtls_destroy_all_sessions();
+	nss_crypto_unregister_user(g_ctx.crypto_hdl);
+}
+
+module_init(nss_dtls_init_module);
+module_exit(nss_dtls_exit_module);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("NSS DTLS manager");
diff --git a/dtls/nss_connmgr_dtls.h b/dtls/nss_connmgr_dtls.h
new file mode 100644
index 0000000..c071c39
--- /dev/null
+++ b/dtls/nss_connmgr_dtls.h
@@ -0,0 +1,143 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2016, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_connnmgr_dtls.h
+ */
+
+#ifndef _NSS_CONNMGR_DTLS_H_
+#define _NSS_CONNMGR_DTLS_H_
+
+#include "nss_dtlsmgr.h"
+#include <nss_crypto_if.h>
+
+/*
+ * Debug macros
+ */
+#if (NSS_DTLSMGR_DEBUG_LEVEL < 1)
+#define nss_dtlsmgr_assert(fmt, args...)
+#else
+#define nss_dtlsmgr_assert(c) BUG_ON(!(c))
+#endif
+
+#if defined(CONFIG_DYNAMIC_DEBUG)
+/*
+ * Compile messages for dynamic enable/disable
+ */
+#define nss_dtlsmgr_warn(s, ...) pr_debug("%s[%d]:" s, __func__, \
+					  __LINE__, ##__VA_ARGS__)
+#define nss_dtlsmgr_info(s, ...) pr_debug("%s[%d]:" s, __func__, \
+					  __LINE__, ##__VA_ARGS__)
+#define nss_dtlsmgr_trace(s, ...) pr_debug("%s[%d]:" s, __func__, \
+					   __LINE__, ##__VA_ARGS__)
+#else
+
+/*
+ * Statically compile messages at different levels
+ */
+#if (NSS_DTLSMGR_DEBUG_LEVEL < 2)
+#define nss_dtlsmgr_warn(s, ...)
+#else
+#define nss_dtlsmgr_warn(s, ...) pr_warn("%s[%d]:" s, __func__, \
+					 __LINE__, ##__VA_ARGS__)
+#endif
+
+#if (NSS_DTLSMGR_DEBUG_LEVEL < 3)
+#define nss_dtlsmgr_info(s, ...)
+#else
+#define nss_dtlsmgr_info(s, ...) pr_notice("%s[%d]:" s, __func__, \
+					   __LINE__, ##__VA_ARGS__)
+#endif
+
+#if (NSS_DTLSMGR_DEBUG_LEVEL < 4)
+#define nss_dtlsmgr_trace(s, ...)
+#else
+#define nss_dtlsmgr_trace(s, ...)  pr_info("%s[%d]:" s, __func__, \
+					   __LINE__, ##__VA_ARGS__)
+#endif
+#endif
+
+#define NSS_DTLSMGR_HDR_LEN 13			/* DTLS header length */
+#define NSS_DTLSMGR_CAPWAPHDR_LEN 4		/* CAPWAP-DTLS header length */
+#define NSS_DTLSMGR_SESSION_MAGIC 0x5d7eb219	/* DTLS session magic value */
+
+/*
+ * DTLS payload content type
+ */
+#define NSS_DTLSMGR_CTYPE_APP 23		/* Application data */
+
+/*
+ * DTLS metadata
+ */
+#define NSS_DTLSMGR_METADATA_LEN 4		/* DTLS metadata length */
+#define NSS_DTLSMGR_METADATA_CTYPE(m) (m >> 24)	/* DTLS metadata content type */
+#define NSS_DTLSMGR_METADATA_ERROR(m) ((m >> 16) & 0x00FF)
+						/* DTLS metadata error */
+/*
+ * DTLS metadata error types
+ */
+#define NSS_DTLSMGR_METADATA_ERROR_OK 0
+
+/*
+ * DTLS Manager session
+ */
+struct nss_dtlsmgr_session {
+	uint32_t magic;			/* Magic value used to
+					   verify DTLS session */
+	atomic_t ref;			/* Reference counter */
+	uint32_t ver;			/* DTLS version */
+	uint32_t flags;			/* Session flags */
+	uint32_t crypto_idx_encap;	/* Current encap crypto session idx */
+	uint32_t crypto_idx_decap;	/* Current decap crypto session idx */
+	uint32_t cidx_encap_pending;	/* Pending encap crypto session idx */
+	uint32_t cidx_decap_pending;	/* Pending decap crypto session idx */
+	nss_dtlsmgr_session_stats_update_cb_t stats_update_cb;
+					/* Callback for Stats update */
+	uint32_t nss_dtls_if;		/* NSS DTLS session I/F */
+	struct nss_ctx_instance *nss_ctx;
+					/* NSS context */
+	struct net_device *netdev;	/* Netdevice */
+	uint16_t sport;			/* Source UDP/UDPLite port */
+	uint16_t dport;			/* Destination UDP/UDPLite port */
+	uint16_t window_size;		/* Anit-replay window size */
+	uint16_t epoch;			/* Current Epoch */
+	union nss_dtlsmgr_ip sip;	/* Source IPv4/IPv6 address */
+	union nss_dtlsmgr_ip dip;	/* Destination IPv4/IPv6 address */
+	uint32_t nss_app_if;		/* NSS I/F of application using
+					   this DTLS session */
+	uint8_t ip_ttl;			/* IP Time To Live */
+};
+
+/*
+ * DTLS Manager global context type
+ */
+struct nss_dtlsmgr_ctx {
+	nss_crypto_handle_t crypto_hdl;
+	spinlock_t lock;
+	struct nss_dtlsmgr_session *session[NSS_MAX_DTLS_SESSIONS];
+};
+
+/*
+ * DTLS Manager per session netdev private data
+ */
+struct nss_dtlsmgr_netdev_priv {
+	struct nss_dtlsmgr_session *s;
+};
+
+nss_dtlsmgr_status_t nss_dtlsmgr_netdev_create(struct nss_dtlsmgr_session *ds);
+nss_dtlsmgr_status_t nss_dtlsmgr_netdev_destroy(struct nss_dtlsmgr_session *ds);
+
+#endif
diff --git a/dtls/nss_connmgr_dtls_netdev.c b/dtls/nss_connmgr_dtls_netdev.c
new file mode 100644
index 0000000..b214878
--- /dev/null
+++ b/dtls/nss_connmgr_dtls_netdev.c
@@ -0,0 +1,215 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2016, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_connmgr_dtls_netdev.c
+ *	NSS DTLS Manager netdev module
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/ipv6.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/udp.h>
+#include <linux/ipv6.h>
+
+#include <nss_api_if.h>
+#include <nss_dynamic_interface.h>
+
+#include "nss_connmgr_dtls.h"
+
+/*
+ * Maximum tailroom required by crypto
+ */
+#define NSS_DTLSMGR_TROOM (128 + (2 * NSS_CRYPTO_MAX_HASHLEN_SHA256))
+
+/*
+ * Maximum headroom for encapsulating headers
+ */
+#define NSS_DTLSMGR_MAX_HDR_LEN ((NSS_DTLSMGR_HDR_LEN + 3)	\
+				 + NSS_DTLSMGR_CAPWAPHDR_LEN	\
+				 + (2 * NSS_CRYPTO_MAX_IVLEN_AES)	\
+				 + sizeof(struct ipv6hdr)	\
+				 + sizeof(struct udphdr))
+
+/*
+ * nss_dtlsmgr_session_xmit()
+ */
+static netdev_tx_t nss_dtlsmgr_session_xmit(struct sk_buff *skb,
+					    struct net_device *dev)
+{
+	struct nss_dtlsmgr_netdev_priv *priv;
+	struct nss_dtlsmgr_session *s;
+	int32_t  nhead, ntail;
+
+	priv = netdev_priv(dev);
+	s = priv->s;
+
+	switch (skb->protocol) {
+	case htons(ETH_P_IP):
+		if (s->flags & NSS_DTLSMGR_IPV6_ENCAP) {
+			nss_dtlsmgr_info("%p: NSS DTLS I/F %d: skb(%p) invalid L3 protocol 0x%x\n", dev, s->nss_dtls_if, skb, ETH_P_IP);
+			return NETDEV_TX_BUSY;
+		}
+		break;
+
+	case htons(ETH_P_IPV6):
+		if (!(s->flags & NSS_DTLSMGR_IPV6_ENCAP)) {
+			nss_dtlsmgr_info("%p: NSS DTLS I/F %d: skb(%p) invalid L3 protocol 0x%x\n", dev, s->nss_dtls_if, skb, ETH_P_IPV6);
+			return NETDEV_TX_BUSY;
+		}
+		break;
+
+	default:
+		nss_dtlsmgr_info("%p: NSS DTLS I/F %d: skb(%p) unsupported IP protocol 0x%x\n", dev, s->nss_dtls_if, skb, ntohs(skb->protocol));
+		return NETDEV_TX_BUSY;
+	}
+
+	nhead = dev->needed_headroom;
+	ntail = dev->needed_tailroom;
+
+	if (skb_is_nonlinear(skb)) {
+		nss_dtlsmgr_info("%p: NSS DTLS does not support non-linear skb %p\n", dev, skb);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (unlikely(skb_shared(skb))) {
+		nss_dtlsmgr_info("%p: Shared skb:%p is not supported\n",
+				 dev, skb);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (skb_cloned(skb) || (skb_headroom(skb) < nhead)
+	    || (skb_tailroom(skb) < ntail)) {
+		if (pskb_expand_head(skb, nhead, ntail, GFP_KERNEL)) {
+			nss_dtlsmgr_info("%p: skb:%p unable to expand buffer\n",
+					 dev, skb);
+			return NETDEV_TX_BUSY;
+		}
+	}
+
+	if (skb->data != skb_network_header(skb)) {
+		skb_pull(skb, skb_network_offset(skb));
+	}
+
+	if (nss_dtls_tx_buf(skb, s->nss_dtls_if, s->nss_ctx) != NSS_TX_SUCCESS) {
+		return NETDEV_TX_BUSY;
+	}
+
+	return NETDEV_TX_OK;
+}
+
+/*
+ * nss_dtlsmgr_session_stop()
+ */
+static int nss_dtlsmgr_session_stop(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+/*
+ * nss_dtlsmgr_session_open()
+ */
+static int nss_dtlsmgr_session_open(struct net_device *dev)
+{
+	netif_start_queue(dev);
+	return 0;
+}
+
+/*
+ * DTLS netdev ops
+ */
+static const struct net_device_ops nss_dtlsmgr_session_ops = {
+	.ndo_start_xmit = nss_dtlsmgr_session_xmit,
+	.ndo_open = nss_dtlsmgr_session_open,
+	.ndo_stop = nss_dtlsmgr_session_stop,
+	.ndo_set_mac_address = eth_mac_addr,
+};
+
+/*
+ * nss_dtlsmgr_dev_setup()
+ */
+static void nss_dtlsmgr_dev_setup(struct net_device *dev)
+{
+	dev->addr_len = ETH_ALEN;
+	dev->mtu = ETH_DATA_LEN;
+	dev->hard_header_len = NSS_DTLSMGR_MAX_HDR_LEN;
+	dev->needed_headroom = 0;
+	dev->needed_tailroom = NSS_DTLSMGR_TROOM;
+
+	dev->type = ARPHRD_ETHER;
+	dev->ethtool_ops = NULL;
+	dev->header_ops = NULL;
+	dev->netdev_ops = &nss_dtlsmgr_session_ops;
+	dev->destructor = NULL;
+
+	memcpy(dev->dev_addr, "\xaa\xbb\xcc\xdd\xee\xff", dev->addr_len);
+	memset(dev->broadcast, 0xff, dev->addr_len);
+	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+}
+
+/*
+ * nss_dtlsmgr_netdev_create()
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_netdev_create(struct nss_dtlsmgr_session *ds)
+{
+	struct net_device *dev;
+	struct nss_dtlsmgr_netdev_priv *priv;
+	int32_t err = 0;
+
+	dev = alloc_netdev(sizeof(struct nss_dtlsmgr_netdev_priv),
+			   "qca-nss-dtls%d", nss_dtlsmgr_dev_setup);
+	if (!dev) {
+		nss_dtlsmgr_info("DTLS netdev alloc failed\n");
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	priv = netdev_priv(dev);
+	priv->s = ds;
+
+	err = rtnl_is_locked() ? register_netdevice(dev) : register_netdev(dev);
+	if (err < 0) {
+		nss_dtlsmgr_info("DTLS netdev register failed\n");
+		free_netdev(dev);
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	ds->netdev = dev;
+	return NSS_DTLSMGR_OK;
+}
+
+/*
+ * nss_dtlsmgr_netdev_destroy()
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_netdev_destroy(struct nss_dtlsmgr_session *ds)
+{
+	if (!ds && !ds->netdev) {
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	rtnl_is_locked() ? unregister_netdevice(ds->netdev)
+			 : unregister_netdev(ds->netdev);
+
+	free_netdev(ds->netdev);
+	ds->netdev = NULL;
+	return NSS_DTLSMGR_OK;
+}
diff --git a/exports/nss_dtlsmgr.h b/exports/nss_dtlsmgr.h
new file mode 100644
index 0000000..418c4d2
--- /dev/null
+++ b/exports/nss_dtlsmgr.h
@@ -0,0 +1,268 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2016, 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.
+ **************************************************************************
+ */
+
+/*
+ * nss_dtlsmgr.h
+ *	DTLS manager interface definitions.
+ */
+#ifndef _NSS_DTLSMGR_H_
+#define _NSS_DTLSMGR_H_
+
+/**
+ * @brief NSS DTLS manager status
+ */
+typedef enum nss_dtlsmgr_status {
+	NSS_DTLSMGR_OK,			/**< DTLS manager status ok */
+	NSS_DTLSMGR_FAIL,		/**< DTLS manager status fail */
+	NSS_DTLSMGR_INVALID_VERSION,	/**< Invalid DTLS version */
+	NSS_DTLSMGR_INVALID_CIPHER,	/**< Invalid cipher algorithm */
+	NSS_DTLSMGR_INVALID_AUTH,	/**< Invalid auth algorithm */
+	NSS_DTLSMGR_INVALID_KEY,	/**< Invalid key for cipher/auth */
+	NSS_DTLSMGR_CRYPTO_FAILED,	/**< Failed to allocate/initialize
+					     crypto session */
+} nss_dtlsmgr_status_t;
+
+/**
+ * @brief DTLS Version
+ */
+enum nss_dtlsmgr_dtlsver {
+	NSS_DTLSMGR_VERSION_1_0,	/**< DTLS v1.0 */
+	NSS_DTLSMGR_VERSION_1_2,	/**< DTLS v1.2 */
+	NSS_DTLSMGR_VERSION_INVALID,	/**< DTLS version invalid */
+};
+
+/**
+ * @brief NSS DTLS manager flags
+ */
+enum nss_dtlsmgr_flags {
+	NSS_DTLSMGR_IPV6_ENCAP = 0x00000001,
+					/**< Outer IP header is IPv6 */
+	NSS_DTLSMGR_UDPLITE_ENCAP = 0x00000002,
+					/**< UDPLite encapsulation */
+	NSS_DTLSMGR_CAPWAP = 0x00000004,
+					/**< CAPWAP-DTLS session */
+	NSS_DTLSMGR_CAPWAP_UDPLITE_HDR_CSUM = 0x00000008,
+					/**< Generate only UDP-Lite
+					     header checksum */
+	NSS_DTLSMGR_PKT_DEBUG = 0x00000010,
+					/* DTLS packet debug */
+};
+
+/**
+ * @brief IPv4/IPv6 address
+ */
+union nss_dtlsmgr_ip {
+	uint32_t ipv4;			/**< IPv4 address */
+	uint32_t ipv6[4];		/**< IPv6 address */
+};
+
+/**
+ * @brief NSS DTLS session encap data
+ */
+struct nss_dtlsmgr_encap_config {
+	enum nss_dtlsmgr_dtlsver ver;	/**< Version used in DTLS header */
+	enum nss_crypto_cipher cipher_type;
+					/**< Cipher key for encap */
+	uint32_t cipher_key_len;	/**< Cipher key length */
+	uint8_t *cipher_key;		/**< Location of cipher key */
+	enum nss_crypto_auth auth_type;	/**< Auth key for encap */
+	uint32_t auth_key_len;		/**< Auth key length */
+	uint8_t *auth_key;		/**< Location of auth key */
+	uint16_t sport;			/**< Source UDP port */
+	uint16_t dport;			/**< Destination UDP port */
+	uint16_t epoch;			/**< Epoch */
+	union nss_dtlsmgr_ip sip;	/**< Source IP address */
+	union nss_dtlsmgr_ip dip;	/**< Destination IP address */
+	uint8_t ip_ttl;			/**< IP time to live */
+};
+
+/**
+ * @brief NSS DTLS session decap data
+ */
+struct nss_dtlsmgr_decap_config {
+	enum nss_crypto_cipher cipher_type;
+					/**< Cipher key for decap */
+	uint32_t cipher_key_len;	/**< Cipher key length */
+	uint8_t *cipher_key;		/**< Location of cipher key */
+	enum nss_crypto_auth auth_type;	/**< Auth key for decap */
+	uint32_t auth_key_len;		/**< Auth key length */
+	uint8_t *auth_key;		/**< Location of auth key */
+	uint32_t app_if;		/**< NSS I/F number of tunnel
+					     associated with DTLS session.
+					     For CAPWAP, this will be the
+					     CAPWAP tunnel NSS I/F. */
+	uint16_t replay_window_size;	/**< Anti-Replay window size */
+};
+
+/**
+ * @brief NSS DTLS session create return parameters
+ */
+struct nss_dtlsmgr_return_data {
+	uint32_t dtls_if;		/**< NSS I/F number of DTLS session */
+	uint32_t mtu_adjust;		/**< MTU adjustment */
+};
+
+/**
+ * NSS DTLS session stats update
+ */
+struct nss_dtlsmgr_session_stats_update {
+	uint32_t tx_pkts;		/**< Tx packets */
+	uint32_t rx_pkts;		/**< Rx packets */
+	uint32_t rx_dropped;		/**< Rx drops */
+	uint32_t tx_auth_done;		/**< Tx authentication done */
+	uint32_t rx_auth_done;		/**< Rx successful authentication */
+	uint32_t tx_cipher_done;	/**< Tx cipher done */
+	uint32_t rx_cipher_done;	/**< Rx cipher done */
+	uint32_t tx_cbuf_alloc_fail;	/**< Tx crypto buffer allocation fail */
+	uint32_t rx_cbuf_alloc_fail;	/**< Rx crypto buffer allocation fail */
+	uint32_t tx_cenqueue_fail;	/**< Tx crypto enqueue fail */
+	uint32_t rx_cenqueue_fail;	/**< Rx crypto enqueue fail */
+	uint32_t tx_dropped_hroom;	/**< Tx drop due to
+					     insufficient headroom */
+	uint32_t tx_dropped_troom;	/**< Tx drop due to
+					     insufficient tailroom */
+	uint32_t tx_forward_enqueue_fail;
+					/**< Enqueue failed to forwarding
+					     node after encap */
+	uint32_t rx_forward_enqueue_fail;
+					/**< Enqueue failed to receiving
+					     node after decap */
+	uint32_t rx_invalid_version;	/**< Rx invalid DTLS version */
+	uint32_t rx_invalid_epoch;	/**< Rx invalid DTLS epoch */
+	uint32_t rx_malformed;		/**< Rx malformed DTLS record */
+	uint32_t rx_cipher_fail;	/**< Rx cipher fail */
+	uint32_t rx_auth_fail;		/**< Rx authentication fail */
+	uint32_t rx_capwap_classify_fail;
+					/**< Rx CAPWAP classification fail */
+	uint32_t rx_replay_fail;	/**< Rx anti-replay failures */
+	uint32_t rx_replay_duplicate;	/**< Rx anti-replay fail for
+					     duplicate record */
+	uint32_t rx_replay_out_of_window;
+					/**< Rx anti-replay fail for out
+					     of window record */
+	uint32_t outflow_queue_full;	/**< Tx drop due to encap queue full */
+	uint32_t decap_queue_full;	/**< Rx drop due to decap queue full */
+	uint32_t pbuf_alloc_fail;	/**< Buffer allocation fail */
+	uint32_t pbuf_copy_fail;	/**< Buffer copy fail */
+	uint16_t epoch;			/**< Current Epoch */
+	uint16_t tx_seq_high;		/**< Upper 16-bits of current
+					     sequence number */
+	uint32_t tx_seq_low;		/**< Lower 32-bits of current
+					     sequence number */
+};
+
+/**
+ * NSS DTLS session stats update callback
+ */
+typedef void (*nss_dtlsmgr_session_stats_update_cb_t)(uint32_t dtls_if, struct nss_dtlsmgr_session_stats_update *supdate);
+
+
+/**
+ * @brief NSS DTLS session definition
+ */
+struct nss_dtlsmgr_session_create_config {
+	uint32_t flags;				/**< Bit mask of
+						     enum nss_dtlsmgr_flags */
+	nss_dtlsmgr_session_stats_update_cb_t cb;
+						/**< Stats update callback */
+	struct nss_dtlsmgr_encap_config encap;	/**< Encap data */
+	struct nss_dtlsmgr_decap_config decap;	/**< Decap data */
+};
+
+/**
+ * @brief NSS DTLS session Tx/Rx cipher update parameters
+ */
+struct nss_dtlsmgr_session_update_config {
+	enum nss_crypto_cipher cipher_type;	/**< Cipher algo */
+	uint32_t cipher_key_len;		/**< Cipher key */
+	uint8_t *cipher_key;			/**< Location of cipher key */
+	enum nss_crypto_auth auth_type;		/**< Auth algo */
+	uint32_t auth_key_len;			/**< Auth key length */
+	uint8_t *auth_key;			/**< Location of auth key */
+	uint16_t epoch;				/**< Epoch */
+};
+
+/**
+ * @brief Create a NSS DTLS session and associated crypto sessions
+ *
+ * @param in_data[IN] DTLS session create data
+ * @param out_data[out] Return parameters from DTLS session create operation
+ *
+ * @return NSS_DTLSMGR_OK for success
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_session_create_with_crypto(struct nss_dtlsmgr_session_create_config *in_data, struct nss_dtlsmgr_return_data *out_data);
+
+/**
+ * @brief Destroy a NSS DTLS session and associated crypto sessions
+ *
+ * @param dtls_if[IN] NSS DTLS I/F
+ *
+ * @return NSS_DTLSMGR_OK for success
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_session_destroy(uint32_t dtls_if);
+
+/**
+ * @brief Update pending Rx cipher state of a DTLS session
+ *
+ * @param dtls_if[IN] NSS DTLS I/F
+ * @param udata[IN] DTLS session update parameters
+ *
+ * @return NSS_DTLSMGR_OK for success
+ *
+ * Configures new parameters into the pending Rx cipher
+ * state of a DTLS session. This has no effect on the current
+ * cipher state and its processing of Rx packets.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_rekey_rx_cipher_update(uint32_t dtls_if, struct nss_dtlsmgr_session_update_config *udata);
+
+/**
+ * @brief Update pending Tx cipher state of a DTLS session
+ *
+ * @param dtls_if[IN] NSS DTLS I/F
+ * @param udata[IN] DTLS session update parameters
+ *
+ * @return NSS_DTLSMGR_OK for success
+ *
+ * Configures new parameters into the pending Tx cipher
+ * state of a DTLS session. This has no effect on the current
+ * cipher state and its processing of Tx packets.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_rekey_tx_cipher_update(uint32_t dtls_if, struct nss_dtlsmgr_session_update_config *udata);
+
+/**
+ * @brief Switch Rx to new cipher state
+ *
+ * @param dtls_if[IN] NSS DTLS I/F
+ *
+ * @return NSS_DTLSMGR_OK for success
+ *
+ * Causes the Rx pending cipher state of a DTLS session
+ * to become current effectively rekeying the Rx path.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_rekey_rx_cipher_switch(uint32_t dtls_if);
+
+/**
+ * @brief Switch Tx to new cipher state
+ *
+ * @param dtls_if[IN] NSS DTLS I/F
+ *
+ * @return NSS_DTLSMGR_OK for success
+ *
+ * Causes the Tx pending cipher state of a DTLS session
+ * to become current effectively rekeying the Tx path.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_rekey_tx_cipher_switch(uint32_t dtls_if);
+#endif /* _NSS_DTLSMGR_H_ */