blob: 22a72e7943c9b783c61153fe34ace155fa5fdc20 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2023 MediaTek Inc.
*
* Author: Chris.Chou <chris.chou@mediatek.com>
* Ren-Ting Wang <ren-ting.wang@mediatek.com>
* Peter Wang <peterjy.wang@mediatek.com>
*/
#include <linux/bitops.h>
#include <mtk_eth_soc.h>
#include <mtk_hnat/hnat.h>
#include <mtk_hnat/nf_hnat_mtk.h>
#include <pce/cdrt.h>
#include <pce/cls.h>
#include <pce/netsys.h>
#include "crypto-eip/crypto-eip.h"
#include "crypto-eip/ddk-wrapper.h"
#include "crypto-eip/internal.h"
struct mtk_CDRT_DTLS_entry CDRT_DTLS_params;
struct DTLSResourceMgmt *dtls_table[CAPWAP_MAX_TUNNEL_NUM];
static int
mtk_setup_cdrt_dtls(struct cdrt_entry *cdrt_entry_p, enum cdrt_type type)
{
struct cdrt_desc *cdesc = &cdrt_entry_p->desc;
cdesc->desc1.dtls.pkt_len = 0;
cdesc->desc1.dtls.rsv1 = 0;
cdesc->desc1.dtls.capwap = 1;
if (type == CDRT_ENCRYPT)
cdesc->desc1.dtls.dir = 0;
else
cdesc->desc1.dtls.dir = 1;
cdesc->desc1.dtls.content_type = 3;
cdesc->desc1.dtls.type = 3;
cdesc->desc1.aad_len = 0;
cdesc->desc1.rsv1 = 0;
cdesc->desc1.app_id = 0;
cdesc->desc1.token_len = 0x30;
cdesc->desc1.rsv2 = 0;
cdesc->desc1.p_tr[0] = 0xfffffffc;
cdesc->desc1.p_tr[1] = 0xffffffff;
cdesc->desc2.usr = 0;
cdesc->desc2.rsv1 = 0;
cdesc->desc2.strip_pad = 1;
cdesc->desc2.allow_pad = 1;
cdesc->desc2.hw_srv = 0x28;
cdesc->desc2.rsv2 = 0;
cdesc->desc2.flow_lookup = 0;
cdesc->desc2.rsv3 = 0;
cdesc->desc2.ofs = 14;
cdesc->desc2.next_hdr = 0;
cdesc->desc2.fl = 0;
cdesc->desc2.ip4_chksum = 0;
if (type == CDRT_ENCRYPT)
cdesc->desc2.l4_chksum = 1;
else
cdesc->desc2.l4_chksum = 0;
cdesc->desc2.parse_eth = 0;
cdesc->desc2.keep_outer = 0;
cdesc->desc2.rsv4 = 0;
cdesc->desc2.rsv5[0] = 0;
cdesc->desc2.rsv5[1] = 0;
cdesc->desc3.option_meta[0] = 0x00000000;
cdesc->desc3.option_meta[1] = 0x00000000;
cdesc->desc3.option_meta[2] = 0x00000000;
cdesc->desc3.option_meta[3] = 0x00000000;
return mtk_pce_cdrt_entry_write(cdrt_entry_p);
}
static int
mtk_add_cdrt_dtls(enum cdrt_type type)
{
int ret = 0;
struct cdrt_entry *cdrt_entry_p = NULL;
cdrt_entry_p = mtk_pce_cdrt_entry_alloc(type);
if (cdrt_entry_p == NULL) {
CRYPTO_ERR("%s: mtk_pce_cdrt_entry_alloc failed!\n", __func__);
return 1;
}
ret = mtk_setup_cdrt_dtls(cdrt_entry_p, type);
if (ret)
goto free_cdrt;
if (type == CDRT_DECRYPT)
CDRT_DTLS_params.cdrt_inbound = cdrt_entry_p;
else
CDRT_DTLS_params.cdrt_outbound = cdrt_entry_p;
return ret;
free_cdrt:
mtk_pce_cdrt_entry_free(cdrt_entry_p);
return ret;
}
void
mtk_update_cdrt_idx(struct mtk_cdrt_idx_param *cdrt_idx_params_p)
{
cdrt_idx_params_p->cdrt_idx_inbound = CDRT_DTLS_params.cdrt_inbound->idx;
cdrt_idx_params_p->cdrt_idx_outbound = CDRT_DTLS_params.cdrt_outbound->idx;
}
void
mtk_dtls_capwap_init(void)
{
int i = 0;
// init cdrt for dtls
if (mtk_add_cdrt_dtls(CDRT_DECRYPT))
CRYPTO_ERR("%s: CDRT DECRYPT for DTLS init failed!\n", __func__);
if (mtk_add_cdrt_dtls(CDRT_ENCRYPT))
CRYPTO_ERR("%s: CDRT ENCRYPT for DTLS init failed!\n", __func__);
// add hook function for tops driver
#if defined(CONFIG_MTK_TOPS_CAPWAP_DTLS)
mtk_submit_SAparam_to_eip_driver = mtk_update_dtls_param;
mtk_remove_SAparam_to_eip_driver = mtk_remove_dtls_param;
mtk_update_cdrt_idx_from_eip_driver = mtk_update_cdrt_idx;
#endif
// init table as NULL
for (i = 0; i < CAPWAP_MAX_TUNNEL_NUM; i++)
dtls_table[i] = NULL;
}
void
mtk_dtls_capwap_deinit(void)
{
int i = 0;
// Loop and check if all SA in table are freed
for (i = 0; i < CAPWAP_MAX_TUNNEL_NUM; i++) {
if (dtls_table[i] != NULL) {
mtk_ddk_remove_dtls_param(dtls_table[i]);
kfree(dtls_table[i]);
dtls_table[i] = NULL;
}
}
if (CDRT_DTLS_params.cdrt_inbound != NULL)
mtk_pce_cdrt_entry_free(CDRT_DTLS_params.cdrt_inbound);
if (CDRT_DTLS_params.cdrt_outbound != NULL)
mtk_pce_cdrt_entry_free(CDRT_DTLS_params.cdrt_outbound);
#if defined(CONFIG_MTK_TOPS_CAPWAP_DTLS)
mtk_update_cdrt_idx_from_eip_driver = NULL;
mtk_submit_SAparam_to_eip_driver = NULL;
mtk_remove_SAparam_to_eip_driver = NULL;
#endif
}
void
mtk_update_dtls_param(struct DTLS_param *DTLSParam_p, int TnlIdx)
{
int ret;
if (dtls_table[TnlIdx]) {
CRYPTO_NOTICE("tnl_idx-%d- existed, will be removed first.\n", TnlIdx);
mtk_ddk_remove_dtls_param(dtls_table[TnlIdx]);
kfree(dtls_table[TnlIdx]);
dtls_table[TnlIdx] = NULL;
} else {
dtls_table[TnlIdx] = kmalloc(sizeof(struct DTLSResourceMgmt), GFP_KERNEL);
if (!dtls_table[TnlIdx]) {
CRYPTO_ERR("%s: kmalloc for dtls resource table failed\n", __func__);
return;
}
memset(dtls_table[TnlIdx], 0, sizeof(struct DTLSResourceMgmt));
}
/* Setup Transform Record for DTLS */
dtls_table[TnlIdx]->sa_out.p =
mtk_ddk_tr_capwap_dtls_build(true, DTLSParam_p, SAB_DIRECTION_OUTBOUND);
if (!dtls_table[TnlIdx]->sa_out.p) {
CRYPTO_ERR("%s: sa_out build failed\n", __func__);
kfree(dtls_table[TnlIdx]);
dtls_table[TnlIdx] = NULL;
return;
}
dtls_table[TnlIdx]->sa_in.p =
mtk_ddk_tr_capwap_dtls_build(true, DTLSParam_p, SAB_DIRECTION_INBOUND);
if (!dtls_table[TnlIdx]->sa_in.p) {
CRYPTO_ERR("%s: sa_in build failed\n", __func__);
goto failed;
}
/* Setup DTL Lookup */
ret = mtk_ddk_pcl_capwap_dtls_build(DTLSParam_p,
dtls_table[TnlIdx], SAB_DIRECTION_OUTBOUND);
if (ret < 0) {
CRYPTO_ERR("%s: PCL DTL Outbound Setup failed\n", __func__);
goto failed;
}
ret = mtk_ddk_pcl_capwap_dtls_build(DTLSParam_p,
dtls_table[TnlIdx], SAB_DIRECTION_INBOUND);
if (ret < 0) {
CRYPTO_ERR("%s: PCL DTL Inbound Setup failed\n", __func__);
mtk_ddk_remove_dtls_pcl(dtls_table[TnlIdx], SAB_DIRECTION_OUTBOUND);
goto failed;
}
DTLSParam_p->SA_encrypt = dtls_table[TnlIdx]->sa_out.p;
DTLSParam_p->SA_decrypt = dtls_table[TnlIdx]->sa_in.p;
return;
failed:
mtk_ddk_remove_dtls_sa(dtls_table[TnlIdx]);
kfree(dtls_table[TnlIdx]);
dtls_table[TnlIdx] = NULL;
return;
}
void mtk_remove_dtls_param(struct DTLS_param *DTLSParam_p, int TnlIdx)
{
CRYPTO_INFO("%s: Remove TnlIdx=%d\n", __func__, TnlIdx);
mtk_ddk_remove_dtls_param(dtls_table[TnlIdx]);
kfree(dtls_table[TnlIdx]);
dtls_table[TnlIdx] = NULL;
}