Merge "[qca-nss-drv] Create new DTLS framework"
diff --git a/Makefile b/Makefile
index 0f6f7a7..dc69777 100644
--- a/Makefile
+++ b/Makefile
@@ -14,8 +14,6 @@
nss_cmn.o \
nss_core.o \
nss_coredump.o \
- nss_dtls.o \
- nss_dtls_stats.o \
nss_dynamic_interface.o \
nss_edma.o \
nss_edma_stats.o \
@@ -97,6 +95,8 @@
ifeq ($(SoC),$(filter $(SoC),ipq806x ipq40xx))
qca-nss-drv-objs += nss_data_plane/nss_data_plane_gmac.o \
nss_hal/ipq806x/nss_hal_pvt.o \
+ nss_dtls.o \
+ nss_dtls_stats.o \
nss_crypto.o
ccflags-y += -I$(obj)/nss_hal/ipq806x -DNSS_HAL_IPQ806X_SUPPORT
endif
@@ -104,6 +104,7 @@
ifeq ($(SoC),$(filter $(SoC),ipq807x ipq807x_64))
qca-nss-drv-objs += nss_data_plane/nss_data_plane_edma.o \
nss_hal/ipq807x/nss_hal_pvt.o \
+ nss_dtls_cmn.o \
nss_crypto_cmn.o
ccflags-y += -I$(obj)/nss_hal/ipq807x -DNSS_HAL_IPQ807x_SUPPORT
endif
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index 74ec181..606f1dc 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -59,6 +59,7 @@
#include "nss_portid.h"
#include "nss_oam.h"
#include "nss_dtls.h"
+#include "nss_dtls_cmn.h"
#include "nss_edma.h"
#include "nss_bridge.h"
#include "nss_ppe.h"
diff --git a/exports/nss_dtls_cmn.h b/exports/nss_dtls_cmn.h
new file mode 100644
index 0000000..2285974
--- /dev/null
+++ b/exports/nss_dtls_cmn.h
@@ -0,0 +1,387 @@
+/*
+ **************************************************************************
+ * 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.
+ **************************************************************************
+ */
+
+/**
+ * @file nss_dtls_cmn.h
+ * NSS DTLS common interface definitions, supports inner/outer interface split.
+ */
+
+#ifndef _NSS_DTLS_CMN_H_
+#define _NSS_DTLS_CMN_H_
+
+/**
+ * @addtogroup nss_dtls_cmn_subsystem
+ * @{
+ */
+
+#define NSS_DTLS_CMN_CTX_HDR_IPV6 0x0001 /**< DTLS with IPv6. */
+#define NSS_DTLS_CMN_CTX_HDR_UDPLITE 0x0002 /**< DTLS with UDPLite. */
+#define NSS_DTLS_CMN_CTX_HDR_CAPWAP 0x0004 /**< DTLS with CAPWAP. */
+#define NSS_DTLS_CMN_CTX_CIPHER_MODE_GCM 0x0008 /**< DTLS with GCM cipher mode. */
+#define NSS_DTLS_CMN_CTX_OUTER_UDPLITE_CSUM 0x10000 /**< Checksum only UDPLite header. */
+#define NSS_DTLS_CMN_CTX_INNER_ACCEPT_ALL 0x20000
+#define NSS_DTLS_CMN_CLE_MAX 32 /**< Max classification error. */
+
+/**
+ * nss_dtls_cmn_metadata_types
+ * Message types for DTLS requests and responses.
+ */
+enum nss_dtls_cmn_msg_type {
+ NSS_DTLS_CMN_MSG_TYPE_CONFIGURE_NODE, /**< Configure DTLS firmware node. */
+ NSS_DTLS_CMN_MSG_TYPE_CONFIGURE_HDR, /**< Configure the base context parameter. */
+ NSS_DTLS_CMN_MSG_TYPE_CONFIGURE_DTLS, /**< Configure DTLS parameters. */
+ NSS_DTLS_CMN_MSG_TYPE_SWITCH_DTLS, /**< Switch to new DTLS transform. */
+ NSS_DTLS_CMN_MSG_TYPE_DECONFIGURE, /**< Deconfigure context. */
+ NSS_DTLS_CMN_MSG_TYPE_SYNC_STATS, /**< Synchronize statistics. */
+ NSS_DTLS_CMN_MSG_TYPE_NODE_STATS, /**< Node statistics. */
+ NSS_DTLS_CMN_MSG_MAX
+};
+
+/**
+ * nss_dtls_cmn_error_response_types
+ * Error types for DTLS responses.
+ */
+enum nss_dtls_cmn_error {
+ NSS_DTLS_CMN_ERROR_NONE = 0,
+ NSS_DTLS_CMN_ERROR_UNKNOWN_MSG,
+ NSS_DTLS_CMN_ERROR_INVALID_DESTIF,
+ NSS_DTLS_CMN_ERROR_INVALID_SRCIF,
+ NSS_DTLS_CMN_ERROR_INVALID_CRYPTO,
+ NSS_DTLS_CMN_ERROR_INVALID_VER,
+ NSS_DTLS_CMN_ERROR_INVALID_CTX_TYPE,
+ NSS_DTLS_CMN_ERROR_INVALID_CTX_WORDS,
+ NSS_DTLS_CMN_ERROR_FAIL_ALLOC_HWCTX,
+ NSS_DTLS_CMN_ERROR_FAIL_COPY_CTX,
+ NSS_DTLS_CMN_ERROR_FAIL_SWITCH_HWCTX,
+ NSS_DTLS_CMN_ERROR_ALREADY_CONFIGURED,
+ NSS_DTLS_CMN_ERROR_NOMEM,
+ NSS_DTLS_CMN_ERROR_MAX,
+};
+
+/**
+ * DTLS node statistics
+ */
+struct nss_dtls_cmn_node_stats {
+ uint32_t fail_ctx_alloc; /**< Failure in allocating a context. */
+ uint32_t fail_ctx_free; /**< Failure in freeing up the context. */
+ uint32_t fail_pbuf_stats; /**< Failure in pbuf allocation for statistics. */
+};
+
+/**
+ * DTLS hardware statistics
+ */
+struct nss_dtls_cmn_hw_stats {
+ uint32_t len_error; /**< Length error. */
+ uint32_t token_error; /**< Token error, unknown token command/instruction. */
+ uint32_t bypass_error; /**< Token contains too much bypass data. */
+ uint32_t config_error; /**< Invalid command/algorithm/mode/combination. */
+ uint32_t algo_error; /**< Unsupported algorithm. */
+ uint32_t hash_ovf_error; /**< Hash input overflow. */
+ uint32_t ttl_error; /**< TTL or HOP-Limit underflow. */
+ uint32_t csum_error; /**< Checksum error. */
+ uint32_t timeout_error; /**< Data timed-out. */
+};
+
+/**
+ * nss_dtls_cmn_ctx_stats
+ * DTLS session statistics.
+ */
+struct nss_dtls_cmn_ctx_stats {
+ struct nss_cmn_node_stats pkt; /**< Common node statistics. */
+ uint32_t rx_single_rec; /**< Received single DTLS record datagrams. */
+ uint32_t rx_multi_rec; /**< Received multiple DTLS record datagrams. */
+ uint32_t fail_crypto_resource; /**< Failure in allocation of crypto resource. */
+ uint32_t fail_crypto_enqueue; /**< Failure due to queue full in crypto or hardware. */
+ uint32_t fail_headroom; /**< Failure in headroom check. */
+ uint32_t fail_tailroom; /**< Failure in tailroom check. */
+ uint32_t fail_ver; /**< Failure in DTLS version check. */
+ uint32_t fail_epoch; /**< Failure in DTLS epoch check. */
+ uint32_t fail_dtls_record; /**< Failure in reading DTLS record. */
+ uint32_t fail_capwap; /**< Failure in CAPWAP classification. */
+ uint32_t fail_replay; /**< Failure in anti-replay check. */
+ uint32_t fail_replay_dup; /**< Failure in anti-replay; duplicate records. */
+ uint32_t fail_replay_win; /**< Failure in anti-replay; packet outside the window. */
+ uint32_t fail_queue; /**< Failure due to queue full in DTLS. */
+ uint32_t fail_queue_nexthop; /**< Failure due to queue full in next_hop. */
+ uint32_t fail_pbuf_alloc; /**< Failure in pbuf allocation. */
+ uint32_t fail_pbuf_linear; /**< Failure in pbuf linearization. */
+ uint32_t fail_pbuf_stats; /**< Failure in pbuf allocation for statistics. */
+ uint32_t fail_pbuf_align; /**< Failure in pbuf alignment. */
+ uint32_t fail_ctx_active; /**< Failure in enqueue due to inactive context. */
+ uint32_t fail_hwctx_active; /**< Failure in enqueue due to inactive hardware context. */
+ uint32_t fail_cipher; /**< Failure in decrypting the data. */
+ uint32_t fail_auth; /**< Failure in authenticating the data. */
+ uint32_t fail_seq_ovf; /**< Failure due to sequence number overflow. */
+ uint32_t fail_blk_len; /**< Failure in decapsulation due to bad cipher block length. */
+ uint32_t fail_hash_len; /**< Failure in decapsulation due to bad hash block length. */
+
+ struct nss_dtls_cmn_hw_stats fail_hw; /**< Hardware failure statistics. */
+
+ uint32_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. */
+ uint8_t res1[2]; /**< Reserved for future use. */
+
+ uint8_t res2[16]; /**< Reserved for future use. */
+};
+
+/**
+ * nss_dtls_cmn_ctx_config_hdr
+ * Parameters for outer header transform.
+ */
+struct nss_dtls_cmn_ctx_config_hdr {
+ uint32_t flags; /**< Context flags. */
+ uint32_t dest_ifnum; /**< Destination interface for packets. */
+ uint32_t src_ifnum; /**< Source interface of packets. */
+ uint32_t sip[4]; /**< Source IPv4/v6 address. */
+ uint32_t dip[4]; /**< Destination IPv4/v6 address. */
+
+ uint16_t sport; /**< Source UDP/UDPLite port. */
+ uint16_t dport; /**< Destination UDP/UDPLite port. */
+
+ uint8_t hop_limit_ttl; /**< IP header TTL field. */
+ uint8_t dscp; /**< DSCP value. */
+ uint8_t dscp_copy; /**< Copy DSCP value. */
+ uint8_t df; /**< Do not fragment DTLS over IPv4. */
+};
+
+/**
+ * nss_dtls_cmn_ctx_config_dtls
+ * Parameters for DTLS transform.
+ */
+struct nss_dtls_cmn_ctx_config_dtls {
+ uint32_t ver; /**< Version (enum dtls_cmn_ver). */
+ uint32_t crypto_idx; /**< Crypto index for cipher context. */
+
+ uint16_t window_size; /**< Anti-replay window size. */
+ uint16_t epoch; /**< Initial epoch value. */
+
+ uint8_t iv_len; /**< Crypto IV length for encapsulation. */
+ uint8_t hash_len; /**< Auth hash length for encapsulation. */
+ uint8_t blk_len; /**< Cipher block length. */
+ uint8_t res1; /**< Reserved for alignment. */
+};
+
+/**
+ * nss_dtls_cmn_msg
+ * Data for sending and receiving DTLS messages.
+ */
+struct nss_dtls_cmn_msg {
+ struct nss_cmn_msg cm; /**< Common message header. */
+
+ /**
+ * Payload of a DTLS message.
+ */
+ union {
+ struct nss_dtls_cmn_ctx_config_hdr hdr_cfg; /**< Session configuration. */
+ struct nss_dtls_cmn_ctx_config_dtls dtls_cfg; /**< Cipher update information. */
+ struct nss_dtls_cmn_ctx_stats stats; /**< Session statistics. */
+ struct nss_dtls_cmn_node_stats node_stats; /**< Node statistics. */
+ } msg; /**< Message payload for DTLS session messages exchanged with NSS core. */
+};
+
+/**
+ * Callback function for receiving DTLS messages.
+ *
+ * @datatypes
+ * nss_dtls_cmn_msg
+ *
+ * @param[in] app_data Pointer to the application context of the message.
+ * @param[in] msg Pointer to the message data.
+ */
+typedef void (*nss_dtls_cmn_msg_callback_t)(void *app_data, struct nss_cmn_msg *msg);
+
+/**
+ * Callback function for receiving DTLS session data.
+ *
+ * @datatypes
+ * net_device \n
+ * sk_buff \n
+ * napi_struct
+ *
+ * @param[in] netdev Pointer to the associated network device.
+ * @param[in] skb Pointer to the data socket buffer.
+ * @param[in] napi Pointer to the NAPI structure.
+ */
+typedef void (*nss_dtls_cmn_data_callback_t)(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi);
+
+/**
+ * nss_dtls_cmn_tx_buf
+ * Sends a DTLS data packet to the NSS.
+ *
+ * @datatypes
+ * sk_buff \n
+ * nss_ctx_instance
+ *
+ * @param[in] os_buf Pointer to the OS data buffer.
+ * @param[in] if_num NSS interface number.
+ * @param[in] nss_ctx Pointer to the NSS core context.
+ *
+ * @return
+ * Status of Tx buffer forwarded to NSS for DTLS operation.
+ */
+nss_tx_status_t nss_dtls_cmn_tx_buf(struct sk_buff *os_buf, uint32_t if_num, struct nss_ctx_instance *nss_ctx);
+
+/**
+ * nss_dtls_cmn_tx_msg
+ * Sends DTLS messages.
+ *
+ * @param[in] nss_ctx Pointer to the NSS core context.
+ * @param[in,out] msg Pointer to the message data.
+ *
+ * @return
+ * Status of the Tx operation.
+ */
+extern nss_tx_status_t nss_dtls_cmn_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_dtls_cmn_msg *msg);
+
+/**
+ * nss_dtls_cmn_tx_msg_sync
+ * Sends DTLS messages synchronously.
+ *
+ * @datatypes
+ * nss_ctx_instance \n
+ * nss_dtls_cmn_msg_type \n
+ * nss_dtls_cmn_msg \n
+ * nss_dtls_cmn_error
+ *
+ * @param[in] nss_ctx Pointer to the NSS context.
+ * @param[in] if_num NSS interface number.
+ * @param[in] type Type of message.
+ * @param[in] len Size of the payload.
+ * @param[in] ndcm Pointer to the message data.
+ * @param[in,out] resp Response for the configuration.
+ *
+ * @return
+ * Status of the Tx operation.
+ */
+extern nss_tx_status_t nss_dtls_cmn_tx_msg_sync(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
+ enum nss_dtls_cmn_msg_type type, uint16_t len,
+ struct nss_dtls_cmn_msg *ndcm, enum nss_dtls_cmn_error *resp);
+
+/**
+ * nss_dtls_cmn_register_if
+ * Registers a DTLS session interface with the NSS for sending and receiving
+ * messages.
+ *
+ * @datatypes
+ * nss_dtls_cmn_data_callback_t \n
+ * nss_dtls_cmn_msg_callback_t
+ *
+ * @param[in] if_num NSS interface number.
+ * @param[in] data_cb Callback function for the message.
+ * @param[in] msg_cb Callback for DTLS tunnel message.
+ * @param[in] netdev Pointer to the associated network device.
+ * @param[in] features Data socket buffer types supported by this interface.
+ * @param[in] app_ctx Pointer to the application context.
+ *
+ * @return
+ * Pointer to the NSS core context.
+ */
+extern struct nss_ctx_instance *nss_dtls_cmn_register_if(uint32_t if_num,
+ nss_dtls_cmn_data_callback_t data_cb,
+ nss_dtls_cmn_msg_callback_t msg_cb,
+ struct net_device *netdev,
+ uint32_t features,
+ uint32_t type,
+ void *app_ctx);
+
+/**
+ * nss_dtls_cmn_unregister_if
+ * Deregisters a DTLS session interface from the NSS.
+ *
+ * @param[in] if_num NSS interface number.
+ *
+ * @return
+ * None.
+ *
+ * @dependencies
+ * The DTLS session interface must have been previously registered.
+ */
+extern void nss_dtls_cmn_unregister_if(uint32_t if_num);
+
+/**
+ * nss_dtls_cmn_notify_register
+ * Register an event callback to handle notification from DTLS firmware package.
+ *
+ * @param[in] if_num NSS interface number.
+ * @param[in] ev_cb Callback for DTLS tunnel message.
+ * @param[in] app_data Pointer to the application context.
+ *
+ * @return
+ * Pointer to NSS core context.
+ */
+extern struct nss_ctx_instance *nss_dtls_cmn_notify_register(uint32_t ifnum, nss_dtls_cmn_msg_callback_t ev_cb,
+ void *app_data);
+
+/**
+ * nss_dtls_cmn_notify_unregister
+ * Unregister an event callback.
+ *
+ * @param[in] if_num NSS interface number.
+ *
+ * @return
+ * None.
+ */
+extern void nss_dtls_cmn_notify_unregister(uint32_t ifnum);
+
+/**
+ * nss_dtls_cmn_msg_init
+ * Initializes a DTLS message.
+ *
+ * @datatypes
+ * nss_dtls_cmn_msg
+ *
+ * @param[in,out] ncm Pointer to the message.
+ * @param[in] if_num NSS interface number.
+ * @param[in] type Type of message.
+ * @param[in] len Size of the payload.
+ * @param[in] cb Pointer to the message callback.
+ * @param[in] app_data Pointer to the application context.
+ *
+ * @return
+ * None.
+ */
+extern void nss_dtls_cmn_msg_init(struct nss_dtls_cmn_msg *ncm, uint32_t if_num, uint32_t type, uint32_t len, void *cb,
+ void *app_data);
+
+/**
+ * nss_dtls_cmn_get_context
+ * Gets the NSS core context for the DTLS session.
+ *
+ * @return
+ * Pointer to the NSS core context.
+ */
+extern struct nss_ctx_instance *nss_dtls_cmn_get_context(void);
+
+/**
+ * nss_dtls_cmn_get_ifnum
+ * Gets the DTLS interface number with a core ID.
+ *
+ * @param[in] if_num NSS interface number.
+ *
+ * @return
+ * Interface number with the core ID.
+ */
+extern int32_t nss_dtls_cmn_get_ifnum(int32_t if_num);
+
+/**
+ * @}
+ */
+
+#endif /* _NSS_DTLS_CMN_H_. */
diff --git a/exports/nss_dynamic_interface.h b/exports/nss_dynamic_interface.h
index 5a0147f..9399ae5 100644
--- a/exports/nss_dynamic_interface.h
+++ b/exports/nss_dynamic_interface.h
@@ -58,6 +58,8 @@
NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR_OUTER,
NSS_DYNAMIC_INTERFACE_TYPE_GRE_TUNNEL_INNER,
NSS_DYNAMIC_INTERFACE_TYPE_GRE_TUNNEL_OUTER,
+ NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER,
+ NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER,
NSS_DYNAMIC_INTERFACE_TYPE_MAX
};
diff --git a/nss_dtls_cmn.c b/nss_dtls_cmn.c
new file mode 100644
index 0000000..1ac43fb
--- /dev/null
+++ b/nss_dtls_cmn.c
@@ -0,0 +1,567 @@
+/*
+ **************************************************************************
+ * 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.
+ **************************************************************************
+ */
+
+#include "nss_tx_rx_common.h"
+
+#define NSS_DTLS_CMN_TX_TIMEOUT 3000 /* 3 Seconds */
+#define NSS_DTLS_CMN_INTERFACE_MAX_LONG BITS_TO_LONGS(NSS_MAX_NET_INTERFACES)
+#define NSS_DTLS_CMN_STATS_MAX_LINES (NSS_STATS_NODE_MAX + 32)
+#define NSS_DTLS_CMN_STATS_SIZE_PER_IF (NSS_STATS_MAX_STR_LENGTH * NSS_DTLS_CMN_STATS_MAX_LINES)
+/*
+ * Private data structure
+ */
+static struct nss_dtls_cmn_cmn_pvt {
+ struct semaphore sem;
+ struct completion complete;
+ enum nss_dtls_cmn_error resp;
+ unsigned long if_map[NSS_DTLS_CMN_INTERFACE_MAX_LONG];
+} dtls_cmn_pvt;
+
+/*
+ * nss_dtls_cmn_stats_sync()
+ * Update dtls_cmn node statistics.
+ */
+static void nss_dtls_cmn_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm)
+{
+ struct nss_dtls_cmn_msg *ndcm = (struct nss_dtls_cmn_msg *)ncm;
+ struct nss_top_instance *nss_top = nss_ctx->nss_top;
+ struct nss_dtls_cmn_ctx_stats *msg_stats = &ndcm->msg.stats;
+ uint64_t *if_stats;
+
+ spin_lock_bh(&nss_top->stats_lock);
+
+ /*
+ * Update common node stats,
+ * Note: DTLS only supports a single queue for RX
+ */
+ if_stats = nss_top->stats_node[ncm->interface];
+ if_stats[NSS_STATS_NODE_RX_PKTS] += msg_stats->pkt.rx_packets;
+ if_stats[NSS_STATS_NODE_RX_BYTES] += msg_stats->pkt.rx_bytes;
+ if_stats[NSS_STATS_NODE_RX_QUEUE_0_DROPPED] += msg_stats->pkt.rx_dropped[0];
+
+ if_stats[NSS_STATS_NODE_TX_PKTS] += msg_stats->pkt.tx_packets;
+ if_stats[NSS_STATS_NODE_TX_BYTES] += msg_stats->pkt.tx_bytes;
+
+ spin_unlock_bh(&nss_top->stats_lock);
+}
+
+/*
+ * nss_dtls_cmn_stats_read()
+ * Read dtls_cmn node statiistics.
+ */
+static ssize_t nss_dtls_cmn_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
+{
+ struct nss_ctx_instance *nss_ctx = nss_dtls_cmn_get_context();
+ enum nss_dynamic_interface_type type;
+ ssize_t bytes_read = 0;
+ size_t len = 0, size;
+ uint32_t if_num;
+ char *buf;
+
+ size = NSS_DTLS_CMN_STATS_SIZE_PER_IF * bitmap_weight(dtls_cmn_pvt.if_map, NSS_MAX_NET_INTERFACES);
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf) {
+ nss_warning("Could not allocate memory for local statistics buffer");
+ return 0;
+ }
+
+ /*
+ * Common node stats for each DTLS dynamic interface.
+ */
+ for_each_set_bit(if_num, dtls_cmn_pvt.if_map, NSS_MAX_NET_INTERFACES) {
+
+ type = nss_dynamic_interface_get_type(nss_ctx, if_num);
+
+ switch (type) {
+ case NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER:
+ len += scnprintf(buf + len, size - len, "\nInner if_num:%03u", if_num);
+ break;
+
+ case NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER:
+ len += scnprintf(buf + len, size - len, "\nOuter if_num:%03u", if_num);
+ break;
+
+ default:
+ len += scnprintf(buf + len, size - len, "\nUnknown(%d) if_num:%03u", type, if_num);
+ break;
+ }
+
+ len += scnprintf(buf + len, size - len, "\n-------------------\n");
+ len += nss_stats_fill_common_stats(if_num, buf, len, size - len);
+ }
+
+ bytes_read = simple_read_from_buffer(ubuf, sz, ppos, buf, len);
+ kfree(buf);
+
+ return bytes_read;
+}
+
+/*
+ * nss_dtls_cmn_stats_ops
+ */
+NSS_STATS_DECLARE_FILE_OPERATIONS(dtls_cmn)
+
+/*
+ * nss_dtls_cmn_verify_ifnum()
+ * Verify if the interface number is a DTLS interface.
+ */
+static bool nss_dtls_cmn_verify_ifnum(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
+{
+ enum nss_dynamic_interface_type type = nss_dynamic_interface_get_type(nss_ctx, if_num);
+
+ if (type == NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER)
+ return true;
+
+ if (type == NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER)
+ return true;
+
+ if (if_num == NSS_DTLS_INTERFACE)
+ return true;
+
+ return false;
+}
+
+/*
+ * nss_dtls_cmn_handler()
+ * Handle NSS -> HLOS messages for dtls tunnel
+ */
+static void nss_dtls_cmn_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *data)
+{
+ nss_dtls_cmn_msg_callback_t cb;
+ void *app_data;
+
+ NSS_VERIFY_CTX_MAGIC(nss_ctx);
+
+ nss_trace("%p: handle event for interface num :%u", nss_ctx, ncm->interface);
+
+ /*
+ * Is this a valid request/response packet?
+ */
+ if (ncm->type >= NSS_DTLS_CMN_MSG_MAX) {
+ nss_warning("%p:Bad message type(%d) for DTLS interface %d", nss_ctx, ncm->type, ncm->interface);
+ return;
+ }
+
+ if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_dtls_cmn_msg)) {
+ nss_warning("%p:Bad message length(%d)", nss_ctx, ncm->len);
+ return;
+ }
+
+ if (ncm->type == NSS_DTLS_CMN_MSG_TYPE_SYNC_STATS)
+ nss_dtls_cmn_stats_sync(nss_ctx, ncm);
+
+ /*
+ * Update the callback and app_data for NOTIFY messages
+ */
+ if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
+ ncm->cb = (nss_ptr_t)nss_top_main.if_rx_msg_callback[ncm->interface];
+ ncm->app_data = (nss_ptr_t)nss_ctx->nss_rx_interface_handlers[nss_ctx->id][ncm->interface].app_data;
+ }
+
+ /*
+ * Log failures
+ */
+ nss_core_log_msg_failures(nss_ctx, ncm);
+
+ /*
+ * Callback
+ */
+ cb = (nss_dtls_cmn_msg_callback_t)ncm->cb;
+ app_data = (void *)ncm->app_data;
+
+ /*
+ * Call DTLS session callback
+ */
+ if (!cb) {
+ nss_warning("%p: No callback for dtls session interface %d", nss_ctx, ncm->interface);
+ return;
+ }
+
+ nss_trace("%p: calling dtlsmgr event handler(%u)", nss_ctx, ncm->interface);
+ cb(app_data, ncm);
+}
+
+/*
+ * nss_dtls_cmn_callback()
+ * Callback to handle the completion of NSS->HLOS messages.
+ */
+static void nss_dtls_cmn_callback(void *app_data, struct nss_cmn_msg *ncm)
+{
+ /*
+ * This callback is for synchronous operation. The caller sends its
+ * response pointer which needs to be loaded with the response
+ * data arriving from the NSS
+ */
+ enum nss_dtls_cmn_error *resp = (enum nss_dtls_cmn_error *)app_data;
+
+ *resp = (ncm->response == NSS_CMN_RESPONSE_ACK) ? NSS_DTLS_CMN_ERROR_NONE : ncm->error;
+ complete(&dtls_cmn_pvt.complete);
+
+ return;
+}
+
+/*
+ * nss_dtls_cmn_tx_buf()
+ * Transmit buffer over DTLS interface
+ */
+nss_tx_status_t nss_dtls_cmn_tx_buf(struct sk_buff *skb, uint32_t if_num, struct nss_ctx_instance *nss_ctx)
+{
+ int32_t status;
+
+ NSS_VERIFY_CTX_MAGIC(nss_ctx);
+
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: 'DTLS If Tx' core not ready", nss_ctx);
+ return NSS_TX_FAILURE_NOT_READY;
+ }
+
+ if (!nss_dtls_cmn_verify_ifnum(nss_ctx, if_num))
+ return NSS_TX_FAILURE;
+
+ status = nss_core_send_buffer(nss_ctx, if_num, skb, NSS_IF_DATA_QUEUE_0,
+ H2N_BUFFER_PACKET, H2N_BIT_FLAG_VIRTUAL_BUFFER);
+ switch (status) {
+ case NSS_CORE_STATUS_SUCCESS:
+ break;
+
+ case NSS_CORE_STATUS_FAILURE_QUEUE:
+ nss_warning("%p: Unable to enqueue DTLS packet(%u); queue full", nss_ctx, if_num);
+ return NSS_TX_FAILURE_QUEUE;
+
+ default:
+ nss_warning("%p: Unable to enqueue DTLS packet(%u)", nss_ctx, if_num);
+ return NSS_TX_FAILURE;
+ }
+
+ nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
+ NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
+
+ return NSS_TX_SUCCESS;
+}
+EXPORT_SYMBOL(nss_dtls_cmn_tx_buf);
+
+/*
+ * nss_dtls_cmn_tx_msg()
+ * Transmit a DTLS message to NSS firmware
+ */
+nss_tx_status_t nss_dtls_cmn_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_dtls_cmn_msg *msg)
+{
+ struct nss_dtls_cmn_msg *nm;
+ struct nss_cmn_msg *ncm = &msg->cm;
+ struct sk_buff *nbuf;
+ int32_t status;
+
+ NSS_VERIFY_CTX_MAGIC(nss_ctx);
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: dtls msg dropped as core not ready", nss_ctx);
+ return NSS_TX_FAILURE_NOT_READY;
+ }
+
+ if (ncm->type >= NSS_DTLS_CMN_MSG_MAX) {
+ nss_warning("%p: dtls message type out of range: %d", nss_ctx, ncm->type);
+ return NSS_TX_FAILURE;
+ }
+
+ if (!nss_dtls_cmn_verify_ifnum(nss_ctx, ncm->interface)) {
+ nss_warning("%p: dtls message interface is bad: %u", nss_ctx, ncm->interface);
+ return NSS_TX_FAILURE;
+ }
+
+ if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_dtls_cmn_msg)) {
+ nss_warning("%p: dtls message length is invalid: %d", nss_ctx, ncm->len);
+ return NSS_TX_FAILURE;
+ }
+
+ nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
+ if (unlikely(!nbuf)) {
+ NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
+ nss_warning("%p: dtls msg dropped as command allocation failed", nss_ctx);
+ return NSS_TX_FAILURE;
+ }
+
+ /*
+ * Copy the message to our skb
+ */
+ nm = (struct nss_dtls_cmn_msg *)skb_put(nbuf, sizeof(struct nss_dtls_cmn_msg));
+ memcpy(nm, msg, sizeof(struct nss_dtls_cmn_msg));
+
+ status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
+ switch (status) {
+ case NSS_CORE_STATUS_SUCCESS:
+ break;
+
+ case NSS_CORE_STATUS_FAILURE_QUEUE:
+ dev_kfree_skb_any(nbuf);
+ nss_warning("%p: Unable to enqueue DTLS packet(%u); queue full", nss_ctx, ncm->interface);
+ return NSS_TX_FAILURE_QUEUE;
+
+ default:
+ dev_kfree_skb_any(nbuf);
+ nss_warning("%p: Unable to enqueue DTLS packet(%u)", nss_ctx, ncm->interface);
+ return NSS_TX_FAILURE;
+ }
+
+ nss_trace("%p: sending message for interface (%u), type(%d)", nss_ctx, ncm->interface, ncm->type);
+
+ nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
+
+ NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
+ return NSS_TX_SUCCESS;
+}
+EXPORT_SYMBOL(nss_dtls_cmn_tx_msg);
+
+/*
+ * nss_dtls_cmn_tx_msg_sync()
+ * Transmit a DTLS message to NSS firmware synchronously.
+ */
+nss_tx_status_t nss_dtls_cmn_tx_msg_sync(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
+ enum nss_dtls_cmn_msg_type type, uint16_t len,
+ struct nss_dtls_cmn_msg *ndcm, enum nss_dtls_cmn_error *resp)
+{
+ struct nss_dtls_cmn_msg ndcm_local;
+ nss_tx_status_t status;
+ int ret;
+
+ /*
+ * Length of the message should be the based on type
+ */
+ if (len > sizeof(ndcm_local.msg)) {
+ nss_warning("%p: (%u)Bad message length(%u) for type (%d)", nss_ctx, if_num, len, type);
+ return NSS_TX_FAILURE_TOO_LARGE;
+ }
+
+ /*
+ * Response buffer is a required for copying the response for message
+ */
+ if (!resp) {
+ nss_warning("%p: (%u)Response buffer is empty, type(%d)", nss_ctx, if_num, type);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ /*
+ * TODO: this can be removed in future as we need to ensure that the response
+ * memory is only updated when the current outstanding request is waiting.
+ * This can be solved by introducing sequence no. in messages and only completing
+ * the message if the sequence no. matches. For now this is solved by passing
+ * a known memory dtls_cmn_pvt.resp
+ */
+ down(&dtls_cmn_pvt.sem);
+
+ /*
+ * We need to copy the message content into the actual message
+ * to be sent to NSS
+ */
+ nss_dtls_cmn_msg_init(&ndcm_local, if_num, type, len, nss_dtls_cmn_callback, &dtls_cmn_pvt.resp);
+ memcpy(&ndcm_local.msg, &ndcm->msg, len);
+
+ status = nss_dtls_cmn_tx_msg(nss_ctx, &ndcm_local);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: dtls_tx_msg failed", nss_ctx);
+ goto done;
+ }
+
+ ret = wait_for_completion_timeout(&dtls_cmn_pvt.complete, msecs_to_jiffies(NSS_DTLS_CMN_TX_TIMEOUT));
+ if (!ret) {
+ nss_warning("%p: DTLS msg tx failed due to timeout", nss_ctx);
+ status = NSS_TX_FAILURE_NOT_READY;
+ goto done;
+ }
+
+ /*
+ * Read memory barrier
+ */
+ smp_rmb();
+
+ /*
+ * Copy the response received
+ */
+ *resp = dtls_cmn_pvt.resp;
+
+ /*
+ * Only in case of non-error response we will
+ * indicate success
+ */
+ if (dtls_cmn_pvt.resp != NSS_DTLS_CMN_ERROR_NONE)
+ status = NSS_TX_FAILURE;
+
+done:
+ up(&dtls_cmn_pvt.sem);
+ return status;
+}
+EXPORT_SYMBOL(nss_dtls_cmn_tx_msg_sync);
+
+/*
+ * nss_dtls_cmn_notify_register()
+ * Register a handler for notification from NSS firmware.
+ */
+struct nss_ctx_instance *nss_dtls_cmn_notify_register(uint32_t if_num, nss_dtls_cmn_msg_callback_t ev_cb,
+ void *app_data)
+{
+ struct nss_ctx_instance *nss_ctx = nss_dtls_cmn_get_context();
+ uint32_t ret;
+
+ BUG_ON(!nss_ctx);
+
+ ret = nss_core_register_handler(nss_ctx, if_num, nss_dtls_cmn_handler, app_data);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("%p: unable to register event handler for interface(%u)", nss_ctx, if_num);
+ return NULL;
+ }
+
+ nss_top_main.if_rx_msg_callback[if_num] = ev_cb;
+
+ return nss_ctx;
+}
+EXPORT_SYMBOL(nss_dtls_cmn_notify_register);
+
+/*
+ * nss_dtls_cmn_notify_unregister()
+ * Unregister notification callback handler.
+ */
+void nss_dtls_cmn_notify_unregister(uint32_t if_num)
+{
+ struct nss_ctx_instance *nss_ctx = nss_dtls_cmn_get_context();
+ uint32_t ret;
+
+ BUG_ON(!nss_ctx);
+
+ ret = nss_core_unregister_handler(nss_ctx, if_num);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("%p: unable to un register event handler for interface(%u)", nss_ctx, if_num);
+ return;
+ }
+
+ nss_top_main.if_rx_msg_callback[if_num] = NULL;
+
+ return;
+}
+EXPORT_SYMBOL(nss_dtls_cmn_notify_unregister);
+
+/*
+ * nss_dtls_cmn_register_if()
+ * Register data and event callback handlers for dynamic interface.
+ */
+struct nss_ctx_instance *nss_dtls_cmn_register_if(uint32_t if_num,
+ nss_dtls_cmn_data_callback_t data_cb,
+ nss_dtls_cmn_msg_callback_t ev_cb,
+ struct net_device *netdev,
+ uint32_t features,
+ uint32_t type,
+ void *app_data)
+{
+ struct nss_ctx_instance *nss_ctx = nss_dtls_cmn_get_context();
+ uint32_t ret;
+
+ if (!nss_dtls_cmn_verify_ifnum(nss_ctx, if_num)) {
+ nss_warning("%p: DTLS Interface is not dynamic:%u", nss_ctx, if_num);
+ return NULL;
+ }
+
+ if (nss_ctx->subsys_dp_register[if_num].ndev) {
+ nss_warning("%p: Cannot find free slot for DTLS NSS I/F:%u", nss_ctx, if_num);
+ return NULL;
+ }
+
+ nss_core_register_subsys_dp(nss_ctx, if_num, data_cb, NULL, app_data, netdev, features);
+ nss_ctx->subsys_dp_register[if_num].type = type;
+
+ ret = nss_core_register_handler(nss_ctx, if_num, nss_dtls_cmn_handler, app_data);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("%p: unable to register event handler for interface(%u)", nss_ctx, if_num);
+ return NULL;
+ }
+
+ nss_top_main.if_rx_msg_callback[if_num] = ev_cb;
+
+ /*
+ * Atomically set the bitmap for the interface number
+ */
+ set_bit(if_num, dtls_cmn_pvt.if_map);
+ return nss_ctx;
+}
+EXPORT_SYMBOL(nss_dtls_cmn_register_if);
+
+/*
+ * nss_dtls_cmn_unregister_if()
+ * Unregister data and event callback handlers for the interface.
+ */
+void nss_dtls_cmn_unregister_if(uint32_t if_num)
+{
+ struct nss_ctx_instance *nss_ctx = nss_dtls_cmn_get_context();
+
+ if (!nss_ctx->subsys_dp_register[if_num].ndev) {
+ nss_warning("%p: Cannot find registered netdev for DTLS NSS I/F:%u", nss_ctx, if_num);
+ return;
+ }
+
+ nss_core_unregister_subsys_dp(nss_ctx, if_num);
+ nss_ctx->subsys_dp_register[if_num].type = 0;
+
+ nss_core_unregister_handler(nss_ctx, if_num);
+ nss_top_main.if_rx_msg_callback[if_num] = NULL;
+
+ /*
+ * Atomically clear the bitmap for the interface number
+ */
+ clear_bit(if_num, dtls_cmn_pvt.if_map);
+}
+EXPORT_SYMBOL(nss_dtls_cmn_unregister_if);
+
+/*
+ * nss_dtls_get_context()
+ * Return DTLS NSS context.
+ */
+struct nss_ctx_instance *nss_dtls_cmn_get_context(void)
+{
+ return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.dtls_handler_id];
+}
+EXPORT_SYMBOL(nss_dtls_cmn_get_context);
+
+/*
+ * nss_dtls_cmn_msg_init()
+ * Initialize nss_dtls_cmn msg.
+ */
+void nss_dtls_cmn_msg_init(struct nss_dtls_cmn_msg *ncm, uint32_t if_num,
+ uint32_t type, uint32_t len, void *cb, void *app_data)
+{
+ nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
+}
+EXPORT_SYMBOL(nss_dtls_cmn_msg_init);
+
+/*
+ * nss_dtls_cmn_get_ifnum()
+ * Return DTLS interface number with coreid.
+ */
+int32_t nss_dtls_cmn_get_ifnum(int32_t if_num)
+{
+ struct nss_ctx_instance *nss_ctx = nss_dtls_cmn_get_context();
+
+ NSS_VERIFY_CTX_MAGIC(nss_ctx);
+ return NSS_INTERFACE_NUM_APPEND_COREID(nss_ctx, if_num);
+}
+EXPORT_SYMBOL(nss_dtls_cmn_get_ifnum);
+
+/*
+ * nss_dtls_cmn_register_handler()
+ * DTLS initialization.
+ */
+void nss_dtls_cmn_register_handler(void)
+{
+ sema_init(&dtls_cmn_pvt.sem, 1);
+ init_completion(&dtls_cmn_pvt.complete);
+ nss_stats_create_dentry("dtls_cmn", &nss_dtls_cmn_stats_ops);
+}
diff --git a/nss_hal/nss_hal.c b/nss_hal/nss_hal.c
index dacab2b..cd3592a 100644
--- a/nss_hal/nss_hal.c
+++ b/nss_hal/nss_hal.c
@@ -426,8 +426,14 @@
if (npd->dtls_enabled == NSS_FEATURE_ENABLED) {
nss_top->dtls_handler_id = nss_dev->id;
+#if defined(NSS_HAL_IPQ807x_SUPPORT)
+ nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_INNER] = nss_dev->id;
+ nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_DTLS_CMN_OUTER] = nss_dev->id;
+ nss_dtls_cmn_register_handler();
+#else
nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_DTLS] = nss_dev->id;
nss_dtls_register_handler();
+#endif
}
if (npd->map_t_enabled == NSS_FEATURE_ENABLED) {
diff --git a/nss_tx_rx_common.h b/nss_tx_rx_common.h
index 6e80af4..e27077e 100644
--- a/nss_tx_rx_common.h
+++ b/nss_tx_rx_common.h
@@ -198,6 +198,7 @@
extern void nss_portid_register_handler(void);
extern void nss_oam_register_handler(void);
extern void nss_dtls_register_handler(void);
+extern void nss_dtls_cmn_register_handler(void);
extern void nss_gre_tunnel_register_handler(void);
extern void nss_trustsec_tx_register_handler(void);
extern void nss_wifili_register_handler(void);