[qca-nss-clients] dtls: New API framework for v2

Created a new API framework for dtlsmgr which makes use of
Linux CryptoAPI to allocate crypto sessions.

Change-Id: Ia38e99b05cf1c3d85ef2f4665b88cb32719683bf
Signed-off-by: Tanmay V Jagdale <tjagdale@codeaurora.org>
Signed-off-by: Samarjeet Banerjee <banerjee@codeaurora.org>
diff --git a/Makefile b/Makefile
index 3331b56..69dd568 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@
 
 obj-$(bridge-mgr)+= bridge/
 obj-$(capwapmgr)+= capwapmgr/
-obj-$(dtlsmgr)+= dtls/
+obj-$(dtlsmgr)+= dtls/$(DTLSMGR_DIR)/
 obj-$(gre)+= gre/
 obj-$(ipsecmgr)+= ipsecmgr/
 obj-$(l2tpv2)+= l2tp/l2tpv2/
diff --git a/dtls/v2.0/Makefile b/dtls/v2.0/Makefile
new file mode 100644
index 0000000..2785ba1
--- /dev/null
+++ b/dtls/v2.0/Makefile
@@ -0,0 +1,11 @@
+# Makefile for DTLS manager
+
+ccflags-y += $(NSS_CCFLAGS) -I$(obj)/../../exports
+ccflags-y += -DNSS_DTLSMGR_DEBUG_LEVEL=0
+ccflags-y += -DNSS_DTLSMGR_BUILD_ID=\"'Build_ID - $(shell date +'%m/%d/%y, %H:%M:%S') SoC=$(SoC)'\"
+
+obj-m += qca-nss-dtlsmgr.o
+qca-nss-dtlsmgr-objs += nss_dtlsmgr.o
+qca-nss-dtlsmgr-objs += nss_dtlsmgr_ctx.o
+qca-nss-dtlsmgr-objs += nss_dtlsmgr_ctx_dev.o
+qca-nss-dtlsmgr-objs += nss_dtlsmgr_ctx_stats.o
diff --git a/dtls/v2.0/nss_dtlsmgr.c b/dtls/v2.0/nss_dtlsmgr.c
new file mode 100644
index 0000000..418c208
--- /dev/null
+++ b/dtls/v2.0/nss_dtlsmgr.c
@@ -0,0 +1,175 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017, 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.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 <linux/crypto.h>
+#include <linux/debugfs.h>
+#include <linux/rtnetlink.h>
+#include <net/ipv6.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/atomic.h>
+
+#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/aes.h>
+#include <crypto/authenc.h>
+#include <crypto/des.h>
+#include <crypto/sha.h>
+
+#include <nss_api_if.h>
+#include <nss_dynamic_interface.h>
+
+#include <nss_cryptoapi.h>
+#include <nss_dtls_cmn.h>
+#include <nss_dtlsmgr.h>
+
+#include "nss_dtlsmgr_private.h"
+
+/*
+ * Global DTLS context
+ */
+struct nss_dtlsmgr g_dtls = {0};
+
+/*
+ * nss_dtlsmgr_node_configure_done()
+ *	Check and set the configured flag if the DTLS firmware package is successfully configured.
+ */
+static void nss_dtlsmgr_node_configure_done(void *app_data, struct nss_cmn_msg *ncm)
+{
+	struct nss_dtlsmgr *drv = app_data;
+
+	nss_dtlsmgr_info("%p: configure node(%u) response(%d) error(%d)\n", drv,
+			 ncm->interface, ncm->response, ncm->error);
+	atomic_cmpxchg(&drv->is_configured, false, (ncm->response == NSS_CMN_RESPONSE_ACK) ||
+			(ncm->error == NSS_DTLS_CMN_ERROR_ALREADY_CONFIGURED));
+}
+
+/*
+ * nss_dtlsmgr_node_configure()
+ *	Send a configure message to the DTLS firmware package.
+ */
+static void nss_dtlsmgr_node_configure(struct nss_dtlsmgr *drv, uint32_t if_num)
+{
+	struct nss_dtls_cmn_msg ndcm = {0};
+	nss_tx_status_t nss_status;
+
+	/*
+	 * Send DTLS configure message to NSS
+	 */
+	nss_dtls_cmn_msg_init(&ndcm, if_num, NSS_DTLS_CMN_MSG_TYPE_CONFIGURE_NODE, 0,
+			      nss_dtlsmgr_node_configure_done, drv);
+
+	nss_status = nss_dtls_cmn_tx_msg(drv->nss_ctx, &ndcm);
+	if (nss_status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_warn("%p: unable to send node configure (%u)\n", drv, if_num);
+		return;
+	}
+}
+
+/*
+ * nss_dtlsmgr_rx_event()
+ *	Handle the response notification from the firmware.
+ */
+static void nss_dtlsmgr_rx_event(void *app_data, struct nss_cmn_msg *ncm)
+{
+	struct nss_dtlsmgr *drv = app_data;
+
+	nss_dtlsmgr_trace("%p: received Node stats sync:%u\n", drv, ncm->interface);
+
+	/*
+	 * The firmware DTLS should not configure its DMA rings till it
+	 * knows that the HW is fully configured by host crypto driver.
+	 * Since, the firmware boots independent of the host. There is no
+	 * guarantee that the DMA will be ready for configuration when the
+	 * firmware is configuring itself. Thus our approach is to notify
+	 * the firmware to setup its DMA after the host is ready. Here we
+	 * use a simple approach of module load order where the DTLS Manager
+	 * loads after the crypto driver. The expectation is that the crypto
+	 * driver would configure the HW correctly and other modules dependent
+	 * upon it would get the chance to load. Once, the configuration is
+	 * done for DTLS when would like to avoid further configuration of the
+	 * DMA.
+	 *
+	 * TODO: Multiple items
+	 * - Use a nss_cryptoapi_xxx to detect whether the crypto is ready.
+	 * - Add a mechanism to switch to pointer for first time configuration
+	 * - Add support for node stats. Eventhough the node stats is already
+	 * captured in NSS driver.
+	 */
+	if (!atomic_read(&drv->is_configured)) {
+		nss_dtlsmgr_node_configure(drv, ncm->interface);
+		return;
+	}
+}
+
+/*
+ * nss_dtlsmgr_init_module()
+ *	Initialize the DTLS manager module.
+ */
+int __init nss_dtlsmgr_init_module(void)
+{
+	struct nss_dtlsmgr *drv = &g_dtls;
+
+	atomic_set(&drv->is_configured, false);
+
+	nss_dtlsmgr_trace("registering for base interface(%u)", NSS_DTLS_INTERFACE);
+	drv->nss_ctx = nss_dtls_cmn_notify_register(NSS_DTLS_INTERFACE, nss_dtlsmgr_rx_event, drv);
+	if (!drv->nss_ctx) {
+		nss_dtlsmgr_warn("%p: DTLS NSS context instance is NULL", drv);
+		return -ENODEV;
+	}
+
+	drv->root_dir = debugfs_create_dir("qca-nss-dtlsmgr", NULL);
+	if (!drv->root_dir)
+		nss_dtlsmgr_warn("Failed to create debugfs directory");
+
+	pr_info("qca-nss-dtlsmgr module loaded (%s)\n", NSS_DTLSMGR_BUILD_ID);
+	return 0;
+}
+
+/*
+ * nss_dtlsmgr_exit_module()
+ *	Remove the DTLS manager module.
+ */
+void __exit nss_dtlsmgr_exit_module(void)
+{
+	struct nss_dtlsmgr *drv = &g_dtls;
+
+	nss_dtls_cmn_notify_unregister(NSS_DTLS_INTERFACE);
+
+	debugfs_remove_recursive(drv->root_dir);
+
+	atomic_set(&drv->is_configured, false);
+
+	nss_dtlsmgr_info("dtls manger is unloaded");
+}
+
+module_init(nss_dtlsmgr_init_module);
+module_exit(nss_dtlsmgr_exit_module);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("NSS DTLS manager");
diff --git a/dtls/v2.0/nss_dtlsmgr_ctx.c b/dtls/v2.0/nss_dtlsmgr_ctx.c
new file mode 100644
index 0000000..a9818be
--- /dev/null
+++ b/dtls/v2.0/nss_dtlsmgr_ctx.c
@@ -0,0 +1,797 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017, 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_ctx.c
+ *	NSS DTLS Manager Context
+ */
+
+#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 <linux/crypto.h>
+#include <linux/debugfs.h>
+#include <linux/rtnetlink.h>
+#include <net/ipv6.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/atomic.h>
+
+#include <crypto/algapi.h>
+#include <crypto/aead.h>
+#include <crypto/aes.h>
+#include <crypto/authenc.h>
+#include <crypto/des.h>
+#include <crypto/sha.h>
+
+#include <nss_api_if.h>
+#include <nss_dynamic_interface.h>
+
+#include <nss_cryptoapi.h>
+#include <nss_dtls_cmn.h>
+#include <nss_dtlsmgr.h>
+
+#include "nss_dtlsmgr_private.h"
+
+extern struct nss_dtlsmgr g_dtls;
+
+/*
+ * Linux crypto algorithm names.
+ */
+static const char *g_dtls_algo_name[NSS_DTLSMGR_ALGO_MAX] = {
+	"echainiv(authenc(hmac(sha1),cbc(aes)))",
+	"echainiv(authenc(hmac(sha256),cbc(aes)))",
+	"echainiv(authenc(hmac(sha1),cbc(des3_ede)))",
+	"echainiv(authenc(hmac(sha256),cbc(des3_ede)))"
+};
+
+/*
+ * nss_dtlsmgr_ctx_alloc_crypto()
+ *	Allocate a crypto session through Linux CryptoAPI framework.
+ */
+static int nss_dtlsmgr_ctx_alloc_crypto(struct nss_dtlsmgr_ctx *ctx, struct nss_dtlsmgr_dtls_data *dtls,
+					struct nss_dtlsmgr_crypto *crypto)
+{
+	struct crypto_authenc_key_param *key_param;
+	struct rtattr *rta;
+	char *keys, *p;
+	uint16_t keylen;
+
+	if (crypto->algo >= ARRAY_SIZE(g_dtls_algo_name)) {
+		nss_dtlsmgr_warn("%p: invalid crypto algorithm", ctx);
+		return -EINVAL;
+	}
+
+	dtls->aead = crypto_alloc_aead(g_dtls_algo_name[crypto->algo], 0, 0);
+	if (IS_ERR(dtls->aead)) {
+		nss_dtlsmgr_warn("%p: failed to allocate crypto aead context", ctx);
+		return -ENOMEM;
+	}
+
+	nss_dtlsmgr_trace("cipher_keylen:%d auth_keylen:%d\n", crypto->cipher_key.len, crypto->auth_key.len);
+
+	/*
+	 * Construct keys
+	 */
+	keylen = RTA_SPACE(sizeof(*key_param));
+	keylen += crypto->cipher_key.len;
+	keylen += crypto->auth_key.len;
+	keylen += crypto->nonce.len;
+
+	keys = vzalloc(keylen);
+	if (!keys) {
+		nss_dtlsmgr_warn("%p: failed to allocate key memory", ctx);
+		crypto_free_aead(dtls->aead);
+		return -ENOMEM;
+	}
+
+	p = keys;
+	rta = (void *)p;
+	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
+	rta->rta_len = RTA_LENGTH(sizeof(*key_param));
+	key_param = RTA_DATA(rta);
+	p += RTA_SPACE(sizeof(*key_param));
+
+	/*
+	 * Copy authentication key
+	 */
+	memcpy(p, crypto->auth_key.data, crypto->auth_key.len);
+	p += crypto->auth_key.len;
+
+	/*
+	 * Copy cipher Key
+	 */
+	key_param->enckeylen = cpu_to_be32(crypto->cipher_key.len);
+	memcpy(p, crypto->cipher_key.data, crypto->cipher_key.len);
+
+	if (crypto_aead_setkey(dtls->aead, keys, keylen)) {
+		nss_dtlsmgr_warn("%p: failed to configure keys", ctx);
+		vfree(keys);
+		crypto_free_aead(dtls->aead);
+		return -ENOSPC;
+	}
+
+	nss_cryptoapi_aead_ctx2session(dtls->aead, &dtls->crypto_idx);
+	dtls->blk_len = (uint8_t)crypto_aead_blocksize(dtls->aead);
+	dtls->hash_len = (uint8_t)crypto_aead_authsize(dtls->aead);
+	dtls->iv_len = (uint8_t)crypto_aead_ivsize(dtls->aead);
+
+	vfree(keys);
+	return 0;
+}
+
+/*
+ * nss_dtlsmgr_ctx_alloc_dtls()
+ *	Allocate a DTLS session.
+ */
+static struct nss_dtlsmgr_dtls_data *nss_dtlsmgr_ctx_alloc_dtls(struct nss_dtlsmgr_ctx *ctx,
+								struct nss_dtlsmgr_ctx_data *data,
+								struct nss_dtlsmgr_crypto *crypto)
+{
+	struct nss_dtlsmgr_dtls_data *dtls;
+	int error;
+
+	nss_dtlsmgr_trace("%p: allocating context data(%u)", ctx, data->di_type);
+
+	dtls = vzalloc(sizeof(*dtls));
+	if (!dtls) {
+		nss_dtlsmgr_warn("%p: failed to allocate dtls data(%u) ", ctx, data->di_type);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&dtls->list);
+
+	error = nss_dtlsmgr_ctx_alloc_crypto(ctx, dtls, crypto);
+	if (error < 0) {
+		nss_dtlsmgr_warn("%p: unable to allocate crypto(%u) - error(%d)", ctx, data->di_type, error);
+		vfree(dtls);
+		return NULL;
+	}
+
+	nss_dtlsmgr_trace("%p: crypto_aead allocated", ctx);
+	return dtls;
+}
+
+/*
+ * nss_dtlsmgr_ctx_free_dtls()
+ *	Free the DTLS context.
+ */
+static void nss_dtlsmgr_ctx_free_dtls(struct nss_dtlsmgr_dtls_data *dtls)
+{
+	crypto_free_aead(dtls->aead);
+	vfree(dtls);
+}
+
+/*
+ * nss_dtlsmgr_ctx_configure_hdr()
+ *	Configure the DTLS header related information.
+ */
+static bool nss_dtlsmgr_ctx_configure_hdr(struct nss_dtlsmgr_ctx_data *data)
+{
+	const uint32_t type = NSS_DTLS_CMN_MSG_TYPE_CONFIGURE_HDR;
+	enum nss_dtls_cmn_error resp = NSS_DTLS_CMN_ERROR_NONE;
+	struct nss_dtls_cmn_ctx_config_hdr *cfg;
+	struct nss_dtls_cmn_msg ndcm = { {0} };
+	nss_tx_status_t status;
+	uint32_t mask = 0;
+
+	BUG_ON(in_atomic());
+
+	mask |= NSS_DTLS_CMN_CTX_HDR_IPV6;
+	mask |= NSS_DTLS_CMN_CTX_HDR_UDPLITE;
+	mask |= NSS_DTLS_CMN_CTX_HDR_CAPWAP;
+	mask |= NSS_DTLS_CMN_CTX_CIPHER_MODE_GCM;
+	mask |= NSS_DTLS_CMN_CTX_OUTER_UDPLITE_CSUM;
+	mask |= NSS_DTLS_CMN_CTX_INNER_ACCEPT_ALL;
+
+	cfg = &ndcm.msg.hdr_cfg;
+	cfg->flags = data->flags & mask;
+	cfg->dest_ifnum = data->dest_ifnum;
+	cfg->src_ifnum = data->src_ifnum;
+
+	memcpy(cfg->sip, data->flow.sip, sizeof(cfg->sip));
+	memcpy(cfg->dip, data->flow.dip, sizeof(cfg->dip));
+
+	cfg->sport = data->flow.sport;
+	cfg->dport = data->flow.dport;
+	cfg->hop_limit_ttl = data->flow.hop_limit_ttl;
+	cfg->dscp = data->flow.dscp;
+	cfg->dscp_copy = data->flow.dscp_copy;
+	cfg->df = data->flow.df;
+
+	nss_dtlsmgr_trace("flags:0x%x dest_ifnum:0x%x src_ifnum:0x%x sport:0x%x dport:0x%x sip:0x%x dip:0x%x",
+			  cfg->flags, cfg->dest_ifnum, cfg->src_ifnum, cfg->sport, cfg->dport,
+			  cfg->sip[0], cfg->dip[0]);
+
+	status = nss_dtls_cmn_tx_msg_sync(data->nss_ctx, data->ifnum, type, sizeof(*cfg), &ndcm, &resp);
+	if (status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_warn("%p: msg_sync failed, if_num(%u), status(%d), type(%d), resp(%d)",
+				 data, data->ifnum, type, status, resp);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * nss_dtlsmgr_ctx_configure_dtls()
+ *	Configure the DTLS version, crypto related data, window size and epoch.
+ */
+static bool nss_dtlsmgr_ctx_configure_dtls(struct nss_dtlsmgr_ctx_data *data, struct nss_dtlsmgr_dtls_data *dtls)
+{
+	const uint32_t type = NSS_DTLS_CMN_MSG_TYPE_CONFIGURE_DTLS;
+	enum nss_dtls_cmn_error resp = NSS_DTLS_CMN_ERROR_NONE;
+	struct nss_dtls_cmn_ctx_config_dtls *cfg;
+	struct nss_dtls_cmn_msg ndcm = {0};
+	nss_tx_status_t status;
+
+	BUG_ON(in_atomic());
+
+	cfg = &ndcm.msg.dtls_cfg;
+	cfg->ver = dtls->ver;
+	cfg->crypto_idx = dtls->crypto_idx;
+	cfg->epoch = dtls->epoch;
+	cfg->window_size = dtls->window_size;
+	cfg->iv_len = dtls->iv_len;
+	cfg->hash_len = dtls->hash_len;
+	cfg->blk_len = dtls->blk_len;
+
+	status = nss_dtls_cmn_tx_msg_sync(data->nss_ctx, data->ifnum, type, sizeof(*cfg), &ndcm, &resp);
+	if (status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_warn("%p: msg_sync failed, if_num(%u), status(%d), type(%d), resp(%d)",
+				data, data->ifnum, type, status, resp);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * nss_dtlsmgr_ctx_deconfigure()
+ *	Deconfigure the DTLS context and free all the related data.
+ */
+static bool nss_dtlsmgr_ctx_deconfigure(struct nss_dtlsmgr_ctx *ctx, struct nss_dtlsmgr_ctx_data *data)
+{
+	const uint32_t type = NSS_DTLS_CMN_MSG_TYPE_CONFIGURE_DTLS;
+	enum nss_dtls_cmn_error resp = NSS_DTLS_CMN_ERROR_NONE;
+	struct nss_dtls_cmn_msg ndcm = {0};
+	struct nss_dtlsmgr_dtls_data *cur;
+	nss_tx_status_t status;
+
+	status = nss_dtls_cmn_tx_msg_sync(data->nss_ctx, data->ifnum, type, 0, &ndcm, &resp);
+	if (status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_warn("%p: msg_sync failed, if_num(%u), status(%d), type(%d), resp(%d)",
+				ctx, data->ifnum, type, status, resp);
+		return false;
+	}
+
+	nss_dtls_cmn_unregister_if(data->ifnum);
+
+	for (;;) {
+		write_lock(&ctx->lock);
+		cur = list_first_entry_or_null(&data->dtls_active, struct nss_dtlsmgr_dtls_data, list);
+		if (!cur) {
+			write_unlock(&ctx->lock);
+			break;
+		}
+
+		list_del(&cur->list);
+		write_unlock(&ctx->lock);
+		nss_dtlsmgr_ctx_free_dtls(cur);
+	}
+
+	status = nss_dynamic_interface_dealloc_node(data->ifnum, data->di_type);
+	if (status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_warn("%p: fail to deallocate dynamic(%d) interface(%u)", ctx, data->di_type, data->ifnum);
+		return false;
+	}
+
+	data->ifnum = -1;
+	return true;
+}
+
+/*
+ * nss_dtlsmgr_ctx_create_encap()
+ *	Create DTLS encapsulation dynamic interface and configure the DTLS context.
+ */
+static int nss_dtlsmgr_ctx_create_encap(struct nss_dtlsmgr_ctx *ctx, uint32_t ifnum,
+					uint32_t src_ifnum, struct nss_dtlsmgr_config *ndc)
+{
+	struct nss_dtlsmgr_encap_config *cfg = &ndc->encap;
+	struct nss_dtlsmgr_ctx_data *data = &ctx->encap;
+	struct nss_dtlsmgr_flow_data *flow = &data->flow;
+	struct nss_dtlsmgr_dtls_data *dtls;
+	uint32_t mask;
+
+	dtls = nss_dtlsmgr_ctx_alloc_dtls(ctx, &ctx->encap, &ndc->encap.crypto);
+	if (!dtls) {
+		nss_dtlsmgr_warn("%p: unable to allocate encap context data", ctx);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&data->dtls_active);
+
+	data->di_type = NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER;
+	data->ifnum = ifnum;
+	data->src_ifnum = src_ifnum;
+	data->flags = ndc->flags;
+	data->tailroom = dtls->blk_len + dtls->hash_len;
+	data->headroom = dtls->iv_len;
+
+	memcpy(&flow->sip, cfg->sip, sizeof(flow->sip));
+	memcpy(&flow->dip, cfg->dip, sizeof(flow->dip));
+
+	flow->sport = cfg->sport;
+	flow->dport = cfg->dport;
+	flow->dscp = cfg->dscp;
+	flow->dscp_copy = cfg->dscp_copy;
+	flow->df = cfg->df;
+	flow->hop_limit_ttl = cfg->ip_ttl;
+
+	dtls->epoch = cfg->epoch;
+	dtls->ver = cfg->ver;
+
+	mask = NSS_DTLSMGR_HDR_IPV6 | NSS_DTLSMGR_HDR_CAPWAP;
+
+	data->headroom += NSS_DTLSMGR_DTLS_HDR_SZ;
+
+	/*
+	 * We need to provide the firmware the source and
+	 * destination interface number. This allows it
+	 * to work with dynamically created interfaces
+	 *
+	 */
+	switch (mask & ndc->flags) {
+	case NSS_DTLSMGR_HDR_IPV6 | NSS_DTLSMGR_HDR_CAPWAP:
+		data->dest_ifnum = NSS_IPV6_RX_INTERFACE;
+		data->headroom += sizeof(struct ipv6hdr);
+		data->headroom += NSS_DTLSMGR_CAPWAP_DTLS_HDR_SZ;
+		break;
+	case NSS_DTLSMGR_HDR_IPV6:
+		data->dest_ifnum = NSS_IPV6_RX_INTERFACE;
+		data->headroom += sizeof(struct ipv6hdr);
+		break;
+	case NSS_DTLSMGR_HDR_CAPWAP:
+		data->dest_ifnum = NSS_IPV4_RX_INTERFACE;
+		data->headroom += sizeof(struct iphdr);
+		data->headroom += NSS_DTLSMGR_CAPWAP_DTLS_HDR_SZ;
+		break;
+	default:
+		data->dest_ifnum = NSS_IPV4_RX_INTERFACE;
+		data->headroom += sizeof(struct iphdr);
+		break;
+	}
+
+	/*
+	 * Header size is same for UDP and UDPLite
+	 */
+	data->headroom += sizeof(struct udphdr);
+
+	nss_dtlsmgr_trace("%p: encap ifnum(%u), src(%u), dest(0x%x)", ctx, data->ifnum,
+			  data->src_ifnum, data->dest_ifnum);
+
+	/*
+	 * Register NSS DTLS Encap I/F
+	 */
+	data->nss_ctx = nss_dtls_cmn_register_if(data->ifnum,
+						nss_dtlsmgr_ctx_dev_rx,
+						nss_dtlsmgr_ctx_dev_event,
+						ctx->dev,
+						0,
+						data->di_type,
+						(void *)data);
+	if (!data->nss_ctx) {
+		nss_dtlsmgr_warn("%p: NSS register interface(%u) failed", ctx, data->ifnum);
+		nss_dtlsmgr_ctx_free_dtls(dtls);
+		return -ENODEV;
+	}
+
+	if (!nss_dtlsmgr_ctx_configure_hdr(data)) {
+		nss_dtlsmgr_warn("%p: unable to configure(%d) hdr", ctx, data->di_type);
+		goto fail;
+	}
+
+	if (!nss_dtlsmgr_ctx_configure_dtls(data, dtls)) {
+		nss_dtlsmgr_warn("%p: unable to configure(%d) dtls", ctx, data->di_type);
+		goto fail;
+	}
+
+	write_lock(&ctx->lock);
+	list_add(&dtls->list, &data->dtls_active);
+	write_unlock(&ctx->lock);
+
+	return 0;
+fail:
+	nss_dtls_cmn_unregister_if(data->ifnum);
+	nss_dtlsmgr_ctx_free_dtls(dtls);
+	return -EBUSY;
+}
+
+/*
+ * nss_dtlsmgr_ctx_create_decap()
+ *	Create DTLS decapsulation dynamic interface and configure the DTLS context.
+ */
+static int nss_dtlsmgr_ctx_create_decap(struct nss_dtlsmgr_ctx *ctx, uint32_t ifnum, uint32_t src_ifnum,
+					struct nss_dtlsmgr_config *cfg)
+{
+	struct nss_dtlsmgr_ctx_data *data = &ctx->decap;
+	struct nss_dtlsmgr_dtls_data *dtls;
+
+	dtls = nss_dtlsmgr_ctx_alloc_dtls(ctx, &ctx->decap, &cfg->decap.crypto);
+	if (!dtls) {
+		nss_dtlsmgr_warn("%p: unable to allocate decap context data", ctx);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&data->dtls_active);
+
+	data->di_type = NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER;
+	data->ifnum = ifnum;
+
+	/*
+	 * We need to provide the firmware the source and
+	 * destination interface number. This allows it
+	 * to work with dynamically created interfaces
+	 *
+	 */
+	data->src_ifnum = src_ifnum;
+	data->dest_ifnum = cfg->decap.nexthop_ifnum;
+	data->tailroom = data->headroom = 0;
+	data->flags = cfg->flags;
+
+	nss_dtlsmgr_trace("%p: decap ifnum(%u), src(%u), dest(%u)", ctx, data->ifnum,
+			  data->src_ifnum, data->dest_ifnum);
+
+	dtls->window_size = cfg->decap.window_size;
+	dtls->ver = cfg->encap.ver;
+
+	/*
+	 * Register NSS DTLS Decap I/F
+	 */
+	data->nss_ctx = nss_dtls_cmn_register_if(data->ifnum,
+						nss_dtlsmgr_ctx_dev_rx,
+						nss_dtlsmgr_ctx_dev_event,
+						ctx->dev,
+						0,
+						data->di_type,
+						(void *)data);
+	if (!data->nss_ctx) {
+		nss_dtlsmgr_warn("%p: NSS register interface(%u) failed", ctx, data->ifnum);
+		nss_dtlsmgr_ctx_free_dtls(dtls);
+		return -ENODEV;
+	}
+
+	if (!nss_dtlsmgr_ctx_configure_hdr(data)) {
+		nss_dtlsmgr_warn("%p: unable to configure(%d) hdr", ctx, data->di_type);
+		goto fail;
+	}
+
+	if (!nss_dtlsmgr_ctx_configure_dtls(data, dtls)) {
+		nss_dtlsmgr_warn("%p: unable to configure(%d) hdr", ctx, data->di_type);
+		goto fail;
+	}
+
+	write_lock(&ctx->lock);
+	list_add(&dtls->list, &data->dtls_active);
+	write_unlock(&ctx->lock);
+
+	return 0;
+fail:
+	nss_dtls_cmn_unregister_if(data->ifnum);
+	nss_dtlsmgr_ctx_free_dtls(dtls);
+	return -EBUSY;
+}
+
+/*
+ * nss_dtlsmgr_session_create()
+ *	Create DTLS session and associated crypto sessions.
+ */
+struct net_device *nss_dtlsmgr_session_create(struct nss_dtlsmgr_config *cfg)
+{
+	struct nss_dtlsmgr *drv = &g_dtls;
+	struct nss_dtlsmgr_ctx *ctx;
+	struct net_device *dev;
+	int32_t encap_ifnum;
+	int32_t decap_ifnum;
+	int error;
+
+	if (!atomic_read(&drv->is_configured)) {
+		nss_dtlsmgr_warn("%p: dtls firmware not ready", drv);
+		return NULL;
+	}
+
+	if ((cfg->encap.ver != NSS_DTLSMGR_VERSION_1_0) && (cfg->encap.ver != NSS_DTLSMGR_VERSION_1_2)) {
+		nss_dtlsmgr_warn("%p: invalid encapsulation version(%d)", drv, cfg->encap.ver);
+		return NULL;
+	}
+
+	encap_ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER);
+	if (encap_ifnum < 0) {
+		nss_dtlsmgr_warn("%p: failed to allocate encap dynamic interface(%u)", drv, encap_ifnum);
+		return NULL;
+	}
+
+	decap_ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER);
+	if (decap_ifnum < 0) {
+		nss_dtlsmgr_warn("%p: failed to allocate decap dynamic interface(%u)", drv, decap_ifnum);
+		goto dealloc_encap_node;
+	}
+
+	nss_dtlsmgr_trace("dynamic interfaces, encap(%u), decap(%u)", encap_ifnum, decap_ifnum);
+
+	dev = alloc_netdev(sizeof(*ctx), "dtls%d", NET_NAME_ENUM, nss_dtlsmgr_ctx_dev_setup);
+	if (!dev) {
+		nss_dtlsmgr_warn("%p: unable to allocate dtls device", ctx);
+		goto dealloc_decap_node;
+	}
+
+	ctx = netdev_priv(dev);
+	ctx->dev = dev;
+	rwlock_init(&ctx->lock);
+
+	NSS_DTLSMGR_SET_MAGIC(ctx, NSS_DTLSMGR_CTX_MAGIC);
+
+	error = nss_dtlsmgr_ctx_create_encap(ctx, encap_ifnum, decap_ifnum, cfg);
+	if (error < 0) {
+		nss_dtlsmgr_warn("%p: unable to create encap context, error(%d)", ctx, error);
+		goto free_dev;
+	}
+
+	error = nss_dtlsmgr_ctx_create_decap(ctx, decap_ifnum, encap_ifnum, cfg);
+	if (error < 0) {
+		nss_dtlsmgr_warn("%p: unable to create decap context, error(%d)", ctx, error);
+		goto destroy_encap;
+	}
+
+	dev->needed_headroom = ctx->encap.headroom;
+	dev->needed_tailroom = ctx->encap.tailroom;
+
+	error = rtnl_is_locked() ? register_netdevice(dev) : register_netdev(dev);
+	if (error < 0) {
+		nss_dtlsmgr_warn("%p: unable register net_device(%s)", ctx, dev->name);
+		goto destroy_decap;
+	}
+
+	dev->mtu = dev->mtu - (ctx->encap.headroom + ctx->encap.tailroom);
+
+	nss_dtlsmgr_trace("%p: dtls session(%s) created, encap(%u), decap(%u)",
+			  ctx, dev->name, ctx->encap.ifnum, ctx->decap.ifnum);
+
+	if (nss_dtlsmgr_create_debugfs(ctx)) {
+		nss_dtlsmgr_warn("Failed to create debugfs for ctx(%p)", ctx);
+	}
+
+	return dev;
+
+destroy_decap:
+	nss_dtlsmgr_ctx_deconfigure(ctx, &ctx->decap);
+
+destroy_encap:
+	nss_dtlsmgr_ctx_deconfigure(ctx, &ctx->encap);
+
+free_dev:
+	free_netdev(dev);
+
+dealloc_decap_node:
+	nss_dynamic_interface_dealloc_node(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER);
+
+dealloc_encap_node:
+	nss_dynamic_interface_dealloc_node(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER);
+	return NULL;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_session_create);
+
+/*
+ * nss_dtlsmgr_session_destroy()
+ *	Destroy DTLS session
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_session_destroy(struct net_device *dev)
+{
+	struct nss_dtlsmgr_ctx *ctx = netdev_priv(dev);
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+
+	if (!nss_dtlsmgr_ctx_deconfigure(ctx, &ctx->encap)) {
+		nss_dtlsmgr_warn("%p: unable to deconfigure encap", ctx);
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	if (!nss_dtlsmgr_ctx_deconfigure(ctx, &ctx->decap)) {
+		nss_dtlsmgr_warn("%p: unable to deconfigure decap", ctx);
+		return NSS_DTLSMGR_FAIL;
+	}
+
+	NSS_DTLSMGR_SET_MAGIC(ctx, 0);
+
+	rtnl_is_locked() ? unregister_netdevice(dev) : unregister_netdev(dev);
+
+	return NSS_DTLSMGR_OK;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_session_destroy);
+
+/*
+ * nss_dtlsmgr_session_update_encap()
+ *	Update the encapsulation crypto keys.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_session_update_encap(struct net_device *dev, struct nss_dtlsmgr_config_update *cfg)
+{
+	struct nss_dtlsmgr_ctx *ctx = netdev_priv(dev);
+	struct nss_dtlsmgr_ctx_data *data = &ctx->encap;
+	struct nss_dtlsmgr_dtls_data *dtls, *prev_dtls;
+
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+
+	dtls = nss_dtlsmgr_ctx_alloc_dtls(ctx, &ctx->encap, &cfg->crypto);
+	if (!dtls) {
+		nss_dtlsmgr_warn("%p: unable to update encap context data", ctx);
+		return NSS_DTLSMGR_FAIL_NOMEM;
+	}
+
+	/*
+	 * Get the first entry in the list to compare the crypto key lengths
+	 */
+	prev_dtls = list_first_entry_or_null(&data->dtls_active, struct nss_dtlsmgr_dtls_data, list);
+	if (!prev_dtls) {
+		nss_dtlsmgr_warn("%p: dtls list is emtpy\n", ctx);
+		return NSS_DTLSMGR_FAIL_NOCRYPTO;
+	}
+
+	/*
+	 * If the new keys lengths are longer, then there isn't enough headroom and tailroom.
+	 */
+	BUG_ON(prev_dtls->iv_len < dtls->iv_len);
+	BUG_ON(prev_dtls->blk_len < dtls->blk_len);
+	BUG_ON(prev_dtls->hash_len < dtls->hash_len);
+
+	nss_dtlsmgr_trace("%p: encap context update allocated (%u)", ctx, ctx->encap.ifnum);
+
+	dtls->epoch = cfg->epoch;
+	dtls->window_size = cfg->window_size;
+
+	if (!nss_dtlsmgr_ctx_configure_dtls(&ctx->encap, dtls)) {
+		nss_dtlsmgr_warn("%p: unable to configure encap dtls", ctx);
+		nss_dtlsmgr_ctx_free_dtls(dtls);
+		return NSS_DTLSMGR_FAIL_MESSAGE;
+	}
+
+	write_lock(&ctx->lock);
+	list_add_tail(&dtls->list, &ctx->encap.dtls_active);
+	write_unlock(&ctx->lock);
+
+	nss_dtlsmgr_trace("%p: encap context update done", ctx);
+	return NSS_DTLSMGR_OK;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_session_update_encap);
+
+/*
+ * nss_dtlsmgr_session_update_decap()
+ *	Update the decapsulation crypto keys.
+ */
+nss_dtlsmgr_status_t nss_dtlsmgr_session_update_decap(struct net_device *dev, struct nss_dtlsmgr_config_update *cfg)
+{
+	struct nss_dtlsmgr_ctx *ctx = netdev_priv(dev);
+	struct nss_dtlsmgr_dtls_data *dtls;
+
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+
+	dtls = nss_dtlsmgr_ctx_alloc_dtls(ctx, &ctx->decap, &cfg->crypto);
+	if (!dtls) {
+		nss_dtlsmgr_warn("%p: unable to update decap context data", ctx);
+		return NSS_DTLSMGR_FAIL_NOMEM;
+	}
+
+	nss_dtlsmgr_trace("%p: decap context update allocated (%u)", ctx, ctx->decap.ifnum);
+
+	dtls->epoch = cfg->epoch;
+	dtls->window_size = cfg->window_size;
+
+	if (!nss_dtlsmgr_ctx_configure_dtls(&ctx->decap, dtls)) {
+		nss_dtlsmgr_warn("%p: unable to configure decap dtls", ctx);
+		nss_dtlsmgr_ctx_free_dtls(dtls);
+		return NSS_DTLSMGR_FAIL_MESSAGE;
+	}
+
+	write_lock(&ctx->lock);
+	list_add_tail(&dtls->list, &ctx->decap.dtls_active);
+	write_unlock(&ctx->lock);
+
+	nss_dtlsmgr_trace("%p: decap context update done", ctx);
+	return NSS_DTLSMGR_OK;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_session_update_decap);
+
+/*
+ * nss_dtlsmgr_session_switch()
+ *	Send a switch message to the DTLS firmware packege to switch to
+ *	the new cryptographic keys.
+ */
+static bool nss_dtlsmgr_session_switch(struct nss_dtlsmgr_ctx *ctx, struct nss_dtlsmgr_ctx_data *data)
+{
+	const uint32_t type = NSS_DTLS_CMN_MSG_TYPE_SWITCH_DTLS;
+	enum nss_dtls_cmn_error resp = NSS_DTLS_CMN_ERROR_NONE;
+	struct nss_dtls_cmn_msg ndcm = {0};
+	struct nss_dtlsmgr_dtls_data *dtls;
+	nss_tx_status_t status;
+
+	/*
+	 * We essentially pop the head of the dtls list.
+	 * It is expected that an update should have already
+	 * added a new dtls entry at the tail of the list
+	 */
+	write_lock(&ctx->lock);
+	dtls = list_first_entry_or_null(&data->dtls_active, struct nss_dtlsmgr_dtls_data, list);
+	if (!dtls) {
+		write_unlock(&ctx->lock);
+		return false;
+	}
+
+	list_del(&dtls->list);
+	write_unlock(&ctx->lock);
+
+	BUG_ON(in_atomic());
+
+	status = nss_dtls_cmn_tx_msg_sync(data->nss_ctx, data->ifnum, type, 0, &ndcm, &resp);
+	if (status != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_warn("%p: msg_sync failed, if_num(%u), status(%d), type(%d), resp(%d)",
+				ctx, data->ifnum, type, status, resp);
+		return false;
+	}
+
+	nss_dtlsmgr_ctx_free_dtls(dtls);
+	return true;
+}
+
+/*
+ * nss_dtlsmgr_session_switch_encap()
+ *	Send a message to encapsulation DTLS interface to switch to the new crypto keys.
+ */
+bool nss_dtlsmgr_session_switch_encap(struct net_device *dev)
+{
+	struct nss_dtlsmgr_ctx *ctx = netdev_priv(dev);
+	struct nss_dtlsmgr_ctx_data *data = &ctx->encap;
+
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+
+	if (!nss_dtlsmgr_session_switch(ctx, data)) {
+		nss_dtlsmgr_warn("%p: failed to send encap switch_dtls(%u)", ctx, data->ifnum);
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_session_switch_encap);
+
+/*
+ * nss_dtlsmgr_session_switch_decap()
+ *	Send a message to decapsulation DTLS interface to switch to the new crypto keys.
+ */
+bool nss_dtlsmgr_session_switch_decap(struct net_device *dev)
+{
+	struct nss_dtlsmgr_ctx *ctx = netdev_priv(dev);
+	struct nss_dtlsmgr_ctx_data *data = &ctx->decap;
+
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+
+	if (!nss_dtlsmgr_session_switch(ctx, data)) {
+		nss_dtlsmgr_warn("%p: failed to send decap switch_dtls(%u)", ctx, data->ifnum);
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(nss_dtlsmgr_session_switch_decap);
diff --git a/dtls/v2.0/nss_dtlsmgr_ctx_dev.c b/dtls/v2.0/nss_dtlsmgr_ctx_dev.c
new file mode 100644
index 0000000..2c3b126
--- /dev/null
+++ b/dtls/v2.0/nss_dtlsmgr_ctx_dev.c
@@ -0,0 +1,376 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017, 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_ctx_dev.c
+ *	NSS DTLS Manager context device
+ */
+
+#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 <crypto/aes.h>
+#include <crypto/sha.h>
+
+#include <nss_api_if.h>
+#include <nss_dynamic_interface.h>
+#include <nss_dtls_cmn.h>
+#include <nss_dtlsmgr.h>
+
+#include "nss_dtlsmgr_private.h"
+
+/*
+ * nss_dtlsmgr_ctx_dev_event()
+ *	Event Callback to receive events from NSS.
+ */
+void nss_dtlsmgr_ctx_dev_event(void *if_ctx, struct nss_cmn_msg *ncm)
+{
+	struct nss_dtls_cmn_msg *ndcm = (struct nss_dtls_cmn_msg *)ncm;
+	struct nss_dtlsmgr_ctx_data *data = (struct nss_dtlsmgr_ctx_data *)if_ctx;
+	struct nss_dtls_cmn_ctx_stats *msg_stats = &ndcm->msg.stats;
+	struct nss_dtlsmgr_stats *stats;
+	struct nss_dtlsmgr_ctx *ctx;
+	bool encap;
+	int i;
+
+	if (ncm->type != NSS_DTLS_CMN_MSG_TYPE_SYNC_STATS) {
+		nss_dtlsmgr_warn("%p: unsupported message type(%d)", data, ncm->type);
+		return;
+	}
+
+	if ((data->di_type != NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER) &&
+	    (data->di_type != NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER)) {
+		nss_dtlsmgr_warn("%p: unsupported interface type(%d)", data, data->di_type);
+		return;
+	}
+
+	stats = &data->stats;
+
+	if (data->di_type == NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER) {
+		ctx = container_of(data, struct nss_dtlsmgr_ctx, encap);
+		encap = true;
+	} else {
+		ctx = container_of(data, struct nss_dtlsmgr_ctx, decap);
+		encap = false;
+	}
+
+	dev_hold(ctx->dev);
+
+	stats->tx_packets += msg_stats->pkt.tx_packets;
+	stats->tx_bytes += msg_stats->pkt.tx_bytes;
+
+	stats->rx_packets += msg_stats->pkt.rx_packets;
+	stats->rx_bytes += msg_stats->pkt.rx_bytes;
+	stats->rx_dropped += nss_cmn_rx_dropped_sum(&msg_stats->pkt);
+	stats->rx_single_rec += msg_stats->rx_single_rec;
+	stats->rx_multi_rec += msg_stats->rx_multi_rec;
+
+	stats->fail_crypto_resource += msg_stats->fail_crypto_resource;
+	stats->fail_crypto_enqueue += msg_stats->fail_crypto_enqueue;
+	stats->fail_headroom += msg_stats->fail_headroom;
+	stats->fail_tailroom += msg_stats->fail_tailroom;
+	stats->fail_ver += msg_stats->fail_ver;
+	stats->fail_epoch += msg_stats->fail_epoch;
+	stats->fail_dtls_record += msg_stats->fail_dtls_record;
+	stats->fail_capwap += msg_stats->fail_capwap;
+	stats->fail_replay += msg_stats->fail_replay;
+	stats->fail_replay_dup += msg_stats->fail_replay_dup;
+	stats->fail_replay_win += msg_stats->fail_replay_win;
+	stats->fail_queue += msg_stats->fail_queue;
+	stats->fail_queue_nexthop += msg_stats->fail_queue_nexthop;
+	stats->fail_pbuf_alloc += msg_stats->fail_pbuf_alloc;
+	stats->fail_pbuf_linear += msg_stats->fail_pbuf_linear;
+	stats->fail_pbuf_stats += msg_stats->fail_pbuf_stats;
+	stats->fail_pbuf_align += msg_stats->fail_pbuf_align;
+	stats->fail_ctx_active += msg_stats->fail_ctx_active;
+	stats->fail_hwctx_active += msg_stats->fail_hwctx_active;
+	stats->fail_cipher += msg_stats->fail_cipher;
+	stats->fail_auth += msg_stats->fail_auth;
+	stats->fail_seq_ovf += msg_stats->fail_seq_ovf;
+	stats->fail_blk_len += msg_stats->fail_blk_len;
+	stats->fail_hash_len += msg_stats->fail_hash_len;
+
+	stats->fail_hw.len_error += msg_stats->fail_hw.len_error;
+	stats->fail_hw.token_error += msg_stats->fail_hw.token_error;
+	stats->fail_hw.bypass_error += msg_stats->fail_hw.bypass_error;
+	stats->fail_hw.config_error += msg_stats->fail_hw.config_error;
+	stats->fail_hw.algo_error += msg_stats->fail_hw.algo_error;
+	stats->fail_hw.hash_ovf_error += msg_stats->fail_hw.hash_ovf_error;
+	stats->fail_hw.ttl_error += msg_stats->fail_hw.ttl_error;
+	stats->fail_hw.csum_error += msg_stats->fail_hw.csum_error;
+	stats->fail_hw.timeout_error += msg_stats->fail_hw.timeout_error;
+
+	for (i = 0; i < NSS_DTLS_CMN_CLE_MAX; i++)
+		stats->fail_cle[i] += msg_stats->fail_cle[i];
+
+	if (data->notify)
+		data->notify(ctx->dev, &data->stats, encap);
+
+	dev_put(ctx->dev);
+}
+
+/*
+ * nss_dtlsmgr_ctx_dev_rx()
+ *	Receive and process packet from NSS.
+ */
+void nss_dtlsmgr_ctx_dev_rx(struct net_device *dev, struct sk_buff *skb, struct napi_struct *napi)
+{
+	struct nss_dtlsmgr_ctx *ctx;
+	struct nss_dtlsmgr_stats *stats;
+	uint32_t meta;
+
+	BUG_ON(!dev);
+	BUG_ON(!skb);
+
+	dev_hold(dev);
+	ctx = netdev_priv(dev);
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+
+	stats = &ctx->decap.stats;
+
+	/*
+	 * Get DTLS metadata
+	 */
+	meta = ntohl(*(uint32_t *)skb->data);
+	if (NSS_DTLSMGR_METADATA_CTYPE(meta) != NSS_DTLSMGR_CTYPE_APP) {
+		nss_dtlsmgr_warn("%p: dropping non app dtls pkt(%p)", ctx, skb);
+		goto free;
+	}
+
+	if (NSS_DTLSMGR_METADATA_ERROR(meta) != NSS_DTLSMGR_METADATA_ERROR_OK) {
+		nss_dtlsmgr_warn("%p: dropping error dtls pkt(%p)", ctx, skb);
+		goto free;
+	}
+
+	/*
+	 * 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;
+
+	switch (ip_hdr(skb)->version) {
+	case IPVERSION:
+		skb->protocol = htons(ETH_P_IP);
+		break;
+
+	case 6:
+		skb->protocol = htons(ETH_P_IPV6);
+		break;
+
+	default:
+		nss_dtlsmgr_warn("%p: received non-IP packet, dropping", ctx);
+		goto free;
+	}
+
+	netif_receive_skb(skb);
+	dev_put(dev);
+	return;
+free:
+	dev_kfree_skb_any(skb);
+	stats->rx_dropped++;
+	dev_put(dev);
+	return;
+}
+
+/*
+ * nss_dtlsmgr_ctx_dev_tx()
+ *	Transmit packet to DTLS node in NSS firmware.
+ */
+static netdev_tx_t nss_dtlsmgr_ctx_dev_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct nss_dtlsmgr_ctx *ctx = netdev_priv(dev);
+	struct nss_dtlsmgr_ctx_data *encap;
+	struct nss_dtlsmgr_stats *stats;
+	bool expand_skb = false, drop;
+	int nhead, ntail;
+	uint8_t proto;
+
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+	encap = &ctx->encap;
+	stats = &encap->stats;
+	nhead = dev->needed_headroom;
+	ntail = dev->needed_tailroom;
+
+	/*
+	 * Check if skb is shared
+	 */
+	if (unlikely(skb_shared(skb))) {
+		nss_dtlsmgr_trace("%p: shared skb is not supported on (%s): %p", ctx, dev->name, skb);
+		goto free;
+	}
+
+	/*
+	 * Check if packet is given starting from network header
+	 */
+	if (skb->data != skb_network_header(skb)) {
+		nss_dtlsmgr_trace("%p: skb data is not starting from IP header(%s)", ctx, dev->name);
+		goto free;
+	}
+
+	/*
+	 * For all these cases
+	 * - create a writable copy of buffer
+	 * - increase the head room
+	 * - increase the tail room
+	 */
+	if (skb_cloned(skb) || (skb_headroom(skb) < nhead) || (skb_tailroom(skb) < ntail)) {
+		expand_skb = true;
+	}
+
+	if (expand_skb && pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC)) {
+		nss_dtlsmgr_trace("%p: unable to expand buffer for (%s)", ctx, dev->name);
+		stats->fail_headroom++;
+		goto free;
+	}
+
+	proto = ntohs(skb->protocol);
+
+	switch (skb->protocol) {
+	case ETH_P_IP:
+		drop = (encap->flow.flags & NSS_DTLSMGR_HDR_IPV6) == NSS_DTLSMGR_HDR_IPV6;
+		break;
+
+	case htons(ETH_P_IPV6):
+		drop = (encap->flow.flags & NSS_DTLSMGR_HDR_IPV6) != NSS_DTLSMGR_HDR_IPV6;
+		break;
+
+	default:
+		drop = true;
+	}
+
+	if (drop) {
+		nss_dtlsmgr_warn("%p: dtls encap not supported, proto(%d), flags(%u)", ctx, proto, encap->flow.flags);
+		goto free;
+	}
+
+	if (nss_dtls_cmn_tx_buf(skb, encap->ifnum, encap->nss_ctx) != NSS_TX_SUCCESS) {
+		nss_dtlsmgr_trace("%p: unable to tx buffer for (%u)", ctx, encap->ifnum);
+		return NETDEV_TX_BUSY;
+	}
+
+	return NETDEV_TX_OK;
+free:
+	dev_kfree_skb_any(skb);
+	return NETDEV_TX_OK;
+}
+
+/*
+ * nss_dtlsmgr_ctx_dev_close()
+ *	Stop packet transmission on the DTLS network device.
+ */
+static int nss_dtlsmgr_ctx_dev_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+/*
+ * nss_dtlsmgr_ctx_dev_open()
+ *	Start processing packets on the DTLS network device.
+ */
+static int nss_dtlsmgr_ctx_dev_open(struct net_device *dev)
+{
+	netif_start_queue(dev);
+	return 0;
+}
+
+/*
+ * nss_dtlsmgr_ctx_dev_free()
+ *	Free an existing DTLS context device.
+ */
+static void nss_dtlsmgr_ctx_dev_free(struct net_device *dev)
+{
+	nss_dtlsmgr_trace("%p: free dtls context device(%s)", dev, dev->name);
+	free_netdev(dev);
+}
+
+/*
+ * nss_dtlsmgr_ctx_dev_stats64()
+ *	Report packet statistics to Linux.
+ */
+static struct rtnl_link_stats64 *nss_dtlsmgr_ctx_dev_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+	struct nss_dtlsmgr_ctx *ctx = netdev_priv(dev);
+	struct nss_dtlsmgr_stats *encap_stats, *decap_stats;
+
+	encap_stats = &ctx->encap.stats;
+	decap_stats = &ctx->decap.stats;
+
+	stats->rx_packets = decap_stats->rx_packets;
+	stats->rx_bytes = decap_stats->rx_bytes;
+	stats->rx_dropped = decap_stats->rx_dropped;
+
+	stats->tx_bytes = encap_stats->tx_bytes;
+	stats->tx_packets = encap_stats->tx_packets;
+	stats->tx_dropped = encap_stats->fail_headroom + encap_stats->fail_tailroom;
+
+	return stats;
+}
+
+/*
+ * nss_dtlsmgr_ctx_dev_change_mtu()
+ *	Change MTU size of DTLS context device.
+ */
+static int32_t nss_dtlsmgr_ctx_dev_change_mtu(struct net_device *dev, int32_t mtu)
+{
+	dev->mtu = mtu;
+	return 0;
+}
+
+/*
+ * DTLS netdev ops
+ */
+static const struct net_device_ops nss_dtlsmgr_ctx_dev_ops = {
+	.ndo_start_xmit = nss_dtlsmgr_ctx_dev_tx,
+	.ndo_open = nss_dtlsmgr_ctx_dev_open,
+	.ndo_stop = nss_dtlsmgr_ctx_dev_close,
+	.ndo_get_stats64 = nss_dtlsmgr_ctx_dev_stats64,
+	.ndo_change_mtu = nss_dtlsmgr_ctx_dev_change_mtu,
+};
+
+/*
+ * nss_dtlsmgr_ctx_dev_setup()
+ *	Setup the DTLS network device.
+ */
+void nss_dtlsmgr_ctx_dev_setup(struct net_device *dev)
+{
+	dev->addr_len = ETH_ALEN;
+	dev->mtu = ETH_DATA_LEN;
+	dev->hard_header_len = 0;
+	dev->needed_headroom = 0;
+	dev->needed_tailroom = 0;
+
+	dev->type = ARPHRD_TUNNEL;
+	dev->ethtool_ops = NULL;
+	dev->header_ops = NULL;
+	dev->netdev_ops = &nss_dtlsmgr_ctx_dev_ops;
+	dev->destructor = nss_dtlsmgr_ctx_dev_free;
+
+	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);
+}
diff --git a/dtls/v2.0/nss_dtlsmgr_ctx_stats.c b/dtls/v2.0/nss_dtlsmgr_ctx_stats.c
new file mode 100644
index 0000000..46db03d
--- /dev/null
+++ b/dtls/v2.0/nss_dtlsmgr_ctx_stats.c
@@ -0,0 +1,228 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017, 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_ctx_stats.c
+ *	NSS DTLS Manager context statistics
+ */
+
+#include <linux/atomic.h>
+#include <linux/crypto.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include <nss_api_if.h>
+#include <nss_dtlsmgr.h>
+
+#include "nss_dtlsmgr_private.h"
+
+#define NSS_DTLSMGR_STATS_MAX_STR_LENGTH 64
+#define NSS_DTLSMGR_STATS_EXTRA_LINES 16
+
+extern struct nss_dtlsmgr g_dtls;
+
+/*
+ * nss_dtlsmgr_ctx_fill_hw_error_stats()
+ *	Fill hardware error statistics
+ */
+static ssize_t nss_dtlsmgr_ctx_fill_hw_error_stats(struct nss_dtlsmgr_stats *stats, char *buf,
+						   ssize_t max_buf_len, ssize_t len)
+{
+	int i;
+
+	len += snprintf(buf + len, max_buf_len, "\nHardware Errors\n---------------\n");
+	len += snprintf(buf + len, max_buf_len, "length_error        - %lld\n", stats->fail_hw.len_error);
+	len += snprintf(buf + len, max_buf_len, "token_error         - %lld\n", stats->fail_hw.token_error);
+	len += snprintf(buf + len, max_buf_len, "bypass_error        - %lld\n", stats->fail_hw.bypass_error);
+	len += snprintf(buf + len, max_buf_len, "config_error        - %lld\n", stats->fail_hw.config_error);
+	len += snprintf(buf + len, max_buf_len, "algo_error          - %lld\n", stats->fail_hw.algo_error);
+	len += snprintf(buf + len, max_buf_len, "hash_ovf_error      - %lld\n", stats->fail_hw.hash_ovf_error);
+	len += snprintf(buf + len, max_buf_len, "ttl_error           - %lld\n", stats->fail_hw.ttl_error);
+	len += snprintf(buf + len, max_buf_len, "csum_error          - %lld\n", stats->fail_hw.csum_error);
+	len += snprintf(buf + len, max_buf_len, "timeout_error       - %lld\n", stats->fail_hw.timeout_error);
+
+	len += snprintf(buf + len, max_buf_len, "\nClassifcation Errors\n---------------------\n");
+	for (i = 0; i < NSS_DTLS_CMN_CLE_MAX; i++) {
+		/*
+		 * Don't print if there are no errors
+		 */
+		if (!stats->fail_cle[i])
+			continue;
+		len += snprintf(buf + len, max_buf_len, "cle_error_%02d   - %lld\n", i, stats->fail_cle[i]);
+	}
+
+	return len;
+}
+
+/*
+ * nss_dtlsmgr_ctx_encap_stats_read()
+ *	Read the DTLS encapsulation statistics.
+ */
+static ssize_t nss_dtlsmgr_ctx_encap_stats_read(struct file *filep, char __user *buffer, size_t count, loff_t *ppos)
+{
+	struct nss_dtlsmgr_ctx *ctx = filep->private_data;
+	struct nss_dtlsmgr_stats *stats;
+	ssize_t max_buf_len, len, ret;
+	char *buf;
+
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+
+	/*
+	 * (Lines of output) * (Max string length)
+	 */
+	max_buf_len = ((sizeof(*stats) / sizeof(uint64_t)) + NSS_DTLSMGR_STATS_EXTRA_LINES) *
+		      NSS_DTLSMGR_STATS_MAX_STR_LENGTH;
+
+	buf = vzalloc(max_buf_len);
+	if (!buf) {
+		nss_dtlsmgr_warn("Failed to allocate memory for statistic buffer");
+		return 0;
+	}
+
+	/*
+	 * Fill encap statistics
+	 */
+	stats = &ctx->encap.stats;
+	len = snprintf(buf, max_buf_len, "ENCAPSULATION INTERFACE (%d) STATISTICS\n", ctx->encap.ifnum);
+	len += snprintf(buf + len, max_buf_len - len, "tx_packets           - %lld\n", stats->tx_packets);
+	len += snprintf(buf + len, max_buf_len - len, "tx_bytes             - %lld\n", stats->tx_bytes);
+	len += snprintf(buf + len, max_buf_len - len, "fail_crypto_resource - %lld\n", stats->fail_crypto_resource);
+	len += snprintf(buf + len, max_buf_len - len, "fail_crypto_enqueue  - %lld\n", stats->fail_crypto_enqueue);
+	len += snprintf(buf + len, max_buf_len - len, "fail_headroom        - %lld\n", stats->fail_headroom);
+	len += snprintf(buf + len, max_buf_len - len, "fail_tailroom        - %lld\n", stats->fail_tailroom);
+	len += snprintf(buf + len, max_buf_len - len, "fail_queue           - %lld\n", stats->fail_queue);
+	len += snprintf(buf + len, max_buf_len - len, "fail_queue_nexthop   - %lld\n", stats->fail_queue_nexthop);
+	len += snprintf(buf + len, max_buf_len - len, "fail_pbuf_alloc      - %lld\n", stats->fail_pbuf_alloc);
+	len += snprintf(buf + len, max_buf_len - len, "fail_pbuf_linear     - %lld\n", stats->fail_pbuf_linear);
+	len += snprintf(buf + len, max_buf_len - len, "fail_pbuf_stats      - %lld\n", stats->fail_pbuf_stats);
+	len += snprintf(buf + len, max_buf_len - len, "fail_pbuf_align      - %lld\n", stats->fail_pbuf_align);
+	len += snprintf(buf + len, max_buf_len - len, "fail_ctx_active      - %lld\n", stats->fail_ctx_active);
+	len += snprintf(buf + len, max_buf_len - len, "fail_hwctx_active    - %lld\n", stats->fail_hwctx_active);
+	len += snprintf(buf + len, max_buf_len - len, "fail_cipher          - %lld\n", stats->fail_cipher);
+	len += snprintf(buf + len, max_buf_len - len, "fail_auth            - %lld\n", stats->fail_auth);
+	len += snprintf(buf + len, max_buf_len - len, "fail_seq_overflow    - %lld\n", stats->fail_seq_ovf);
+
+	/* Returns total number of bytes written to the buffer */
+	len = nss_dtlsmgr_ctx_fill_hw_error_stats(stats, buf, max_buf_len, len);
+
+	ret = simple_read_from_buffer(buffer, count, ppos, buf, len);
+	vfree(buf);
+
+	return ret;
+}
+/*
+ * nss_dtlsmgr_ctx_decap_stats_read()
+ *	Read the DTLS decapsulation statistics.
+ */
+static ssize_t nss_dtlsmgr_ctx_decap_stats_read(struct file *filep, char __user *buffer, size_t count, loff_t *ppos)
+{
+	struct nss_dtlsmgr_ctx *ctx = filep->private_data;
+	struct nss_dtlsmgr_stats *stats;
+	ssize_t max_buf_len, len, ret;
+	char *buf;
+
+	NSS_DTLSMGR_VERIFY_MAGIC(ctx);
+
+	/*
+	 * (Lines of output) * (Max string length)
+	 */
+	max_buf_len = ((sizeof(*stats) / sizeof(uint64_t)) + NSS_DTLSMGR_STATS_EXTRA_LINES) *
+		      NSS_DTLSMGR_STATS_MAX_STR_LENGTH;
+
+	buf = vzalloc(max_buf_len);
+	if (!buf) {
+		nss_dtlsmgr_warn("Failed to allocate memory for statistic buffer");
+		return 0;
+	}
+
+	/*
+	 * Fill decap statistics
+	 */
+	stats = &ctx->decap.stats;
+	len += snprintf(buf, max_buf_len - len, "DECAPSULATION INTERFACE (%d) STATISTICS\n", ctx->decap.ifnum);
+	len += snprintf(buf + len, max_buf_len - len, "rx_packets           - %lld\n", stats->rx_packets);
+	len += snprintf(buf + len, max_buf_len - len, "rx_bytes             - %lld\n", stats->rx_bytes);
+	len += snprintf(buf + len, max_buf_len - len, "rx_dropped           - %lld\n", stats->rx_dropped);
+	len += snprintf(buf + len, max_buf_len - len, "rx_single_rec        - %lld\n", stats->rx_single_rec);
+	len += snprintf(buf + len, max_buf_len - len, "rx_multi_rec         - %lld\n", stats->rx_multi_rec);
+	len += snprintf(buf + len, max_buf_len - len, "fail_crypto_resource - %lld\n", stats->fail_crypto_resource);
+	len += snprintf(buf + len, max_buf_len - len, "fail_crypto_enqueue  - %lld\n", stats->fail_crypto_enqueue);
+	len += snprintf(buf + len, max_buf_len - len, "fail_version         - %lld\n", stats->fail_ver);
+	len += snprintf(buf + len, max_buf_len - len, "fail_epoch           - %lld\n", stats->fail_epoch);
+	len += snprintf(buf + len, max_buf_len - len, "fail_dtls_record     - %lld\n", stats->fail_dtls_record);
+	len += snprintf(buf + len, max_buf_len - len, "fail_capwap          - %lld\n", stats->fail_capwap);
+	len += snprintf(buf + len, max_buf_len - len, "fail_replay          - %lld\n", stats->fail_replay);
+	len += snprintf(buf + len, max_buf_len - len, "fail_replay_dup      - %lld\n", stats->fail_replay_dup);
+	len += snprintf(buf + len, max_buf_len - len, "fail_replay_window   - %lld\n", stats->fail_replay_win);
+	len += snprintf(buf + len, max_buf_len - len, "fail_queue           - %lld\n", stats->fail_queue);
+	len += snprintf(buf + len, max_buf_len - len, "fail_queue_nexthop   - %lld\n", stats->fail_queue_nexthop);
+	len += snprintf(buf + len, max_buf_len - len, "fail_pbuf_alloc      - %lld\n", stats->fail_pbuf_alloc);
+	len += snprintf(buf + len, max_buf_len - len, "fail_pbuf_linear     - %lld\n", stats->fail_pbuf_linear);
+	len += snprintf(buf + len, max_buf_len - len, "fail_pbuf_stats      - %lld\n", stats->fail_pbuf_stats);
+	len += snprintf(buf + len, max_buf_len - len, "fail_pbuf_align      - %lld\n", stats->fail_pbuf_align);
+	len += snprintf(buf + len, max_buf_len - len, "fail_ctx_active      - %lld\n", stats->fail_ctx_active);
+	len += snprintf(buf + len, max_buf_len - len, "fail_hwctx_active    - %lld\n", stats->fail_hwctx_active);
+	len += snprintf(buf + len, max_buf_len - len, "fail_cipher          - %lld\n", stats->fail_cipher);
+	len += snprintf(buf + len, max_buf_len - len, "fail_auth            - %lld\n", stats->fail_auth);
+	len += snprintf(buf + len, max_buf_len - len, "fail_seq_overflow    - %lld\n", stats->fail_seq_ovf);
+	len += snprintf(buf + len, max_buf_len - len, "fail_block_length    - %lld\n", stats->fail_blk_len);
+	len += snprintf(buf + len, max_buf_len - len, "fail_hash_length     - %lld\n", stats->fail_hash_len);
+
+	/* Returns total number of bytes written to the buffer */
+	len = nss_dtlsmgr_ctx_fill_hw_error_stats(stats, buf, max_buf_len, len);
+
+	ret = simple_read_from_buffer(buffer, count, ppos, buf, len);
+	vfree(buf);
+
+	return ret;
+}
+
+/*
+ * Context file operation structure instance
+ */
+static const struct file_operations nss_dtlsmgr_encap_stats_op = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = nss_dtlsmgr_ctx_encap_stats_read,
+};
+
+static const struct file_operations nss_dtlsmgr_decap_stats_op = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = nss_dtlsmgr_ctx_decap_stats_read,
+};
+
+/*
+ * nss_dtlmsgr_create_debugfs()
+ *	Create debugfs files to display session statistics.
+ */
+int nss_dtlsmgr_create_debugfs(struct nss_dtlsmgr_ctx *ctx)
+{
+	struct nss_dtlsmgr *drv = &g_dtls;
+
+	ctx->dentry = debugfs_create_dir(ctx->dev->name, drv->root_dir);
+	if (!ctx->dentry) {
+		nss_dtlsmgr_warn("failed to create debugfs directory");
+		return -1;
+	}
+
+	debugfs_create_file("encap_stats", S_IRUGO, ctx->dentry, ctx, &nss_dtlsmgr_encap_stats_op);
+	debugfs_create_file("decap_stats", S_IRUGO, ctx->dentry, ctx, &nss_dtlsmgr_decap_stats_op);
+	return 0;
+}
diff --git a/dtls/v2.0/nss_dtlsmgr_private.h b/dtls/v2.0/nss_dtlsmgr_private.h
new file mode 100644
index 0000000..6aab8a2
--- /dev/null
+++ b/dtls/v2.0/nss_dtlsmgr_private.h
@@ -0,0 +1,194 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017, 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_private.h
+ */
+
+#ifndef __NSS_DTLSMGR_PRIVATE_H_
+#define __NSS_DTLSMGR_PRIVATE_H_
+
+#define NSS_DTLSMGR_DEBUG_LEVEL_ERROR 1
+#define NSS_DTLSMGR_DEBUG_LEVEL_WARN 2
+#define NSS_DTLSMGR_DEBUG_LEVEL_INFO 3
+#define NSS_DTLSMGR_DEBUG_LEVEL_TRACE 4
+
+#define nss_dtlsmgr_error(s, ...) do {	\
+	if (net_ratelimit()) {	\
+		pr_alert("%s[%d]:" s "\n", __func__, __LINE__, ##__VA_ARGS__);	\
+	}	\
+} while (0)
+
+#if defined(CONFIG_DYNAMIC_DEBUG)
+/*
+ * Compile messages for dynamic enable/disable
+ */
+#define nss_dtlsmgr_warn(s, ...) pr_debug("%s[%d]:" s "\n", __func__, __LINE__, ##__VA_ARGS__)
+#define nss_dtlsmgr_info(s, ...) pr_debug("%s[%d]:" s "\n", __func__, __LINE__, ##__VA_ARGS__)
+#define nss_dtlsmgr_trace(s, ...) pr_debug("%s[%d]:" s "\n", __func__, __LINE__, ##__VA_ARGS__)
+#else
+
+/*
+ * Statically compile messages at different levels
+ */
+#define nss_dtlsmgr_warn(s, ...) {	\
+	if (NSS_DTLSMGR_DEBUG_LEVEL > NSS_DTLSMGR_DEBUG_LEVEL_ERROR)	\
+		pr_warn("%s[%d]:" s "\n", __func__, __LINE__, ##__VA_ARGS__)	\
+}
+
+#define nss_dtlsmgr_info(s, ...) {	\
+	if (NSS_DTLSMGR_DEBUG_LEVEL > NSS_DTLSMGR_DEBUG_LEVEL_WARN)	\
+		pr_notice("%s[%d]:" s "\n", __func__, __LINE__, ##__VA_ARGS__)	\
+}
+
+#define nss_dtlsmgr_trace(s, ...) {	\
+	if (NSS_DTLSMGR_DEBUG_LEVEL > NSS_DTLSMGR_DEBUG_LEVEL_INFO)	\
+		pr_info("%s[%d]:" s "\n", __func__, __LINE__, ##__VA_ARGS__)	\
+}
+
+#endif /* CONFIG_DYNAMIC_DEBUG */
+
+#define NSS_DTLSMGR_DTLS_HDR_SZ 13			/* DTLS header length */
+#define NSS_DTLSMGR_CAPWAP_DTLS_HDR_SZ 4		/* CAPWAP-DTLS header length */
+#define NSS_DTLSMGR_CTX_MAGIC 0x5d7eb219		/* DTLS context 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
+
+#if defined (NSS_DTLSMGR_DEBUG)
+#define NSS_DTLSMGR_VERIFY_MAGIC(ctx) do { \
+	struct nss_dtlsmgr_ctx *__ctx = (ctx);	\
+	BUG_ON(__ctx->magic != NSS_DTLSMGR_CTX_MAGIC);	\
+} while(0)
+
+#define NSS_DTLSMGR_SET_MAGIC(ctx, magic) do {	\
+	struct nss_dtlsmgr_ctx *__ctx = (ctx);	\
+	__ctx->magic = magic;	\
+} while(0)
+#else
+#define NSS_DTLSMGR_VERIFY_MAGIC(ctx)
+#define NSS_DTLSMGR_SET_MAGIC(ctx, magic)
+#endif
+
+/*
+ * DTLS algorithm infomation
+ */
+struct nss_dtlsmgr_algo_info {
+	const char name[CRYPTO_MAX_ALG_NAME];	/**< Cryptographic algorithm name. */
+	uint16_t max_cipher_keylen;		/**< Cipher key length. */
+	uint16_t max_auth_keylen;		/**< Authentication key length. */
+	uint16_t max_nonce_size;		/**< Nonce size. */
+};
+
+/*
+ * DTLS flow information
+ */
+struct nss_dtlsmgr_flow_data {
+	uint32_t sip[4];			/**< Source IPv4/v6 address. */
+	uint32_t dip[4];			/**< Destination IPv4/v6 address. */
+	uint32_t flags;				/**< Transformation flags. */
+
+	uint16_t sport;				/**< Source UDP/UPDLite port. */
+	uint16_t dport;				/**< Destination UDP/UDPLite port. */
+
+	uint8_t dscp;				/**< Dscp value incase of static. */
+	uint8_t hop_limit_ttl;			/**< Hop limit or time to live. */
+	bool dscp_copy;				/**< Copy dscp. */
+	bool df;				/**< Do not fragment settings. */
+};
+
+/*
+ * DTLS configuration data
+ */
+struct nss_dtlsmgr_dtls_data {
+	struct list_head list;			/**< List of crypto data. */
+	struct crypto_aead *aead;		/**< Linux AEAD context. */
+	uint32_t crypto_idx;
+	uint32_t ver;				/**< DTLS version. */
+
+	uint16_t window_size;			/**< DTLS anti-replay window. */
+	uint16_t epoch;				/**< Current epoch. */
+
+	uint8_t blk_len;			/**< Cipher block length. */
+	uint8_t hash_len;			/**< Hash length. */
+	uint8_t iv_len;				/**< IV length. */
+	uint8_t res1;
+};
+
+/*
+ * DTLS context data
+ */
+struct nss_dtlsmgr_ctx_data {
+	struct nss_dtlsmgr_stats stats;			/**< Statistics. */
+	struct nss_dtlsmgr_flow_data flow;		/**< Flow data information. */
+	struct nss_ctx_instance *nss_ctx;		/**< NSS context handle. */
+	struct list_head dtls_active;			/**< List of active DTLS record(s). */
+
+	uint32_t headroom;				/**< Headroom needed. */
+	uint32_t tailroom;				/**< Tailroom needed. */
+	uint32_t ifnum;					/**< NSS interface number. */
+	uint32_t src_ifnum;				/**< Source interface number for NSS. */
+	uint32_t dest_ifnum;				/**< Destination interface number for NSS. */
+	uint32_t flags;					/**< DTLS flags. */
+	uint32_t di_type;				/**< Dynamic interface type. */
+	nss_dtlsmgr_stats_notify_method_t notify;	/**< Stats notification callback. */
+};
+
+/*
+ * DTLS manager context
+ */
+struct nss_dtlsmgr_ctx {
+	rwlock_t lock;					/**< Context lock. */
+	struct net_device *dev;				/**< Session netdevice. */
+	struct dentry *dentry;				/**< Debugfs directory for ctx statistics. */
+	struct nss_dtlsmgr_ctx_data encap;		/**< Encapsulation data. */
+	struct nss_dtlsmgr_ctx_data decap;		/**< Decapsulation data. */
+
+#if defined (NSS_DTLSMGR_DEBUG)
+	uint32_t magic;					/**< Magic check. */
+#endif
+};
+
+/*
+ * DTLS manager data
+ */
+struct nss_dtlsmgr {
+	atomic_t is_configured;				/**< Firmware is configured. */
+	struct dentry *root_dir;			/**< Debugfs root directory. */
+	struct nss_ctx_instance *nss_ctx;		/**< NSS data/message handle. */
+};
+
+extern struct nss_dtlsmgr g_dtls;
+
+extern void nss_dtlsmgr_ctx_dev_event(void *if_ctx, struct nss_cmn_msg *ndcm);
+extern void nss_dtlsmgr_ctx_dev_rx(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi);
+extern void nss_dtlsmgr_ctx_dev_setup(struct net_device *dev);
+extern int nss_dtlsmgr_create_debugfs(struct nss_dtlsmgr_ctx *ctx);
+#endif /* !__NSS_DTLSMGR_PRIVATE_H_ */
diff --git a/exports/nss_dtlsmgr.h b/exports/nss_dtlsmgr.h
index 418c4d2..6793add 100644
--- a/exports/nss_dtlsmgr.h
+++ b/exports/nss_dtlsmgr.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 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.
@@ -22,247 +22,245 @@
 #define _NSS_DTLSMGR_H_
 
 /**
- * @brief NSS DTLS manager status
+ * NSS DTLS manager flags
+ */
+#define NSS_DTLSMGR_HDR_IPV6 0x0001			/**< L3 header is v6 or v4 */
+#define NSS_DTLSMGR_HDR_UDPLITE 0x0002			/**< L4 header is UDP-Lite or UDP */
+#define NSS_DTLSMGR_HDR_CAPWAP 0x0004			/**< CAPWAP-DTLS or DTLS header */
+#define NSS_DTLSMGR_CIPHER_MODE_GCM 0x0008		/**< Cipher mode is GCM */
+#define NSS_DTLSMGR_OUTER_UDPLITE_CSUM 0x00010000	/**< checksum UDP-Lite header */
+#define NSS_DTLSMGR_INNER_ACCEPT_ALL 0x00020000		/**< Send all error packets after DECAP */
+
+/**
+ * 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_OK,			/**< Status ok */
+	NSS_DTLSMGR_FAIL,		/**< Failed due to unknown reason */
+	NSS_DTLSMGR_FAIL_NOMEM,		/**< Failed to allocate memory */
+	NSS_DTLSMGR_FAIL_NOCRYPTO,	/**< Failed to allocate crypto resource */
+	NSS_DTLSMGR_FAIL_MESSAGE,	/**< Failed to message the NSS */
 	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_INVALID_ALGO,	/**< Invalid algorithm */
+	NSS_DTLSMGR_INVALID_KEYLEN,	/**< Invalid key length for cipher/auth */
 } nss_dtlsmgr_status_t;
 
 /**
- * @brief DTLS Version
+ * DTLS protocol 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 */
+	NSS_DTLSMGR_VERSION_1_0,	/**< Protocol v1.0 */
+	NSS_DTLSMGR_VERSION_1_2,	/**< Protocol v1.2 */
 };
 
 /**
- * @brief NSS DTLS manager flags
+ * NSS DTLS manager supported cryptographic algorithms
  */
-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 */
+enum nss_dtlsmgr_algo {
+	NSS_DTLSMGR_ALGO_AES_CBC_SHA1_HMAC,	/**< AES_CBC_SHA1_HMAC */
+	NSS_DTLSMGR_ALGO_AES_CBC_SHA256_HMAC,	/**< AES_CBC_SHA256_HMAC */
+	NSS_DTLSMGR_ALGO_3DES_CBC_SHA1_HMAC,	/**< 3DES_CBC_SHA1_HMAC */
+	NSS_DTLSMGR_ALGO_3DES_CBC_SHA256_HMAC,	/**< 3DES_CBC_SHA256_HMAC */
+	NSS_DTLSMGR_ALGO_MAX
 };
 
 /**
- * @brief IPv4/IPv6 address
+ * NSS DTLS manager cryptographic structure to represent key and its length.
  */
-union nss_dtlsmgr_ip {
-	uint32_t ipv4;			/**< IPv4 address */
-	uint32_t ipv6[4];		/**< IPv6 address */
+struct nss_dtlsmgr_crypto_data {
+	const uint8_t *data;		/**< Pointer to key or nonce */
+	uint16_t len;			/**< Length of the key */
 };
 
 /**
- * @brief NSS DTLS session encap data
+ * NSS DTLS manager cryptographic data
+ */
+struct nss_dtlsmgr_crypto {
+	enum nss_dtlsmgr_algo algo;			/**< DTLS manager cryptographic algorithm */
+	struct nss_dtlsmgr_crypto_data cipher_key;	/**< Cipher key */
+	struct nss_dtlsmgr_crypto_data auth_key;	/**< Authentication key */
+	struct nss_dtlsmgr_crypto_data nonce;		/**< Nonce */
+};
+
+/**
+ * NSS DTLS manager session encapsulation 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 */
+	struct nss_dtlsmgr_crypto crypto;	/**< Encapsulation crypto configuration */
+	enum nss_dtlsmgr_dtlsver ver;		/**< Version used in DTLS header */
+	uint32_t sip[4];			/**< Source IP address */
+	uint32_t dip[4];			/**< Destination IP address */
+	uint16_t sport;				/**< Source UDP port */
+	uint16_t dport;				/**< Destination UDP port */
+	uint16_t epoch;				/**< Epoch */
+	uint8_t ip_ttl;				/**< IP time to live */
+	uint8_t dscp;				/**< DSCP */
+	bool dscp_copy;				/**< Flag to check if DSCP needs to be copied */
+	bool df;				/**< Flag to check fragmentation */
 };
 
 /**
- * @brief NSS DTLS session decap data
+ * NSS DTLS manager session decapsulation 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 */
+	struct nss_dtlsmgr_crypto crypto;	/**< Decap Crypto configuration */
+	uint32_t nexthop_ifnum;			/**< NSS I/F number to forward after de-capsulation */
+	uint16_t window_size;			/**< Anti-Replay window size */
+};
+
+/*
+ * NSS DTLS manager hardware statistics
+ */
+struct nss_dtlsmgr_hw_stats {
+	uint64_t len_error;             /**< Length error */
+	uint64_t token_error;           /**< Token error, unknown token command/instruction */
+	uint64_t bypass_error;          /**< Token contains too much bypass data */
+	uint64_t config_error;          /**< Invalid command/algorithm/mode/combination */
+	uint64_t algo_error;            /**< Unsupported algorithm */
+	uint64_t hash_ovf_error;        /**< Hash input overflow */
+	uint64_t ttl_error;             /**< TTL or HOP-Limit underflow */
+	uint64_t csum_error;            /**< Checksum error */
+	uint64_t timeout_error;         /**< Data timed-out */
 };
 
 /**
- * @brief NSS DTLS session create return parameters
+ * NSS DTLS manager session statistics
  */
-struct nss_dtlsmgr_return_data {
-	uint32_t dtls_if;		/**< NSS I/F number of DTLS session */
-	uint32_t mtu_adjust;		/**< MTU adjustment */
+struct nss_dtlsmgr_stats {
+	uint64_t tx_packets;		/**< Tx packets. */
+	uint64_t tx_bytes;		/**< Tx bytes. */
+	uint64_t rx_packets;		/**< Rx packets. */
+	uint64_t rx_bytes;		/**< Rx bytes. */
+	uint64_t rx_dropped;		/**< Rx drops. */
+	uint64_t rx_single_rec;		/**< Received single DTLS record datagrams. */
+	uint64_t rx_multi_rec;		/**< Received multiple DTLS record datagrams. */
+	uint64_t fail_crypto_resource;	/**< Failure in allocation of crypto resource. */
+	uint64_t fail_crypto_enqueue;	/**< Failure due to queue full in crypto or hardware. */
+	uint64_t fail_headroom;		/**< Failure in headroom check. */
+	uint64_t fail_tailroom;		/**< Failure in tailroom check. */
+	uint64_t fail_ver;		/**< Failure in DTLS version check. */
+	uint64_t fail_epoch;		/**< Failure in DTLS epoch check. */
+	uint64_t fail_dtls_record;	/**< Failure in reading DTLS record. */
+	uint64_t fail_capwap;		/**< Failure in Capwap classification. */
+	uint64_t fail_replay;		/**< Failure in anti-replay check. */
+	uint64_t fail_replay_dup;	/**< Failure in anti-replay; duplicate records. */
+	uint64_t fail_replay_win;	/**< Failure in anti-replay; packet outside the window. */
+	uint64_t fail_queue;		/**< Failure due to queue full in DTLS. */
+	uint64_t fail_queue_nexthop;	/**< Failure due to queue full in next_hop. */
+	uint64_t fail_pbuf_alloc;	/**< Failure in pbuf allocation. */
+	uint64_t fail_pbuf_linear;	/**< Failure in pbuf linearization. */
+	uint64_t fail_pbuf_stats;	/**< Failure in pbuf allocation for stats. */
+	uint64_t fail_pbuf_align;	/**< Failure in pbuf alignment. */
+	uint64_t fail_ctx_active;	/**< Failure in enqueue due to no active context. */
+	uint64_t fail_hwctx_active;	/**< Failure in enqueue due to no active HW context. */
+	uint64_t fail_cipher;		/**< Failure in decrypting the data. */
+	uint64_t fail_auth;		/**< Failure in authenticating the data. */
+	uint64_t fail_seq_ovf;		/**< Failure due to sequence number overflow. */
+	uint64_t fail_blk_len;		/**< Failure in decapsulation due to bad cipher block length. */
+	uint64_t fail_hash_len;		/**< Failure in decapsulation due to bad hash block length. */
+
+	struct nss_dtlsmgr_hw_stats fail_hw;		/**< Hardware failure statistics. */
+
+	uint64_t fail_cle[NSS_DTLS_CMN_CLE_MAX];	/**< Classification errors */
+
+	uint32_t seq_low;		/**< Lower 32 bits of current Tx sequence number. */
+	uint32_t seq_high;		/**< Upper 16 bits of current Tx sequence number. */
+
+	uint16_t epoch;			/**< Current Epoch value. */
 };
 
 /**
- * NSS DTLS session stats update
+ * NSS DTLS manager session stats update callback
  */
-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 */
+typedef void (*nss_dtlsmgr_stats_notify_method_t)(struct net_device *dev, struct nss_dtlsmgr_stats *stats, bool encap);
+
+/**
+ * NSS DTLS manager session definition
+ */
+struct nss_dtlsmgr_config {
+	uint32_t flags;					/**< DTLS header flags */
+	nss_dtlsmgr_stats_notify_method_t notify;	/**< Stats update callback */
+	struct nss_dtlsmgr_encap_config encap;		/**< Encap data */
+	struct nss_dtlsmgr_decap_config decap;		/**< Decap data */
 };
 
 /**
- * NSS DTLS session stats update callback
+ * NSS DTLS manager session tx/rx cipher update parameters
  */
-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 */
+struct nss_dtlsmgr_config_update {
+	struct nss_dtlsmgr_crypto crypto;	/**< Crypto algorithm and key data */
 	uint16_t epoch;				/**< Epoch */
+	uint16_t window_size;			/**< Anti-Replay window size */
 };
 
 /**
- * @brief Create a NSS DTLS session and associated crypto sessions
+ * nss_dtlsmgr_session_create
+ *	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
+ * @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);
+struct net_device *nss_dtlsmgr_session_create(struct nss_dtlsmgr_config *cfg);
 
 /**
- * @brief Destroy a NSS DTLS session and associated crypto sessions
+ * nss_dtlsmgr_session_destroy
+ *	Destroy a NSS DTLS session and associated crypto sessions
  *
  * @param dtls_if[IN] NSS DTLS I/F
  *
- * @return NSS_DTLSMGR_OK for success
+ * @return
+ * NSS_DTLSMGR_OK for success
  */
-nss_dtlsmgr_status_t nss_dtlsmgr_session_destroy(uint32_t dtls_if);
+nss_dtlsmgr_status_t nss_dtlsmgr_session_destroy(struct net_device *dev);
 
 /**
- * @brief Update pending Rx cipher state of a DTLS session
+ * nss_dtlsmgr_session_update_encap
+ *	Update encapsulation cipher state of a DTLS session.
+ *	Configures new parameters into the pending encapsulation cipher
+ *	state of a DTLS session. This has no effect on the current
+ *	cipher state and its processing of packets.
  *
- * @param dtls_if[IN] NSS DTLS I/F
- * @param udata[IN] DTLS session update parameters
+ * @param dev[IN] DTLS network device
+ * @param cfg[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);
+nss_dtlsmgr_status_t nss_dtlsmgr_session_update_encap(struct net_device *dev, struct nss_dtlsmgr_config_update *cfg);
 
 /**
- * @brief Update pending Tx cipher state of a DTLS session
+ * nss_dtlsmgr_session_update_decap
+ *	Update decapsulation cipher state of a DTLS session.
+ *	Configures new parameters into the pending decapsulation cipher
+ *	state of a DTLS session. This has no effect on the current
+ *	cipher state and its processing of packets.
  *
- * @param dtls_if[IN] NSS DTLS I/F
- * @param udata[IN] DTLS session update parameters
+ * @param dev[IN] DTLS network device
+ * @param cfg[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);
+nss_dtlsmgr_status_t nss_dtlsmgr_session_update_decap(struct net_device *dev, struct nss_dtlsmgr_config_update *cfg);
 
 /**
- * @brief Switch Rx to new cipher state
+ * nss_dtlsmgr_session_switch_encap
+ *	Switch DTLS session from current to new for encapsulation
  *
- * @param dtls_if[IN] NSS DTLS I/F
+ * @param dev[in] DTLS network device
  *
- * @return NSS_DTLSMGR_OK for success
- *
- * Causes the Rx pending cipher state of a DTLS session
- * to become current effectively rekeying the Rx path.
+ * @return TRUE for success
  */
-nss_dtlsmgr_status_t nss_dtlsmgr_rekey_rx_cipher_switch(uint32_t dtls_if);
+bool nss_dtlsmgr_session_switch_encap(struct net_device *dev);
 
 /**
- * @brief Switch Tx to new cipher state
+ * nss_dtlsmgr_session_switch_decap
+ *	Switch DTLS session from current to new for de-capsulation
  *
- * @param dtls_if[IN] NSS DTLS I/F
+ * @param dev[in] DTLS network device
  *
- * @return NSS_DTLSMGR_OK for success
- *
- * Causes the Tx pending cipher state of a DTLS session
- * to become current effectively rekeying the Tx path.
+ * @return TRUE for success
  */
-nss_dtlsmgr_status_t nss_dtlsmgr_rekey_tx_cipher_switch(uint32_t dtls_if);
+bool nss_dtlsmgr_session_switch_decap(struct net_device *dev);
 #endif /* _NSS_DTLSMGR_H_ */