[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_ */