blob: 3285fc1021f92e28c17da29c81016556c31aee40 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2017-2020, 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 <crypto/skcipher.h>
#include <crypto/hash.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("%px: 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("%px: 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("%px: 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("%px: 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");