[qca-nss-clients] NETLINK I/F for crypto
Added the support for crypto in the common netlink
infra structure.
Change-Id: I0a36e1fe5e24fc06093af144e7753fb926c810e6
Signed-off-by: y <mandrw@codeaurora.org>
diff --git a/netlink/Makefile b/netlink/Makefile
index 5a67693..15fd740 100755
--- a/netlink/Makefile
+++ b/netlink/Makefile
@@ -1,5 +1,5 @@
ccflags-y := -I$(obj)/include
-ccflags-y += -I$(obj)/../../qca-nss-crypto/include
+ccflags-y += -I$(obj)/../../qca-nss-crypto/include/
ccflags-y += -DNSS_NL_DEBUG_LEVEL=4
ccflags-y += -DCONFIG_NSS_NLCRYPTO=1
@@ -9,7 +9,7 @@
obj-m += qca-nss-netlink.o
qca-nss-netlink-objs := nss_nl.o
-#qca-nss-netlink-objs += nss_nlcrypto.o
+qca-nss-netlink-objs += nss_nlcrypto.o
qca-nss-netlink-objs += nss_nlipv4.o
#qca-nss-netlink-objs += nss_nlipsec.o
diff --git a/netlink/include/nss_nlcrypto_if.h b/netlink/include/nss_nlcrypto_if.h
new file mode 100755
index 0000000..c76d7c1
--- /dev/null
+++ b/netlink/include/nss_nlcrypto_if.h
@@ -0,0 +1,107 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2015, 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_nlcrypto_if.h
+ * NSS Netlink Crypto headers
+ */
+#ifndef __NSS_NLCRPTO_IF_H
+#define __NSS_NLCRPTO_IF_H
+
+/**
+ * @brief Crypto forwarding Family
+ */
+#define NSS_NLCRYPTO_FAMILY "nss_nlcrypto"
+#define NSS_NLCRYPTO_MAX_KEYLEN 32
+
+/**
+ * @brief crypto commands types
+ */
+enum nss_nlcrypto_cmd {
+ NSS_NLCRYPTO_CMD_UNSPEC = 0, /**< unspecified cmd */
+ NSS_NLCRYPTO_CMD_CREATE_SESSION = 1, /**< session add */
+ NSS_NLCRYPTO_CMD_UPDATE_SESSION = 2, /**< session update */
+ NSS_NLCRYPTO_CMD_DESTROY_SESSION = 3, /**< session delete */
+ NSS_NLCRYPTO_CMD_INFO_SESSION = 4, /**< session info */
+
+ NSS_NLCRYPTO_CMD_MAX
+};
+
+/**
+ * @brief crypto create session
+ */
+struct nss_nlcrypto_create_session {
+ struct nss_crypto_key cipher; /**< cipher key information */
+ struct nss_crypto_key auth; /**< auth key information */
+
+ uint8_t cipher_key[NSS_NLCRYPTO_MAX_KEYLEN]; /**< cipher key data */
+ uint8_t auth_key[NSS_NLCRYPTO_MAX_KEYLEN]; /**< auth key data */
+};
+
+/**
+ * @brief crypto destroy session
+ */
+struct nss_nlcrypto_destroy_session {
+ uint32_t session_idx; /**< session index */
+};
+
+/**
+ * @brief crypto update session
+ */
+struct nss_nlcrypto_update_session {
+ uint32_t session_idx; /**< session index */
+ struct nss_crypto_params param; /**< crypto parameters */
+};
+
+/**
+ * @brief crypto session info
+ */
+struct nss_nlcrypto_info_session {
+ uint32_t session_idx; /**< session information */
+
+ struct {
+ uint16_t algo; /**< algorithm */
+ uint16_t key_len; /**< key length */
+ } cipher, auth;
+};
+
+/**
+ * @brief crypto rule
+ */
+struct nss_nlcrypto_rule {
+ struct nss_nlcmn cm; /**< common message header */
+
+ union {
+ struct nss_nlcrypto_create_session create; /**< session create */
+ struct nss_nlcrypto_update_session update; /**< session update */
+ struct nss_nlcrypto_destroy_session destroy; /**< session destroy */
+ struct nss_nlcrypto_info_session info; /**< session info */
+ }msg;
+};
+
+/**
+ * @brief NETLINK Crypto message init
+ *
+ * @param rule[IN] NSS NETLINK crypto rule
+ * @param type[IN] Crypto message type
+ */
+static inline void nss_nlcrypto_rule_init(struct nss_nlcrypto_rule *rule, enum nss_nlcrypto_cmd type)
+{
+ nss_nlcmn_set_ver(&rule->cm, NSS_NL_VER);
+ nss_nlcmn_init_cmd(&rule->cm, type, sizeof(struct nss_nlcrypto_rule));
+}
+
+#endif /* __NSS_NLCRPTO_IF_H */
diff --git a/netlink/nss_nlcrypto.c b/netlink/nss_nlcrypto.c
new file mode 100644
index 0000000..9f793d0
--- /dev/null
+++ b/netlink/nss_nlcrypto.c
@@ -0,0 +1,513 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2015, 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_nlcrypto.c
+ * NSS Netlink Crypto Handler
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/netlink.h>
+#include <linux/version.h>
+#include <net/genetlink.h>
+
+#include <nss_api_if.h>
+#include <nss_cmn.h>
+#include <nss_nl_if.h>
+#include "nss_nl.h"
+#include <nss_crypto_if.h>
+#include "nss_nlcrypto_if.h"
+/*
+ * @brief prototypes
+ */
+
+static int nss_nlcrypto_op_session_create(struct sk_buff *skb_msg, struct genl_info *info);
+static int nss_nlcrypto_op_session_update(struct sk_buff *skb_msg, struct genl_info *info);
+static int nss_nlcrypto_op_session_destroy(struct sk_buff *skb_msg, struct genl_info *info);
+static int nss_nlcrypto_op_session_info(struct sk_buff *skb_msg, struct genl_info *info);
+
+
+/*
+ * @brief Crypto family definition
+ */
+static struct genl_family nss_nlcrypto_family = {
+ .id = GENL_ID_GENERATE, /* Auto generate ID */
+ .name = NSS_NLCRYPTO_FAMILY, /* family name string */
+ .hdrsize = sizeof(struct nss_nlcrypto_rule), /* NSS NETLINK Crypto rule */
+ .version = NSS_NL_VER, /* Set it to NSS_NLIPv4 version */
+ .maxattr = NSS_NLCRYPTO_CMD_MAX, /* maximum commands supported */
+ .netnsok = true,
+ .pre_doit = NULL,
+ .post_doit = NULL,
+};
+
+/*
+ * @brief operation table called by the generic netlink layer based on the command
+ */
+static struct genl_ops nss_nlcrypto_ops[] = {
+ {.cmd = NSS_NLCRYPTO_CMD_CREATE_SESSION, .doit = nss_nlcrypto_op_session_create,}, /* rule create */
+ {.cmd = NSS_NLCRYPTO_CMD_UPDATE_SESSION, .doit = nss_nlcrypto_op_session_update,}, /* rule destroy */
+ {.cmd = NSS_NLCRYPTO_CMD_DESTROY_SESSION, .doit = nss_nlcrypto_op_session_destroy,}, /* rule destroy */
+ {.cmd = NSS_NLCRYPTO_CMD_INFO_SESSION, .doit = nss_nlcrypto_op_session_info,}, /* rule destroy */
+};
+
+
+#define NSS_NLCRYPTO_OPS_SZ ARRAY_SIZE(nss_nlcrypto_ops)
+
+static nss_crypto_handle_t nss_nlcrypto_hdl;
+
+struct nss_nlcrypto_ctx {
+ nss_crypto_handle_t crypto_hdl; /* Crypto handle */
+};
+
+/*
+ * global context
+ */
+static struct nss_nlcrypto_ctx gbl_ctx;
+
+/*
+ * @brief nss_nlcrypto_validate_cipher()
+ * validate the cipher parameters
+ */
+static inline bool nss_nlcrypto_validate_cipher(struct nss_crypto_key *cipher)
+{
+ enum nss_crypto_cipher algo = cipher->algo;
+ uint16_t key_len = cipher->key_len;
+ uint16_t max_key_len = 0;
+
+ switch (algo) {
+ case NSS_CRYPTO_CIPHER_AES:
+ max_key_len = NSS_CRYPTO_MAX_KEYLEN_AES;
+ break;
+
+ case NSS_CRYPTO_CIPHER_DES:
+ max_key_len = NSS_CRYPTO_MAX_KEYLEN_DES;
+ break;
+
+ case NSS_CRYPTO_CIPHER_NULL:
+ max_key_len = 0;
+ break;
+
+ default:
+ return false;
+ }
+
+ /*
+ * Key length shouldn't be more than max key length
+ */
+ return !(key_len > max_key_len);
+}
+
+/*
+ * @brief nss_nlcrypto_validate_auth()
+ * validate the auth parameters
+ */
+static inline bool nss_nlcrypto_validate_auth(struct nss_crypto_key *auth)
+{
+ enum nss_crypto_auth algo = auth->algo;
+ uint16_t key_len = auth->key_len;
+ uint16_t max_key_len = 0;
+
+ switch (algo) {
+ case NSS_CRYPTO_AUTH_SHA1_HMAC:
+ max_key_len = NSS_CRYPTO_MAX_KEYLEN_SHA1;
+ break;
+
+ case NSS_CRYPTO_AUTH_SHA256_HMAC:
+ max_key_len = NSS_CRYPTO_MAX_KEYLEN_SHA256;
+ break;
+
+ case NSS_CRYPTO_AUTH_NULL:
+ max_key_len = 0;
+ break;
+
+ default:
+ return false;
+
+ }
+
+ /*
+ * Key length shouldn't be more than max key length
+ */
+ return !(key_len > max_key_len);
+
+}
+
+/*
+ * @brief nss_nlcrypto_validate_param()
+ * validate the parameters
+ */
+static inline bool nss_nlcrypto_validate_param(struct nss_crypto_params *param)
+{
+ /* check the skip lengths */
+ if (param->auth_skip > param->cipher_skip) {
+ return false;
+ }
+
+ switch (param->req_type) {
+ /* pure encryption */
+ case NSS_CRYPTO_REQ_TYPE_ENCRYPT:
+ return true;
+ /* pure decryption */
+ case NSS_CRYPTO_REQ_TYPE_DECRYPT:
+ return true;
+ /* encryption + authentication */
+ case (NSS_CRYPTO_REQ_TYPE_ENCRYPT | NSS_CRYPTO_REQ_TYPE_AUTH):
+ return true;
+ /* decryption + authentication */
+ case (NSS_CRYPTO_REQ_TYPE_DECRYPT | NSS_CRYPTO_REQ_TYPE_AUTH):
+ return true;
+ /* everything else */
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+/*
+ * @brief nss_nlcrypto_compose_info()
+ * Compose the info message
+ */
+static inline void nss_crypto_copy_info(struct nss_nlcrypto_info_session *reply, uint32_t session_idx)
+{
+ reply->session_idx = session_idx;
+ reply->cipher.algo = nss_crypto_get_cipher(session_idx);
+ reply->auth.algo = nss_crypto_get_auth(session_idx);
+}
+
+/*
+ * @brief nss_nlcrypto_op_session_create()
+ * session add handler
+ */
+static int nss_nlcrypto_op_session_create(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nss_nlcrypto_create_session *create_msg;
+ struct nss_nlcrypto_info_session *reply;
+ struct nss_crypto_key *cipher = NULL;
+ struct nss_crypto_key *auth = NULL;
+ struct nss_nlcrypto_rule *nl_rule;
+ nss_crypto_status_t status;
+ struct nss_nlcmn *nl_cm;
+ int32_t session_idx = -1;
+ struct sk_buff *resp;
+ uint32_t pid;
+
+
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlcrypto_family, info, NSS_NLCRYPTO_CMD_CREATE_SESSION);
+ if (!nl_cm) {
+ nss_nl_error("unable to extract rule create data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlcrypto_rule, cm);
+
+ pid = nl_cm->pid;
+ create_msg = &nl_rule->msg.create;
+
+ cipher = &create_msg->cipher;
+ auth = &create_msg->auth;
+
+ /* validate if cipher specific parameters are correct */
+ if (nss_nlcrypto_validate_cipher(cipher) == false) {
+ nss_nl_error("cipher validation failed: algo(%d), key_len(%d)\n",
+ cipher->algo, cipher->key_len);
+ return -EINVAL;
+ }
+
+ /* validate if auth specific parameters are correct */
+ if (nss_nlcrypto_validate_auth(auth) == false) {
+ nss_nl_error("auth validation failed: algo(%d), key_len(%d)\n",
+ auth->algo,
+ auth->key_len);
+ return -EINVAL;
+ }
+
+ /*
+ * Link the key pointer in crypto driver structure to the array
+ */
+ cipher->key = create_msg->cipher_key;
+ auth->key = create_msg->auth_key;
+
+ status = nss_crypto_session_alloc(gbl_ctx.crypto_hdl, cipher, auth, &session_idx);
+ if (status != NSS_CRYPTO_STATUS_OK) {
+ nss_nl_error("%d:session alloc failed\n", pid);
+ return -EINVAL;
+ }
+
+ /*
+ * copy the NL message for response
+ */
+ resp = nss_nl_copy_msg(skb);
+ if (!resp) {
+ nss_nl_error("%d:unable to save response data from NL buffer\n", pid);
+ return -ENOMEM;
+ }
+
+ /*
+ * overload the nl_rule with the new response address
+ */
+ nl_rule = nss_nl_get_data(resp);
+ nss_nlcrypto_rule_init(nl_rule, NSS_NLCRYPTO_CMD_INFO_SESSION);
+
+ /*
+ * Fill up the info message
+ */
+ reply = &nl_rule->msg.info;
+ memset(reply, 0, sizeof(struct nss_nlcrypto_info_session));
+
+ /*
+ * copy the info message
+ */
+ nss_crypto_copy_info(reply, session_idx);
+
+ /*
+ * unicast the response to user
+ */
+ nss_nl_ucast_resp(resp);
+
+ return 0;
+}
+
+/*
+ * @brief nss_nlcrypto_op_session_update()
+ * session update handler
+ */
+static int nss_nlcrypto_op_session_update(struct sk_buff *skb_msg, struct genl_info *info)
+{
+ struct nss_nlcrypto_rule *nl_rule;
+ struct nss_crypto_params *param;
+ struct nss_nlcmn *nl_cm;
+ uint32_t session_idx;
+ uint32_t pid;
+
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlcrypto_family, info, NSS_NLCRYPTO_CMD_UPDATE_SESSION);
+ if (!nl_cm) {
+ nss_nl_error("unable to extract rule create data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlcrypto_rule, cm);
+ pid = nl_cm->pid;
+
+ session_idx = nl_rule->msg.update.session_idx;
+
+ param = &nl_rule->msg.update.param;
+ if (nss_nlcrypto_validate_param(param) == false) {
+ nss_nl_error("param validation failed: req_type(%d), auth_skip(%d), cipher_skip(%d)\n",
+ param->req_type,param->auth_skip, param->cipher_skip);
+ return -EINVAL;
+ }
+
+ return nss_crypto_session_update(nss_nlcrypto_hdl, session_idx, param);
+}
+
+/*
+ * @brief nss_nlcrypto_op_session_destroy()
+ * delete an existing session
+ *
+ */
+static int nss_nlcrypto_op_session_destroy(struct sk_buff *skb_msg, struct genl_info *info)
+{
+ struct nss_nlcrypto_destroy_session *destroy;
+ struct nss_nlcrypto_rule *nl_rule;
+ nss_crypto_status_t status;
+ struct nss_nlcmn *nl_cm;
+ uint32_t pid;
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlcrypto_family, info, NSS_NLCRYPTO_CMD_DESTROY_SESSION);
+ if (!nl_cm) {
+ nss_nl_error("unable to extract rule create data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlcrypto_rule, cm);
+ pid = nl_cm->pid;
+
+ destroy = &nl_rule->msg.destroy;
+
+ if (nss_crypto_get_cipher(destroy->session_idx) == NSS_CRYPTO_CIPHER_NONE) {
+ nss_nl_error("invalid session index, cipher unknown:%d\n", destroy->session_idx);
+ return -EINVAL;
+ }
+
+ if (nss_crypto_get_auth(destroy->session_idx) == NSS_CRYPTO_AUTH_NONE) {
+ nss_nl_error("invalid session index, auth unknown:%d\n", destroy->session_idx);
+ return -EINVAL;
+ }
+
+ status = nss_crypto_session_free(nss_nlcrypto_hdl, destroy->session_idx);
+ if (status != NSS_CRYPTO_STATUS_OK) {
+ nss_nl_error("unable to delete the session:%d\n", destroy->session_idx);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * @brief nss_nlcrypto_op_session_info()
+ * get session information
+ */
+static int nss_nlcrypto_op_session_info(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nss_nlcrypto_info_session *reply;
+ struct nss_nlcrypto_rule *nl_rule;
+ struct nss_nlcmn *nl_cm;
+ uint32_t session_idx;
+ struct sk_buff *resp;
+ uint32_t pid;
+
+ /*
+ * extract the message payload
+ */
+ nl_cm = nss_nl_get_msg(&nss_nlcrypto_family, info, NSS_NLCRYPTO_CMD_INFO_SESSION);
+ if (!nl_cm) {
+ nss_nl_error("unable to extract rule info data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Message validation required before accepting the configuration
+ */
+ nl_rule = container_of(nl_cm, struct nss_nlcrypto_rule, cm);
+ pid = nl_cm->pid;
+
+ /*
+ * since we need to populate the same information in the session_info
+ * we will reuse the op for response
+ */
+ session_idx = nl_rule->msg.info.session_idx;
+
+ /*
+ * copy the NL message for response
+ */
+ resp = nss_nl_copy_msg(skb);
+ if (!resp) {
+ nss_nl_error("%d:unable to save response data from NL buffer\n", pid);
+ return -ENOMEM;
+ }
+
+ /*
+ * overload the nl_rule with the new response address
+ */
+ nl_rule = nss_nl_get_data(resp);
+
+ /*
+ * Fill up the info message
+ */
+ reply = &nl_rule->msg.info;
+ memset(reply, 0, sizeof(struct nss_nlcrypto_info_session));
+
+ /*
+ * copy the info message
+ */
+ nss_crypto_copy_info(reply, session_idx);
+
+ /*
+ * unicast the response to user
+ */
+ nss_nl_ucast_resp(resp);
+ return 0;
+}
+/*
+ * @brief nss_nlcrypto_attach()
+ * crypto user attach
+ */
+nss_crypto_user_ctx_t nss_nlcrypto_attach(nss_crypto_handle_t crypto)
+{
+ gbl_ctx.crypto_hdl = crypto;
+
+ return (nss_crypto_user_ctx_t)&nss_nlcrypto_family;
+}
+
+/*
+ * @brief nss_nlcrypto_detach()
+ * crypto user detach; triggered by unregister
+ */
+void nss_nlcrypto_detach(nss_crypto_user_ctx_t ctx)
+{
+ gbl_ctx.crypto_hdl = NULL;
+}
+
+/*
+ * @brief nss_nlcrypto_init()
+ * handler init
+ */
+bool nss_nlcrypto_init(void)
+{
+ int status;
+
+ nss_nl_info_always("initiallizing the NSS netlink crypto handler\n");
+
+ /*
+ * register with the family
+ */
+ status = genl_register_family_with_ops(&nss_nlcrypto_family, nss_nlcrypto_ops, NSS_NLCRYPTO_OPS_SZ);
+ if (!status) {
+ return false;
+ }
+
+ nss_crypto_register_user(nss_nlcrypto_attach, nss_nlcrypto_detach, NSS_NLCRYPTO_FAMILY);
+
+ return true;
+}
+
+/*
+ * @brief nss_nlcrypto_exit()
+ * handler exit
+ */
+bool nss_nlcrypto_exit(void)
+{
+ int status;
+
+ nss_nl_info_always("Uninitializing the NSS netlink crypto handler\n");
+
+ /*
+ * unregister with the family
+ */
+ status = genl_unregister_family(&nss_nlcrypto_family);
+ if (status != 0) {
+ return false;
+ }
+
+ nss_crypto_unregister_user(nss_nlcrypto_hdl);
+
+ return true;
+}
diff --git a/netlink/nss_nlipv4.c b/netlink/nss_nlipv4.c
index fe1ce93..0608ab5 100755
--- a/netlink/nss_nlipv4.c
+++ b/netlink/nss_nlipv4.c
@@ -710,7 +710,7 @@
{
int error;
- nss_nl_info("Init NSS netlink ipv4 handler\n");
+ nss_nl_info_always("Init NSS netlink IPv4 handler\n");
/*
* register NETLINK ops with the family
@@ -760,7 +760,7 @@
{
int error;
- nss_nl_info("Exit NSS netlink iipv4 handler\n");
+ nss_nl_info_always("Exit NSS netlink IPv4 handler\n");
/*
* unregister the ops family