[][openwrt][mt7988][crypto][Refactor to unify EIP driver]

[Description]
Refactor to unify EIP driver.
1. Sync CAPWAP-DTLS functions for TOPS from neptune/eip_driver
2. Decoupled with hnat, IPSec inline mode is available even when hnat is
not activated now.

[Release-log]
N/A


Change-Id: Id53b483924fb90bc784570545b37e67e860a6024
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8868628
diff --git a/feed/kernel/crypto-eip/crypto-eip.mk b/feed/kernel/crypto-eip/crypto-eip.mk
index 31df9bd..9150cff 100644
--- a/feed/kernel/crypto-eip/crypto-eip.mk
+++ b/feed/kernel/crypto-eip/crypto-eip.mk
@@ -18,13 +18,19 @@
 ifeq ($(CONFIG_CRYPTO_OFFLOAD_INLINE),y)
 EXTRA_KCONFIG+= \
 	CONFIG_MTK_CRYPTO_EIP_INLINE=m \
-	CONFIG_CRYPTO_XFRM_OFFLOAD_MTK_PCE=$(CONFIG_CRYPTO_XFRM_OFFLOAD_MTK_PCE)
+	CONFIG_CRYPTO_XFRM_OFFLOAD_MTK_PCE=$(CONFIG_CRYPTO_XFRM_OFFLOAD_MTK_PCE) \
+	CONFIG_MTK_TOPS_CAPWAP_DTLS=$(CONFIG_MTK_TOPS_CAPWAP_DTLS)
 
 EXTRA_CFLAGS+= \
 	-I$(LINUX_DIR)/drivers/net/ethernet/mediatek/ \
 	-I$(KERNEL_BUILD_DIR)/pce/inc/
 endif
 
+ifeq ($(CONFIG_MTK_TOPS_CAPWAP_DTLS),y)
+EXTRA_CFLAGS += \
+	-DCONFIG_TOPS_TNL_NUM=$(CONFIG_TOPS_TNL_NUM)
+endif
+
 # crypto-eip kernel package configuration
 define KernelPackage/crypto-eip
   CATEGORY:=MTK Properties
@@ -72,7 +78,8 @@
 	@CRYPTO_OFFLOAD_INLINE \
 	kmod-crypto-eip \
 	kmod-crypto-eip-ddk \
-	+kmod-pce
+	+kmod-pce \
+	+MTK_TOPS_CAPWAP_DTLS:kmod-tops
   FILES:=$(PKG_BUILD_DIR)/crypto-eip-inline.ko
   $(call AddDepends/crypto)
 endef
diff --git a/feed/kernel/crypto-eip/src/Makefile b/feed/kernel/crypto-eip/src/Makefile
index d09ede3..77f6750 100644
--- a/feed/kernel/crypto-eip/src/Makefile
+++ b/feed/kernel/crypto-eip/src/Makefile
@@ -16,5 +16,6 @@
 crypto-eip-inline-y += lookaside-hash.o
 
 crypto-eip-inline-$(CONFIG_CRYPTO_XFRM_OFFLOAD_MTK_PCE) += xfrm-offload.o
+crypto-eip-inline-$(CONFIG_MTK_TOPS_CAPWAP_DTLS) += capwap-dtls-offload.o
 
 include $(wildcard $(src)/*.mk)
diff --git a/feed/kernel/crypto-eip/src/capwap-dtls-offload.c b/feed/kernel/crypto-eip/src/capwap-dtls-offload.c
new file mode 100644
index 0000000..5aef826
--- /dev/null
+++ b/feed/kernel/crypto-eip/src/capwap-dtls-offload.c
@@ -0,0 +1,184 @@
+// 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 *DTLSResourceTable[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++)
+		DTLSResourceTable[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 (DTLSResourceTable[i] != NULL)
+			mtk_ddk_remove_dtls_param(&DTLSResourceTable[i]);
+	}
+
+	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)
+{
+	char *TestName_p;
+
+	if (DTLSResourceTable[TnlIdx] != NULL) {
+		CRYPTO_NOTICE("tnl_idx-%d- existed, will be removed first.\n", TnlIdx);
+		mtk_ddk_remove_dtls_param(&DTLSResourceTable[TnlIdx]);
+	}
+
+	TestName_p = "Inline DTLS-CAPWAP SA setting";
+
+	if (mtk_capwap_dtls_offload(false, true, true, true, false, DTLSParam_p,
+								&DTLSResourceTable[TnlIdx]))
+		CRYPTO_INFO("%s DONE\n", TestName_p);
+	else
+		CRYPTO_ERR("%s: %s FAILED\n", __func__, TestName_p);
+}
+
+void mtk_remove_dtls_param(struct DTLS_param *DTLSParam_p, int TnlIdx)
+{
+	mtk_ddk_remove_dtls_param(&DTLSResourceTable[TnlIdx]);
+}
diff --git a/feed/kernel/crypto-eip/src/ddk-wrapper.c b/feed/kernel/crypto-eip/src/ddk-wrapper.c
index c07b2de..b3c5b90 100644
--- a/feed/kernel/crypto-eip/src/ddk-wrapper.c
+++ b/feed/kernel/crypto-eip/src/ddk-wrapper.c
@@ -2133,7 +2133,23 @@
 	PEC_Capabilities_t pec_cap;
 	PEC_Status_t pec_sta;
 	u32 i = MTK_EIP197_INLINE_NOF_TRIES;
+#ifdef PEC_PCL_EIP197
+	PCL_Status_t pcl_sta;
+#endif
 
+#ifdef PEC_PCL_EIP197
+	pcl_sta = PCL_Init(PCL_INTERFACE_ID, 1);
+	if (pcl_sta != PCL_STATUS_OK) {
+		CRYPTO_ERR("PCL could not be initialized, error=%d\n", pcl_sta);
+		return 0;
+	}
+
+	pcl_sta = PCL_DTL_Init(PCL_INTERFACE_ID);
+	if (pcl_sta != PCL_STATUS_OK) {
+		CRYPTO_ERR("PCL-DTL could not be initialized, error=%d\n", pcl_sta);
+		return -1;
+	}
+#endif
 	while (i) {
 		pec_sta = PEC_Init(PEC_INTERFACE_ID, &pec_init_blk);
 		if (pec_sta == PEC_STATUS_OK) {
@@ -2155,6 +2171,9 @@
 	pec_sta = PEC_Capabilities_Get(&pec_cap);
 	if (pec_sta != PEC_STATUS_OK) {
 		CRYPTO_ERR("PEC capability could not be obtained: %d\n", pec_sta);
+#ifdef PEC_PCL_EIP197
+		PCL_UnInit(PCL_INTERFACE_ID);
+#endif
 		return pec_sta;
 	}
 
@@ -2165,4 +2184,1144 @@
 
 void mtk_ddk_pec_deinit(void)
 {
+	unsigned int LoopCounter = MTK_EIP197_INLINE_NOF_TRIES;
+	PEC_Status_t PEC_Status;
+
+	while (LoopCounter > 0) {
+		PEC_Status = PEC_UnInit(PEC_INTERFACE_ID);
+		if (PEC_Status == PEC_STATUS_OK)
+			break;
+		else if (PEC_Status != PEC_STATUS_OK && PEC_Status != PEC_STATUS_BUSY) {
+			CRYPTO_ERR("PEC could not be un-initialized, error=%d\n", PEC_Status);
+			return;
+		}
+		// Wait for MTK_EIP197_INLINE_RETRY_DELAY_MS milliseconds
+		udelay(MTK_EIP197_INLINE_RETRY_DELAY_MS * 1000);
+		LoopCounter--;
+	}
+	// Check for timeout
+	if (LoopCounter == 0) {
+		CRYPTO_ERR("PEC could not be un-initialized, timeout\n");
+		return;
+	}
+
+#ifdef PEC_PCL_EIP197
+	PCL_DTL_UnInit(PCL_INTERFACE_ID);
+	PCL_UnInit(PCL_INTERFACE_ID);
+#endif
+}
+
+bool
+mtk_ddk_aes_block_encrypt(uint8_t *Key_p,
+							 unsigned int KeyByteCount,
+							 uint8_t *InData_p,
+							 uint8_t *OutData_p)
+{
+	int rc;
+	SABuilder_Params_t params;
+	SABuilder_Params_Basic_t ProtocolParams;
+	unsigned int SAWords = 0;
+
+	DMABuf_Status_t DMAStatus;
+	DMABuf_Properties_t DMAProperties = {0, 0, 0, 0};
+	DMABuf_HostAddress_t SAHostAddress;
+	DMABuf_HostAddress_t TokenHostAddress;
+	DMABuf_HostAddress_t PktHostAddress;
+
+	DMABuf_Handle_t SAHandle = {0};
+	DMABuf_Handle_t TokenHandle = {0};
+	DMABuf_Handle_t PktHandle = {0};
+
+	unsigned int TCRWords = 0;
+	void *TCRData = 0;
+	unsigned int TokenWords = 0;
+	unsigned int TokenHeaderWord;
+	unsigned int TokenMaxWords = 0;
+
+	TokenBuilder_Params_t TokenParams;
+	PEC_CommandDescriptor_t Cmd;
+	PEC_ResultDescriptor_t Res;
+	unsigned int count;
+
+	IOToken_Input_Dscr_t InTokenDscr;
+	IOToken_Output_Dscr_t OutTokenDscr;
+	uint32_t InputToken[IOTOKEN_IN_WORD_COUNT];
+	uint32_t OutputToken[IOTOKEN_OUT_WORD_COUNT];
+	IOToken_Output_Dscr_Ext_t OutTokenDscrExt;
+	IOToken_Input_Dscr_Ext_t InTokenDscrExt;
+
+	ZEROINIT(InTokenDscrExt);
+	ZEROINIT(OutTokenDscrExt);
+
+	ZEROINIT(InTokenDscr);
+	ZEROINIT(OutTokenDscr);
+
+	rc = SABuilder_Init_Basic(&params, &ProtocolParams, SAB_DIRECTION_OUTBOUND);
+	if (rc != 0) {
+		CRYPTO_ERR("SABuilder_Init_Basic failed\n");
+		goto error_exit;
+	}
+	// Add crypto key and parameters.
+	params.CryptoAlgo = SAB_CRYPTO_AES;
+	params.CryptoMode = SAB_CRYPTO_MODE_ECB;
+	params.KeyByteCount = KeyByteCount;
+	params.Key_p = Key_p;
+
+	rc = SABuilder_GetSizes(&params, &SAWords, NULL, NULL);
+
+	if (rc != 0) {
+		CRYPTO_ERR("SA not created because of errors\n");
+		goto error_exit;
+	}
+
+	DMAProperties.fCached   = true;
+	DMAProperties.Alignment = MTK_EIP197_INLINE_DMA_ALIGNMENT_BYTE_COUNT;
+	DMAProperties.Bank	    = MTK_EIP197_INLINE_BANK_TRANSFORM;
+	DMAProperties.Size	    = 4*SAWords;
+
+	DMAStatus = DMABuf_Alloc(DMAProperties, &SAHostAddress, &SAHandle);
+	if (DMAStatus != DMABUF_STATUS_OK) {
+		rc = 1;
+		CRYPTO_ERR("Allocation of SA failed\n");
+		goto error_exit;
+	}
+
+	rc = SABuilder_BuildSA(&params, (uint32_t *)SAHostAddress.p, NULL, NULL);
+
+	if (rc != 0) {
+		LOG_CRIT("SA not created because of errors\n");
+		goto error_exit;
+	}
+
+	rc = TokenBuilder_GetContextSize(&params, &TCRWords);
+
+	if (rc != 0) {
+		CRYPTO_ERR("TokenBuilder_GetContextSize returned errors\n");
+		goto error_exit;
+	}
+
+	// The Token Context Record does not need to be allocated
+	// in a DMA-safe buffer.
+	TCRData = kcalloc(4*TCRWords, sizeof(uint8_t), GFP_KERNEL);
+	if (!TCRData) {
+		rc = 1;
+		CRYPTO_ERR("Allocation of TCR failed\n");
+		goto error_exit;
+	}
+
+	rc = TokenBuilder_BuildContext(&params, TCRData);
+
+	if (rc != 0) {
+		CRYPTO_ERR("TokenBuilder_BuildContext failed\n");
+		goto error_exit;
+	}
+
+	rc = TokenBuilder_GetSize(TCRData, &TokenMaxWords);
+	if (rc != 0) {
+		CRYPTO_ERR("TokenBuilder_GetSize failed\n");
+		goto error_exit;
+	}
+
+	// Allocate one buffer for the token and two packet buffers.
+
+	DMAProperties.fCached   = true;
+	DMAProperties.Alignment = MTK_EIP197_INLINE_DMA_ALIGNMENT_BYTE_COUNT;
+	DMAProperties.Bank      = MTK_EIP197_INLINE_BANK_PACKET;
+	DMAProperties.Size      = 4*TokenMaxWords;
+
+	DMAStatus = DMABuf_Alloc(DMAProperties, &TokenHostAddress, &TokenHandle);
+	if (DMAStatus != DMABUF_STATUS_OK) {
+		rc = 1;
+		CRYPTO_ERR("Allocation of token buffer failed.\n");
+		goto error_exit;
+	}
+
+	DMAProperties.fCached   = true;
+	DMAProperties.Alignment = MTK_EIP197_INLINE_DMA_ALIGNMENT_BYTE_COUNT;
+	DMAProperties.Bank      = MTK_EIP197_INLINE_BANK_PACKET;
+	DMAProperties.Size      = 16;
+
+	DMAStatus = DMABuf_Alloc(DMAProperties, &PktHostAddress,
+							 &PktHandle);
+	if (DMAStatus != DMABUF_STATUS_OK) {
+		rc = 1;
+		CRYPTO_ERR("Allocation of source packet buffer failed.\n");
+		goto error_exit;
+	}
+
+	// Register the SA
+	rc = PEC_SA_Register(PEC_INTERFACE_ID, SAHandle, DMABuf_NULLHandle,
+					  DMABuf_NULLHandle);
+	if (rc != PEC_STATUS_OK) {
+		CRYPTO_ERR("PEC_SA_Register failed\n");
+		goto error_exit;
+	}
+
+	// Copy input packet into source packet buffer.
+	memcpy(PktHostAddress.p, InData_p, 16);
+
+	// Set Token Parameters if specified in test vector.
+	ZEROINIT(TokenParams);
+
+
+	// Prepare a token to process the packet.
+	rc = TokenBuilder_BuildToken(TCRData,
+								 (uint8_t *)PktHostAddress.p,
+								 16,
+								 &TokenParams,
+								 (uint32_t *)TokenHostAddress.p,
+								 &TokenWords,
+								 &TokenHeaderWord);
+	if (rc != TKB_STATUS_OK) {
+		if (rc == TKB_BAD_PACKET)
+			CRYPTO_ERR("Token not created because packet size is invalid\n");
+		else
+			CRYPTO_ERR("Token builder failed\n");
+		goto error_exit_unregister;
+	}
+
+	ZEROINIT(Cmd);
+	Cmd.Token_Handle = TokenHandle;
+	Cmd.Token_WordCount = TokenWords;
+	Cmd.SrcPkt_Handle = PktHandle;
+	Cmd.SrcPkt_ByteCount = 16;
+	Cmd.DstPkt_Handle = PktHandle;
+	Cmd.SA_Handle1 = SAHandle;
+	Cmd.SA_Handle2 = DMABuf_NULLHandle;
+
+	InTokenDscrExt.HW_Services  = IOTOKEN_CMD_PKT_LAC;
+	InTokenDscr.TknHdrWordInit = TokenHeaderWord;
+
+	if (!crypto_iotoken_create(&InTokenDscr,
+							   &InTokenDscrExt,
+							   InputToken,
+							   &Cmd)) {
+		rc = 1;
+		goto error_exit_unregister;
+	}
+
+	rc = PEC_Packet_Put(PEC_INTERFACE_ID,
+						&Cmd,
+						1,
+						&count);
+	if (rc != PEC_STATUS_OK && count != 1) {
+		rc = 1;
+		CRYPTO_ERR("PEC_Packet_Put error\n");
+		goto error_exit_unregister;
+	}
+
+	if (crypto_pe_busy_get_one(&OutTokenDscr, OutputToken, &Res) < 1) {
+		rc = 1;
+		CRYPTO_ERR("error from crypto_pe_busy_get_one\n");
+		goto error_exit_unregister;
+	}
+	memcpy(OutData_p, PktHostAddress.p, 16);
+
+
+error_exit_unregister:
+	PEC_SA_UnRegister(PEC_INTERFACE_ID, SAHandle, DMABuf_NULLHandle,
+					  DMABuf_NULLHandle);
+
+error_exit:
+	DMABuf_Release(SAHandle);
+	DMABuf_Release(TokenHandle);
+	DMABuf_Release(PktHandle);
+
+	if (TCRData != NULL)
+		kfree(TCRData);
+
+	return rc == 0;
+
+}
+
+bool
+mtk_ddk_invalidate_rec(
+		const DMABuf_Handle_t Rec_p,
+		const bool IsTransform)
+{
+	PEC_Status_t PEC_Rc;
+	PEC_CommandDescriptor_t Cmd;
+	PEC_ResultDescriptor_t Res;
+	unsigned int count;
+	IOToken_Input_Dscr_t InTokenDscr;
+	IOToken_Output_Dscr_t OutTokenDscr;
+	uint32_t InputToken[IOTOKEN_IN_WORD_COUNT_IL];
+	uint32_t OutputToken[IOTOKEN_OUT_WORD_COUNT_IL];
+	void *InTokenDscrExt_p = NULL;
+	void *OutTokenDscrExt_p = NULL;
+	IOToken_Input_Dscr_Ext_t InTokenDscrExt;
+	IOToken_Output_Dscr_Ext_t OutTokenDscrExt;
+
+	ZEROINIT(InTokenDscrExt);
+	InTokenDscrExt_p = &InTokenDscrExt;
+	OutTokenDscrExt_p = &OutTokenDscrExt;
+
+	ZEROINIT(InTokenDscr);
+
+	// Fill in the command descriptor for the Invalidate command
+	ZEROINIT(Cmd);
+
+	Cmd.SrcPkt_Handle    = DMABuf_NULLHandle;
+	Cmd.DstPkt_Handle    = DMABuf_NULLHandle;
+	Cmd.SA_Handle1       = Rec_p;
+	Cmd.SA_Handle2       = DMABuf_NULLHandle;
+	Cmd.Token_Handle     = DMABuf_NULLHandle;
+	Cmd.SrcPkt_ByteCount = 0;
+
+#if defined(IOTOKEN_USE_HW_SERVICE)
+	if (IsTransform)
+		InTokenDscrExt.HW_Services = IOTOKEN_CMD_INV_TR;
+	else
+		InTokenDscrExt.HW_Services = IOTOKEN_CMD_INV_FR;
+#endif
+
+	if (!crypto_iotoken_create(&InTokenDscr, InTokenDscrExt_p, InputToken, &Cmd))
+		return false;
+
+	// Issue command
+	PEC_Rc = PEC_Packet_Put(PEC_INTERFACE_ID,
+							&Cmd,
+							1,
+							&count);
+	if (PEC_Rc != PEC_STATUS_OK || count != 1) {
+		CRYPTO_ERR("%s: PEC_Packet_Put() error %d, count %d\n",
+				 __func__,
+				 PEC_Rc,
+				 count);
+		return false;
+	}
+
+	// Receive the result packet ... do we care about contents ?
+	if (crypto_pe_busy_get_one(&OutTokenDscr, OutputToken, &Res) < 1) {
+		CRYPTO_ERR("%s: crypto_pe_busy_get_one() failed\n", __func__);
+		return false;
+	}
+
+	return true;
+}
+
+bool mtk_capwap_dtls_offload(
+		const bool fVerbose,
+		const bool fCAPWAP,
+		const bool fPktCfy,
+		const bool fInline,
+		const bool fContinuousScatter,
+		struct DTLS_param *DTLSParam_p,
+		struct DTLSResourceMgmt **DTLSResource)
+{
+	bool success = false;
+	SABuilder_Status_t SAStatus;
+	SABuilder_Params_t params;
+	SABuilder_Params_SSLTLS_t SSLTLSParams;
+	uint8_t Offset;
+	uint16_t DTLSVersion;
+	uint32_t SAWords = 0;
+	bool fInlinePlain, fInlineCipher;
+
+	DMABuf_Status_t DMAStatus;
+	DMABuf_Properties_t DMAProperties = {0, 0, 0, 0};
+	DMABuf_HostAddress_t SAHostAddress;
+
+	static uint8_t Zero[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	uint8_t *InboundHKey = NULL;
+	uint8_t *OutboundHKey = NULL;
+	uint8_t *InnerDigest = NULL;
+	uint8_t *OuterDigest = NULL;
+
+	PCL_Status_t PCL_Status;
+	PCL_SelectorParams_t SelectorParams;
+	PCL_DTL_TransformParams_t DTLTransformParams;
+	PCL_TransformParams_t TransformParams;
+	PCL_DTL_Hash_Handle_t SAHashHandle;
+
+
+	struct DTLSResourceMgmt *DTLSResourceEntity_p = NULL;
+
+	DTLSResourceEntity_p = kmalloc(sizeof(struct DTLSResourceMgmt), GFP_KERNEL);
+	if (DTLSResourceEntity_p == NULL) {
+		CRYPTO_ERR("%s: kmalloc for DTLSResourceEntity failed\n", __func__);
+		goto error_exit;
+	}
+	memset(DTLSResourceEntity_p, 0, sizeof(struct DTLSResourceMgmt));
+
+	if (fCAPWAP)
+		CRYPTO_INFO("Preparing Transforms and DTL for DTLS-CAPWAP\n");
+	else
+		CRYPTO_INFO("Preparing Transforms and DTL for DTLS\n");
+
+	if (fVerbose)
+		CRYPTO_INFO("*** fVerbose Preparing Transforms and DTL ***\n\n");
+
+	Offset = 14;
+
+	if (fInline) {
+		if (fContinuousScatter) {
+			/* inline + continuous scatter:
+			   Redirect outbound packets ring->inline
+			   Redirect inbound packets inline->ring
+			 */
+			fInlinePlain = false;
+			fInlineCipher = true;
+		} else {
+			fInlinePlain = true;
+			fInlineCipher = true;
+		}
+	} else {
+		fInlinePlain = false;
+		fInlineCipher = false;
+	}
+
+	// Prepare the Outbound SA
+	if (DTLSParam_p->dtls_version == MTK_DTLS_VERSION_1_0)
+		DTLSVersion = SAB_DTLS_VERSION_1_0;
+	else if (DTLSParam_p->dtls_version == MTK_DTLS_VERSION_1_2)
+		DTLSVersion = SAB_DTLS_VERSION_1_2;
+	else {
+		CRYPTO_ERR("%s: Unknown DTLSParam_p->dtls_version: %u\n", __func__,
+					DTLSParam_p->dtls_version);
+		goto error_exit;
+	}
+
+	// Initialize the SA parameters for ESP.The call to SABuilder_Init_ESP
+	// will initialize many parameters, next fill in more parameters, such
+	// as cryptographic keys.
+	SAStatus = SABuilder_Init_SSLTLS(&params,
+								   &SSLTLSParams,
+								   DTLSVersion,
+								   SAB_DIRECTION_OUTBOUND);
+	if (SAStatus != SAB_STATUS_OK) {
+		CRYPTO_ERR("%s: SABuilder_Init_ESP failed\n", __func__);
+		goto error_exit;
+	}
+
+	/* Set DTLS-CAPWAP param from cmd handler */
+	if (DTLSParam_p->sec_mode == AES128_CBC_HMAC_SHA1) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_CBC;
+		params.KeyByteCount = 16;
+		params.AuthAlgo = SAB_AUTH_HMAC_SHA1;
+		params.AuthKeyByteCount = 20;
+	} else if (DTLSParam_p->sec_mode == AES128_CBC_HMAC_SHA2_256) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_CBC;
+		params.KeyByteCount = 16;
+		params.AuthAlgo = SAB_AUTH_HMAC_SHA2_256;
+		params.AuthKeyByteCount = 32;
+	} else if (DTLSParam_p->sec_mode == AES256_CBC_HMAC_SHA1) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_CBC;
+		params.KeyByteCount = 32;
+		params.AuthAlgo = SAB_AUTH_HMAC_SHA1;
+		params.AuthKeyByteCount = 20;
+	} else if (DTLSParam_p->sec_mode == AES256_CBC_HMAC_SHA2_256) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_CBC;
+		params.KeyByteCount = 32;
+		params.AuthAlgo = SAB_AUTH_HMAC_SHA2_256;
+		params.AuthKeyByteCount = 32;
+	} else if (DTLSParam_p->sec_mode == AES128_GCM || DTLSParam_p->sec_mode == AES256_GCM) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_GCM;
+		params.AuthAlgo = SAB_AUTH_AES_GCM;
+		if (DTLSParam_p->sec_mode == AES128_GCM)
+			params.KeyByteCount = 16;
+		else if (DTLSParam_p->sec_mode == AES256_GCM)
+			params.KeyByteCount = 32;
+
+		params.Nonce_p = DTLSParam_p->dtls_encrypt_nonce;
+
+		OutboundHKey = kcalloc(16, sizeof(uint8_t), GFP_KERNEL);
+		if (OutboundHKey == NULL) {
+			CRYPTO_ERR("%s: kmalloc for OutboundHKey failed\n", __func__);
+			goto error_exit;
+		}
+
+		mtk_ddk_aes_block_encrypt(DTLSParam_p->key_encrypt, 16, Zero, OutboundHKey);
+		if (fVerbose)
+			Log_HexDump("OutboundHKey", 0, OutboundHKey, 16);
+		// Byte-swap the HKEY
+		{
+			uint8_t t;
+			unsigned int i;
+
+			for (i = 0; i < 4; i++) {
+				t = OutboundHKey[4*i+3];
+				OutboundHKey[4*i+3] = OutboundHKey[4*i];
+				OutboundHKey[4*i] = t;
+				t = OutboundHKey[4*i+2];
+				OutboundHKey[4*i+2] = OutboundHKey[4*i+1];
+				OutboundHKey[4*i+1] = t;
+			}
+		}
+		if (fVerbose)
+			Log_HexDump("OutboundHKey (swapped)", 0, OutboundHKey, 16);
+		params.AuthKey1_p = OutboundHKey;
+		DTLSResourceEntity_p->HKeyOutbound = OutboundHKey;
+	} else {
+		CRYPTO_ERR("%s: Unknown DTLSParam_p->sec_mode: %u\n", __func__,
+					DTLSParam_p->sec_mode);
+		goto error_exit;
+	}
+	// Add crypto key and parameters.
+	params.Key_p = DTLSParam_p->key_encrypt;
+	// Add authentication key and paramters.
+	if (params.AuthAlgo == SAB_AUTH_HMAC_SHA1 || params.AuthAlgo == SAB_AUTH_HMAC_SHA2_256) {
+#ifdef EIP197_INLINE_HMAC_DIGEST_PRECOMPUTE
+		params.AuthKey1_p = DTLSParam_p->key_auth_encrypt_1; // inner digest directly
+		params.AuthKey2_p = DTLSParam_p->key_auth_encrypt_2; // outer digest directly
+#else
+		// No hardware precompute support, so preform HMAC precompute in
+		// the traditional way.
+		InnerDigest = kcalloc((size_t)params.AuthKeyByteCount, sizeof(uint8_t), GFP_KERNEL);
+		if (InnerDigest == NULL) {
+			CRYPTO_ERR("%s: kmalloc for InnerDigest failed\n", __func__);
+			goto error_exit;
+		}
+		memset(InnerDigest, 0, params.AuthKeyByteCount);
+		DTLSResourceEntity_p->InnerDigestOutbound = InnerDigest;
+		OuterDigest = kcalloc((size_t)params.AuthKeyByteCount, sizeof(uint8_t), GFP_KERNEL);
+		if (OuterDigest == NULL) {
+			CRYPTO_ERR("%s: kmalloc for OuterDigest failed\n", __func__);
+			goto error_exit;
+		}
+		memset(OuterDigest, 0, params.AuthKeyByteCount);
+		DTLSResourceEntity_p->OuterDigestOutbound = OuterDigest;
+		crypto_hmac_precompute(params.AuthAlgo,
+							   DTLSParam_p->key_auth_encrypt_1,
+							   params.AuthKeyByteCount,
+							   InnerDigest,
+							   OuterDigest);
+		if (fVerbose) {
+			Log_HexDump("Inner Digest", 0, InnerDigest, params.AuthKeyByteCount);
+			Log_HexDump("Outer Digest", 0, OuterDigest, params.AuthKeyByteCount);
+		}
+		params.AuthKey1_p = InnerDigest;
+		params.AuthKey2_p = OuterDigest;
+		InnerDigest = NULL;
+		OuterDigest = NULL;
+#endif
+	}
+
+	// Create a reference to the header processor context.
+	SSLTLSParams.epoch = DTLSParam_p->dtls_epoch;
+
+	SSLTLSParams.SSLTLSFlags |= SAB_DTLS_PROCESS_IP_HEADERS |
+					SAB_DTLS_EXT_PROCESSING | SAB_DTLS_IPV4;
+	if (fCAPWAP)
+		SSLTLSParams.SSLTLSFlags |= SAB_DTLS_CAPWAP;
+
+	// Now the SA parameters are completely filled in.
+
+	// We are ready to probe the size required for the transform
+	// record (SA).
+	SAStatus = SABuilder_GetSizes(&params, &SAWords, NULL, NULL);
+
+	if (fVerbose)
+		CRYPTO_INFO(
+			"%s: SABuilder_GetSizes returned %d SA size=%u words for outbound\n",
+			__func__,
+			SAStatus,
+			SAWords);
+	if (SAStatus != SAB_STATUS_OK) {
+		CRYPTO_ERR("%s: SA not created because of errors\n", __func__);
+		goto error_exit;
+	}
+
+	// Allocate a DMA-safe buffer for the SA.
+	DMAProperties.fCached   = true;
+	DMAProperties.Alignment = MTK_EIP197_INLINE_DMA_ALIGNMENT_BYTE_COUNT;
+	DMAProperties.Bank	  = MTK_EIP197_INLINE_BANK_TRANSFORM;
+	DMAProperties.Size	  = SAWords * sizeof(uint32_t);
+
+	DMAStatus = DMABuf_Alloc(DMAProperties, &SAHostAddress,
+						&DTLSResourceEntity_p->DTLSHandleSAOutbound);
+	if (DMAStatus != DMABUF_STATUS_OK || DTLSResourceEntity_p->DTLSHandleSAOutbound.p == NULL) {
+		CRYPTO_ERR("%s Allocation of outbound SA failed\n", __func__);
+		goto error_exit;
+	}
+
+	// Now we can actually build the SA in the DMA-safe buffer.
+	SAStatus = SABuilder_BuildSA(&params, (uint32_t *)SAHostAddress.p, NULL, NULL);
+
+	if (SAStatus != SAB_STATUS_OK) {
+		CRYPTO_ERR("%s: SA not created because of errors\n", __func__);
+		goto error_exit;
+	}
+	if (fVerbose) {
+		CRYPTO_INFO("Outbound transform record created\n");
+
+		Log_HexDump("Outbound transform record",
+					0,
+					SAHostAddress.p,
+					SAWords * sizeof(uint32_t));
+	}
+
+	// Prepare the Inbound SA
+	if (DTLSParam_p->dtls_version == MTK_DTLS_VERSION_1_0)
+		DTLSVersion = SAB_DTLS_VERSION_1_0;
+	else if (DTLSParam_p->dtls_version == MTK_DTLS_VERSION_1_2)
+		DTLSVersion = SAB_DTLS_VERSION_1_2;
+	else {
+		CRYPTO_ERR("%s: Unknown DTLSParam_p->dtls_version: %u\n", __func__,
+					DTLSParam_p->dtls_version);
+		goto error_exit;
+	}
+
+	// Initialize the SA parameters for ESP.The call to SABuilder_Init_ESP
+	// will initialize many parameters, next fill in more parameters, such
+	// as cryptographic keys.
+	SAStatus = SABuilder_Init_SSLTLS(&params,
+								   &SSLTLSParams,
+								   DTLSVersion,
+								   SAB_DIRECTION_INBOUND);
+	if (SAStatus != SAB_STATUS_OK) {
+		CRYPTO_ERR("%s: SABuilder_Init_ESP failed\n", __func__);
+		goto error_exit;
+	}
+
+	/* Set DTLS-CAPWAP param from cmd handler */
+	if (DTLSParam_p->sec_mode == AES128_CBC_HMAC_SHA1) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_CBC;
+		params.KeyByteCount = 16;
+		params.AuthAlgo = SAB_AUTH_HMAC_SHA1;
+		params.AuthKeyByteCount = 20;
+	} else if (DTLSParam_p->sec_mode == AES128_CBC_HMAC_SHA2_256) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_CBC;
+		params.KeyByteCount = 16;
+		params.AuthAlgo = SAB_AUTH_HMAC_SHA2_256;
+		params.AuthKeyByteCount = 32;
+	} else if (DTLSParam_p->sec_mode == AES256_CBC_HMAC_SHA1) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_CBC;
+		params.KeyByteCount = 32;
+		params.AuthAlgo = SAB_AUTH_HMAC_SHA1;
+		params.AuthKeyByteCount = 20;
+	} else if (DTLSParam_p->sec_mode == AES256_CBC_HMAC_SHA2_256) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_CBC;
+		params.KeyByteCount = 32;
+		params.AuthAlgo = SAB_AUTH_HMAC_SHA2_256;
+		params.AuthKeyByteCount = 32;
+	} else if (DTLSParam_p->sec_mode == AES128_GCM || DTLSParam_p->sec_mode == AES256_GCM) {
+		params.CryptoAlgo = SAB_CRYPTO_AES;
+		params.CryptoMode = SAB_CRYPTO_MODE_GCM;
+		params.AuthAlgo = SAB_AUTH_AES_GCM;
+		if (DTLSParam_p->sec_mode == AES128_GCM)
+			params.KeyByteCount = 16;
+		else if (DTLSParam_p->sec_mode == AES256_GCM)
+			params.KeyByteCount = 32;
+
+		params.Nonce_p = DTLSParam_p->dtls_decrypt_nonce;
+
+		InboundHKey = kcalloc(16, sizeof(uint8_t), GFP_KERNEL);
+		if (InboundHKey == NULL) {
+			CRYPTO_ERR("%s: kmalloc for InboundHKey failed\n", __func__);
+			goto error_exit;
+		}
+
+		mtk_ddk_aes_block_encrypt(DTLSParam_p->key_decrypt, 16, Zero, InboundHKey);
+		if (fVerbose)
+			Log_HexDump("InboundHKey", 0, InboundHKey, 16);
+		// Byte-swap the HKEY
+		{
+			uint8_t t;
+			unsigned int i;
+
+			for (i = 0; i < 4; i++) {
+				t = InboundHKey[4*i+3];
+				InboundHKey[4*i+3] = InboundHKey[4*i];
+				InboundHKey[4*i] = t;
+				t = InboundHKey[4*i+2];
+				InboundHKey[4*i+2] = InboundHKey[4*i+1];
+				InboundHKey[4*i+1] = t;
+			}
+		}
+		if (fVerbose)
+			Log_HexDump("InboundHKey (swapped)", 0, InboundHKey, 16);
+		params.AuthKey1_p = InboundHKey;
+		DTLSResourceEntity_p->HKeyInbound = InboundHKey;
+	} else {
+		CRYPTO_ERR("%s: Unknown DTLSParam_p->sec_mode: %u\n", __func__,
+					DTLSParam_p->sec_mode);
+		goto error_exit;
+	}
+
+	// Add crypto key and parameters.
+	params.Key_p = DTLSParam_p->key_decrypt;
+	// Add authentication key and paramters.
+	if (params.AuthAlgo == SAB_AUTH_HMAC_SHA1 || params.AuthAlgo == SAB_AUTH_HMAC_SHA2_256) {
+#ifdef EIP197_INLINE_HMAC_DIGEST_PRECOMPUTE
+		params.AuthKey1_p = DTLSParam_p->key_auth_decrypt_1;
+		params.AuthKey2_p = DTLSParam_p->key_auth_decrypt_2;
+#else
+		// No hardware precompute support, so preform HMAC precompute in
+		// the traditional way.
+		InnerDigest = kcalloc(params.AuthKeyByteCount, sizeof(uint8_t), GFP_KERNEL);
+		if (InnerDigest == NULL) {
+			CRYPTO_ERR("%s: kmalloc for InnerDigest failed\n", __func__);
+			goto error_exit;
+		}
+		memset(InnerDigest, 0, params.AuthKeyByteCount);
+		DTLSResourceEntity_p->InnerDigestInbound = InnerDigest;
+		OuterDigest = kcalloc(params.AuthKeyByteCount, sizeof(uint8_t), GFP_KERNEL);
+		if (OuterDigest == NULL) {
+			CRYPTO_ERR("%s: kmalloc for OuterDigest failed\n", __func__);
+			goto error_exit;
+		}
+		memset(OuterDigest, 0, params.AuthKeyByteCount);
+		DTLSResourceEntity_p->OuterDigestInbound = OuterDigest;
+		crypto_hmac_precompute(params.AuthAlgo,
+							   DTLSParam_p->key_auth_decrypt_1,
+							   params.AuthKeyByteCount,
+							   InnerDigest,
+							   OuterDigest);
+		if (fVerbose) {
+			Log_HexDump("Inner Digest", 0, InnerDigest, params.AuthKeyByteCount);
+			Log_HexDump("Outer Digest", 0, OuterDigest, params.AuthKeyByteCount);
+		}
+		params.AuthKey1_p = InnerDigest;
+		params.AuthKey2_p = OuterDigest;
+		InnerDigest = NULL;
+		OuterDigest = NULL;
+	}
+#endif
+
+	if (fInlinePlain != fInlineCipher) {
+		params.flags |= SAB_FLAG_REDIRECT;
+		params.RedirectInterface = PEC_INTERFACE_ID; /*redirect to ring */
+	}
+
+	SSLTLSParams.SSLTLSFlags |= SAB_DTLS_PROCESS_IP_HEADERS |
+						SAB_DTLS_EXT_PROCESSING | SAB_DTLS_IPV4;
+
+	// Create a reference to the header processor context.
+	SSLTLSParams.epoch = DTLSParam_p->dtls_epoch;
+
+	if (fCAPWAP)
+		SSLTLSParams.SSLTLSFlags |= SAB_DTLS_CAPWAP;
+
+	// Now the SA parameters are completely filled in.
+
+	// We are ready to probe the size required for the transform
+	// record (SA).
+	SAStatus = SABuilder_GetSizes(&params, &SAWords, NULL, NULL);
+
+	if (fVerbose)
+		CRYPTO_INFO("%s: SABuilder_GetSizes returned %d SA size=%u words for inbound\n",
+				 __func__,
+				 SAStatus,
+				 SAWords);
+
+	if (SAStatus != SAB_STATUS_OK) {
+		CRYPTO_ERR("%s: SA not created because of errors\n", __func__);
+		goto error_exit;
+	}
+
+	// Allocate a DMA-safe buffer for the SA.
+	DMAProperties.fCached   = true;
+	DMAProperties.Alignment = MTK_EIP197_INLINE_DMA_ALIGNMENT_BYTE_COUNT;
+	DMAProperties.Bank	  = MTK_EIP197_INLINE_BANK_TRANSFORM;
+	DMAProperties.Size	  = SAWords * sizeof(uint32_t);
+
+	DMAStatus = DMABuf_Alloc(DMAProperties, &SAHostAddress,
+							&DTLSResourceEntity_p->DTLSHandleSAInbound);
+	if (DMAStatus != DMABUF_STATUS_OK || DTLSResourceEntity_p->DTLSHandleSAInbound.p == NULL) {
+		CRYPTO_ERR("%s: Allocation of inbound SA failed\n", __func__);
+		goto error_exit;
+	}
+
+	// Now we can actually build the SA in the DMA-safe buffer.
+	SAStatus = SABuilder_BuildSA(&params, (uint32_t *)SAHostAddress.p, NULL, NULL);
+	if (SAStatus != SAB_STATUS_OK) {
+		CRYPTO_ERR("%s: SA not created because of errors\n", __func__);
+		goto error_exit;
+	}
+	if (fVerbose) {
+		CRYPTO_INFO("Inbound transform record created\n");
+
+		Log_HexDump("Inbound transform record",
+					0,
+					SAHostAddress.p,
+					SAWords * sizeof(uint32_t));
+	}
+
+	// Register the SAs with the PCL API. DMA buffers for hardware transforms
+	// (SAs) are allocated and filled in external to the PCL API.
+	PCL_Status = PCL_Transform_Register(DTLSResourceEntity_p->DTLSHandleSAOutbound);
+	if (PCL_Status != PCL_STATUS_OK) {
+		CRYPTO_ERR("%s: PCL_Transform_Register failed\n", __func__);
+		goto error_exit;
+	}
+	if (fVerbose)
+		CRYPTO_INFO("%s: Outbound transform registered\n", __func__);
+
+	PCL_Status = PCL_Transform_Register(DTLSResourceEntity_p->DTLSHandleSAInbound);
+	if (PCL_Status != PCL_STATUS_OK) {
+		CRYPTO_ERR("%s: PCL_Transform_Register failed\n", __func__);
+		PCL_Transform_UnRegister(DTLSResourceEntity_p->DTLSHandleSAOutbound);
+		goto error_exit;
+	}
+	if (fVerbose)
+		CRYPTO_INFO("%s: Inbound transform registered\n", __func__);
+
+
+
+	/* Create the DTL entries.  */
+	if (fPktCfy) {
+		ZEROINIT(SelectorParams);
+		ZEROINIT(DTLTransformParams);
+
+		SelectorParams.flags = PCL_SELECT_IPV4;
+		SelectorParams.SrcIp = ((unsigned char *)(&(DTLSParam_p->sip)));
+		SelectorParams.DstIp = ((unsigned char *)(&(DTLSParam_p->dip)));
+		SelectorParams.IpProto = 17; //UDP
+		SelectorParams.SrcPort = DTLSParam_p->sport;
+		SelectorParams.DstPort = DTLSParam_p->dport;
+		SelectorParams.spi = 0;
+		SelectorParams.epoch = 0; // No epoch, not present in outbound packet
+
+		/* Compute the hash for the inbound DTL */
+		PCL_Status = PCL_Flow_Hash(&SelectorParams, DTLTransformParams.HashID);
+		if (PCL_Status != PCL_STATUS_OK) {
+			CRYPTO_ERR("%s: PEC_Flow_Hash failed\n", __func__);
+			goto error_exit_unregister;
+		}
+		if (fVerbose)
+			CRYPTO_INFO("%s: Inbound flow hashed\n", __func__);
+
+		/* Add the inbound DTL entry. */
+		PCL_Status = PCL_DTL_Transform_Add(PCL_INTERFACE_ID, 0,
+							&DTLTransformParams,
+							DTLSResourceEntity_p->DTLSHandleSAOutbound,
+							&SAHashHandle);
+		if (PCL_Status != PCL_STATUS_OK) {
+			CRYPTO_ERR("%s: PEC_DTL_Transform_Add failed\n", __func__);
+			goto error_exit_unregister;
+		}
+		if (fVerbose)
+			CRYPTO_INFO("%s: Outbound DTL added\n", __func__);
+
+		ZEROINIT(SelectorParams);
+		ZEROINIT(DTLTransformParams);
+
+		SelectorParams.flags = PCL_SELECT_IPV4;
+		SelectorParams.DstIp = ((unsigned char *)(&(DTLSParam_p->sip)));
+		SelectorParams.SrcIp = ((unsigned char *)(&(DTLSParam_p->dip)));
+		SelectorParams.SrcPort = DTLSParam_p->dport;
+		SelectorParams.DstPort = DTLSParam_p->sport;
+		SelectorParams.IpProto = 17; //UDP
+		SelectorParams.epoch = DTLSParam_p->dtls_epoch;
+
+		/* Compute the hash for the inbound DTL */
+		PCL_Status = PCL_Flow_Hash(&SelectorParams, DTLTransformParams.HashID);
+		if (PCL_Status != PCL_STATUS_OK) {
+			CRYPTO_ERR("%s: PEC_Flow_Hash failed\n", __func__);
+			PCL_DTL_Transform_Remove(PCL_INTERFACE_ID, 0,
+							DTLSResourceEntity_p->DTLSHandleSAOutbound);
+			goto error_exit_unregister;
+		}
+		if (fVerbose)
+			CRYPTO_INFO("%s: Inbound lookup hashed\n", __func__);
+
+		/* Add the inbound DTL entry. */
+		PCL_Status = PCL_DTL_Transform_Add(PCL_INTERFACE_ID, 0,
+						&DTLTransformParams,
+						DTLSResourceEntity_p->DTLSHandleSAInbound,
+						&SAHashHandle);
+		if (PCL_Status != PCL_STATUS_OK) {
+			CRYPTO_ERR("%s: PEC_DTL_Transform_Add failed\n", __func__);
+			PCL_DTL_Transform_Remove(PCL_INTERFACE_ID, 0,
+							DTLSResourceEntity_p->DTLSHandleSAOutbound);
+			goto error_exit_unregister;
+		}
+		if (fVerbose)
+			CRYPTO_INFO("%s: Inbound DTL added\n", __func__);
+	}
+
+	/* At this point, both outbound and inbound transforms have been
+	 * registered and both outbound and inbound DTL entries are added to the
+	 * lookup table. The Packet Engine is ready to accept packets and
+	 * perform classification and processing autonomously.*/
+
+	if (fVerbose)
+		CRYPTO_INFO("*** Finished update DTLS-CAPWAP SA ***\n\n");
+
+	// If we made it to here, consider this run a success. Any jump
+	// to one of the error labels below will skip "success = true"
+	success = true;
+	DTLSParam_p->SA_encrypt = DTLSResourceEntity_p->DTLSHandleSAOutbound.p;
+	DTLSParam_p->SA_decrypt = DTLSResourceEntity_p->DTLSHandleSAInbound.p;
+	DTLSResourceEntity_p->DTLSParam = DTLSParam_p;
+	*DTLSResource = DTLSResourceEntity_p;
+
+	return success;
+
+
+error_exit_unregister:
+	/* At this point, all flows have been removed, so we can start
+	 * removing the transform records.	Note: all flows that use the
+	 * transform must be removed before removing the transform.
+	 *
+	 * When any flow creation error occurs, return to this point. The
+	 * flow records have not been created, but the transform records
+	 * are registered at this point.
+	 */
+
+	/* Obtain statistics of the outbound transform. We do this at the
+	 * end of the lifetime of the transform, but it can be done at any
+	 * time when the transform is registered.*/
+	PCL_Status = PCL_Transform_Get_ReadOnly(DTLSResourceEntity_p->DTLSHandleSAOutbound,
+									&TransformParams);
+	if (PCL_Status != PCL_STATUS_OK)
+		CRYPTO_ERR("%s: Could not obtain statistics for outbound transform\n", __func__);
+	else
+		CRYPTO_INFO("Statistics of outbound transform: %u packets %u octets\n",
+				 TransformParams.PacketsCounterLo,
+				 TransformParams.OctetsCounterLo);
+
+	/* Obtain statistics of the inbound transform. */
+	PCL_Status = PCL_Transform_Get_ReadOnly(DTLSResourceEntity_p->DTLSHandleSAInbound,
+									&TransformParams);
+	if (PCL_Status != PCL_STATUS_OK)
+		CRYPTO_ERR("%s: Could not obtain statistics for inbound transform\n", __func__);
+	else
+		CRYPTO_INFO("Statistics of inbound transform: %u packets %u octets\n",
+				 TransformParams.PacketsCounterLo,
+				 TransformParams.OctetsCounterLo);
+
+
+	/* Unregister both transforms. Report, but do not handle the
+	 * results of these calls. If they fail, there is nothing sensible
+	 * that we can do to recover.
+	 */
+	if (!mtk_ddk_invalidate_rec(DTLSResourceEntity_p->DTLSHandleSAOutbound, true))
+		CRYPTO_ERR("%s: transform invalidate failed\n", __func__);
+	else if (fVerbose)
+		CRYPTO_INFO("transform invalidate succeeded\n");
+
+
+	PCL_Status = PCL_Transform_UnRegister(DTLSResourceEntity_p->DTLSHandleSAOutbound);
+	if (PCL_Status != PCL_STATUS_OK)
+		CRYPTO_ERR("%s: PCL_Transform_UnRegister failed\n", __func__);
+	else if (fVerbose)
+		CRYPTO_INFO("PCL_Transform_UnRegister succeeded\n");
+
+
+	if (!mtk_ddk_invalidate_rec(DTLSResourceEntity_p->DTLSHandleSAInbound, true))
+		CRYPTO_ERR("%s: transform invalidate failed\n", __func__);
+	else if (fVerbose)
+		CRYPTO_INFO("transform invalidate succeeded\n");
+
+
+	PCL_Status = PCL_Transform_UnRegister(DTLSResourceEntity_p->DTLSHandleSAInbound);
+	if (PCL_Status != PCL_STATUS_OK)
+		CRYPTO_ERR("%s: PCL_Transform_UnRegister failed\n", __func__);
+	else if (fVerbose)
+		CRYPTO_INFO("PCL_Transform_UnRegister succeeded\n");
+
+
+error_exit:
+	/* Remove the buffers occupied by the transforms, the packets and the
+	 * header processor contexts.
+	 *
+	 * Return here if any error occurs before the transforms are registered.
+	 * When we return here with an error, not all buffers may have been
+	 * allocated.
+	 * Note: DMABuf_Release can be called when no buffer was allocated.
+	 */
+	if (DTLSResourceEntity_p != NULL) {
+		if (DTLSResourceEntity_p->DTLSHandleSAOutbound.p != NULL) {
+			DMABuf_Release(DTLSResourceEntity_p->DTLSHandleSAOutbound);
+			DTLSResourceEntity_p->DTLSHandleSAOutbound.p = NULL;
+			DTLSResourceEntity_p->DTLSParam->SA_encrypt = (void *) NULL;
+		}
+		if (DTLSResourceEntity_p->DTLSHandleSAInbound.p != NULL) {
+			DMABuf_Release(DTLSResourceEntity_p->DTLSHandleSAInbound);
+			DTLSResourceEntity_p->DTLSHandleSAInbound.p = NULL;
+			DTLSResourceEntity_p->DTLSParam->SA_decrypt = (void *) NULL;
+		}
+		if (DTLSResourceEntity_p->HKeyOutbound != NULL) {
+			kfree(DTLSResourceEntity_p->HKeyOutbound);
+			DTLSResourceEntity_p->HKeyOutbound = NULL;
+		}
+		if (DTLSResourceEntity_p->HKeyInbound != NULL) {
+			kfree(DTLSResourceEntity_p->HKeyInbound);
+			DTLSResourceEntity_p->HKeyInbound = NULL;
+		}
+		if (DTLSResourceEntity_p->InnerDigestInbound != NULL) {
+			kfree(DTLSResourceEntity_p->InnerDigestInbound);
+			DTLSResourceEntity_p->InnerDigestInbound = NULL;
+		}
+		if (DTLSResourceEntity_p->OuterDigestInbound != NULL) {
+			kfree(DTLSResourceEntity_p->OuterDigestInbound);
+			DTLSResourceEntity_p->OuterDigestInbound = NULL;
+		}
+		if (DTLSResourceEntity_p->InnerDigestOutbound != NULL) {
+			kfree(DTLSResourceEntity_p->InnerDigestOutbound);
+			DTLSResourceEntity_p->InnerDigestOutbound = NULL;
+		}
+		if (DTLSResourceEntity_p->OuterDigestOutbound != NULL) {
+			kfree(DTLSResourceEntity_p->OuterDigestOutbound);
+			DTLSResourceEntity_p->OuterDigestOutbound = NULL;
+		}
+		if (DTLSResourceEntity_p != NULL) {
+			kfree(DTLSResourceEntity_p);
+			DTLSResourceEntity_p = NULL;
+		}
+		*DTLSResource = NULL;
+	}
+	return success;
+}
+
+void mtk_ddk_remove_dtls_param(struct DTLSResourceMgmt **DTLSResource)
+{
+	bool fVerbose = false;
+	bool fPktCfy = true;
+	PCL_Status_t PCL_Status;
+	PCL_TransformParams_t TransformParams;
+
+	if (*DTLSResource == NULL) {
+		if (fVerbose)
+			CRYPTO_ERR("%s: DTLSResource is NULL\n", __func__);
+		return;
+	}
+
+	// unregister_flows
+	if (fPktCfy) {
+		PCL_Status = PCL_DTL_Transform_Remove(PCL_INTERFACE_ID, 0,
+							(*DTLSResource)->DTLSHandleSAInbound);
+		if (PCL_Status != PCL_STATUS_OK)
+			CRYPTO_ERR("%s: PCL_DLT_Tansform_Remove Inbound failed\n", __func__);
+		else
+			if (fVerbose)
+				CRYPTO_INFO("PCL_DTL_Transform_Remove Inbound succeeded\n");
+
+		PCL_Status = PCL_DTL_Transform_Remove(PCL_INTERFACE_ID, 0,
+							(*DTLSResource)->DTLSHandleSAOutbound);
+		if (PCL_Status != PCL_STATUS_OK)
+			CRYPTO_ERR("%s: PCL_DLT_Tansform_Remove Outbound failed\n", __func__);
+		else
+			if (fVerbose)
+				CRYPTO_INFO("PCL_DTL_Transform_Remove Outbound succeeded\n");
+	}
+
+	/* At this point, all flows have been removed, so we can start
+	 * removing the transform records.  Note: all flows that use the
+	 * transform must be removed before removing the transform.
+	 *
+	 * When any flow creation error occurs, return to this point. The
+	 * flow records have not been created, but the transform records
+	 * are registered at this point.
+	 */
+
+	/* Obtain statistics of the outbound transform. We do this at the
+	 * end of the lifetime of the transform, but it can be done at any
+	 * time when the transform is registered.*/
+	PCL_Status = PCL_Transform_Get_ReadOnly((*DTLSResource)->DTLSHandleSAOutbound,
+								&TransformParams);
+	if (PCL_Status != PCL_STATUS_OK)
+		CRYPTO_ERR("%s: Could not obtain statistics for outbound transform\n", __func__);
+	else
+		CRYPTO_INFO("Statistics of outbound transform: %u packets %u octets\n",
+				 TransformParams.PacketsCounterLo,
+				 TransformParams.OctetsCounterLo);
+
+	/* Obtain statistics of the inbound transform. */
+	PCL_Status = PCL_Transform_Get_ReadOnly((*DTLSResource)->DTLSHandleSAInbound,
+								&TransformParams);
+	if (PCL_Status != PCL_STATUS_OK)
+		CRYPTO_ERR("%s: Could not obtain statistics for inbound transform\n", __func__);
+	else
+		CRYPTO_INFO("Statistics of inbound transform: %u packets %u octets\n",
+				 TransformParams.PacketsCounterLo,
+				 TransformParams.OctetsCounterLo);
+
+
+	/* Unregister both transforms. Report, but do not handle the
+	 * results of these calls. If they fail, there is nothing sensible
+	 * that we can do to recover.
+	 */
+	if (!mtk_ddk_invalidate_rec((*DTLSResource)->DTLSHandleSAOutbound, true))
+		CRYPTO_ERR("%s: transform invalidate failed\n", __func__);
+	else
+		if (fVerbose)
+			CRYPTO_INFO("transform invalidate succeeded\n");
+#ifdef PEC_PCL_EIP197
+		PCL_Status = PCL_Transform_UnRegister((*DTLSResource)->DTLSHandleSAOutbound);
+		if (PCL_Status != PCL_STATUS_OK)
+			CRYPTO_ERR("%s: PCL_Transform_UnRegister failed\n", __func__);
+		else
+			if (fVerbose)
+				CRYPTO_INFO("PCL_Transform_UnRegister succeeded\n");
+#else
+		PEC_SA_UnRegister(PCL_INTERFACE_ID, (*DTLSResource)->DTLSHandleSAOutbound,
+						DMABuf_NULLHandle, DMABuf_NULLHandle);
+#endif
+
+	if (!mtk_ddk_invalidate_rec((*DTLSResource)->DTLSHandleSAInbound, true))
+		CRYPTO_ERR("%s: transform invalidate failed\n", __func__);
+	else
+		if (fVerbose)
+			CRYPTO_INFO("transform invalidate succeeded\n");
+#ifdef PEC_PCL_EIP197
+		PCL_Status = PCL_Transform_UnRegister((*DTLSResource)->DTLSHandleSAInbound);
+		if (PCL_Status != PCL_STATUS_OK)
+			CRYPTO_ERR("%s: PCL_Transform_UnRegister failed\n", __func__);
+		else
+			if (fVerbose)
+				CRYPTO_INFO("PCL_Transform_UnRegister succeeded\n");
+#else
+		PEC_SA_UnRegister(PCL_INTERFACE_ID, (*DTLSResource)->DTLSHandleSAInbound,
+						DMABuf_NULLHandle, DMABuf_NULLHandle);
+#endif
+
+	/* Remove the buffers occupied by the transforms, the packets and the
+	 * header processor contexts.
+	 *
+	 * Return here if any error occurs before the transforms are registered.
+	 * When we return here with an error, not all buffers may have been
+	 * allocated.
+	 * Note: DMABuf_Release can be called when no buffer was allocated.
+	 */
+	if ((*DTLSResource)->DTLSHandleSAOutbound.p != NULL) {
+		DMABuf_Release((*DTLSResource)->DTLSHandleSAOutbound);
+		(*DTLSResource)->DTLSHandleSAOutbound.p = NULL;
+		(*DTLSResource)->DTLSParam->SA_encrypt = (void *) NULL;
+	}
+	if ((*DTLSResource)->DTLSHandleSAInbound.p != NULL) {
+		DMABuf_Release((*DTLSResource)->DTLSHandleSAInbound);
+		(*DTLSResource)->DTLSHandleSAInbound.p = NULL;
+		(*DTLSResource)->DTLSParam->SA_decrypt = (void *) NULL;
+	}
+	if ((*DTLSResource)->HKeyOutbound != NULL) {
+		kfree((*DTLSResource)->HKeyOutbound);
+		(*DTLSResource)->HKeyOutbound = NULL;
+	}
+	if ((*DTLSResource)->HKeyInbound != NULL) {
+		kfree((*DTLSResource)->HKeyInbound);
+		(*DTLSResource)->HKeyInbound = NULL;
+	}
+	if ((*DTLSResource)->InnerDigestInbound != NULL) {
+		kfree((*DTLSResource)->InnerDigestInbound);
+		(*DTLSResource)->InnerDigestInbound = NULL;
+	}
+	if ((*DTLSResource)->OuterDigestInbound != NULL) {
+		kfree((*DTLSResource)->OuterDigestInbound);
+		(*DTLSResource)->OuterDigestInbound = NULL;
+	}
+	if ((*DTLSResource)->InnerDigestOutbound != NULL) {
+		kfree((*DTLSResource)->InnerDigestOutbound);
+		(*DTLSResource)->InnerDigestOutbound = NULL;
+	}
+	if ((*DTLSResource)->OuterDigestOutbound != NULL) {
+		kfree((*DTLSResource)->OuterDigestOutbound);
+		(*DTLSResource)->OuterDigestOutbound = NULL;
+	}
+	if (*DTLSResource != NULL) {
+		kfree(*DTLSResource);
+		*DTLSResource = NULL;
+	}
+	*DTLSResource = NULL;
 }
diff --git a/feed/kernel/crypto-eip/src/ddk/Makefile b/feed/kernel/crypto-eip/src/ddk/Makefile
index 775e942..08c5106 100644
--- a/feed/kernel/crypto-eip/src/ddk/Makefile
+++ b/feed/kernel/crypto-eip/src/ddk/Makefile
@@ -41,6 +41,7 @@
 crypto-eip-ddk-y += ./kit/builder/sa/sa_builder_ipsec.o
 # crypto-eip-ddk-y += ./kit/builder/sa/sa_builder_srtp.o
 crypto-eip-ddk-y += ./kit/builder/sa/sa_builder_ssltls.o
+crypto-eip-ddk-y += ./kit/builder/sa/sa_builder_extended_dtls.o
 
 # token builder
 crypto-eip-ddk-y += ./kit/builder/token/token_builder_context.o
@@ -87,6 +88,3 @@
 
 # ring
 crypto-eip-ddk-y += ./kit/ring/ringhelper.o
-
-# log
-crypto-eip-ddk-y += ./kit/log/log.o
diff --git a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/configs/cs_sa_builder.h b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/configs/cs_sa_builder.h
index 816b574..b334cf4 100644
--- a/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/configs/cs_sa_builder.h
+++ b/feed/kernel/crypto-eip/src/ddk/inc/crypto-eip/ddk/configs/cs_sa_builder.h
@@ -65,7 +65,7 @@
 
 /* Enable if the SA Builder must support extended use case for DTLS
    processing */
-//#define SAB_ENABLE_DTLS_EXTENDED
+#define SAB_ENABLE_DTLS_EXTENDED
 
 /* Enable if the SA Builder must support extended use case for Basic
    processing */
diff --git a/feed/kernel/crypto-eip/src/ddk/kit/log/log.c b/feed/kernel/crypto-eip/src/ddk/kit/log/log.c
index 84473f9..785db75 100644
--- a/feed/kernel/crypto-eip/src/ddk/kit/log/log.c
+++ b/feed/kernel/crypto-eip/src/ddk/kit/log/log.c
@@ -74,6 +74,7 @@
         Log_FormattedMessage("\n");
     } // for
 }
+EXPORT_SYMBOL(Log_HexDump);
 
 
 /*----------------------------------------------------------------------------
diff --git a/feed/kernel/crypto-eip/src/inc/crypto-eip/crypto-eip.h b/feed/kernel/crypto-eip/src/inc/crypto-eip/crypto-eip.h
index 5d27272..2fa7526 100644
--- a/feed/kernel/crypto-eip/src/inc/crypto-eip/crypto-eip.h
+++ b/feed/kernel/crypto-eip/src/inc/crypto-eip/crypto-eip.h
@@ -34,6 +34,9 @@
 #define EIP197_AUTO_LOOKUP_1		(0xfffffffc)
 #define EIP197_AUTO_LOOKUP_2		(0xffffffff)
 
+#define PEC_PCL_EIP197
+#define CAPWAP_MAX_TUNNEL_NUM CONFIG_TOPS_TNL_NUM
+
 struct mtk_crypto {
 	struct mtk_eth *eth;
 	void __iomem *crypto_base;
@@ -50,6 +53,76 @@
 	u32 dir;			/* SABuilder_Direction_t */
 };
 
+/* DTLS */
+enum dtls_sec_mode_type {
+	__DTLS_SEC_MODE_TYPE_NONE = 0,
+	AES128_CBC_HMAC_SHA1,
+	AES256_CBC_HMAC_SHA1,
+	AES128_CBC_HMAC_SHA2_256,
+	AES256_CBC_HMAC_SHA2_256,
+	AES128_GCM,
+	AES256_GCM,
+	__DTLS_SEC_MODE_TYPE_MAX = 7,
+};
+
+enum dtls_version {
+	MTK_DTLS_VERSION_1_0 = 0,
+	MTK_DTLS_VERSION_1_2 = 1,
+	__DTLS_VERSION_MAX = 2,
+};
+
+struct DTLS_param {
+	__be32 dip;
+	__be32 sip;
+	uint16_t dport;
+	uint16_t sport;
+	uint16_t dtls_epoch;
+	uint16_t dtls_version;
+	uint8_t sec_mode;
+	uint8_t *dtls_encrypt_nonce;
+	uint8_t *dtls_decrypt_nonce;
+	uint8_t *key_encrypt;
+	uint8_t *key_auth_encrypt_1;
+	uint8_t *key_auth_encrypt_2;
+	uint8_t *key_decrypt;
+	uint8_t *key_auth_decrypt_1;
+	uint8_t *key_auth_decrypt_2;
+	void *SA_encrypt;
+	void *SA_decrypt;
+} __packed __aligned(16);
+
+struct DTLSResourceMgmt {
+	struct DTLS_param *DTLSParam;
+	DMABuf_Handle_t DTLSHandleSAOutbound;
+	DMABuf_Handle_t DTLSHandleSAInbound;
+	uint8_t *HKeyOutbound;
+	uint8_t *HKeyInbound;
+	uint8_t *InnerDigestOutbound;
+	uint8_t *OuterDigestOutbound;
+	uint8_t *InnerDigestInbound;
+	uint8_t *OuterDigestInbound;
+};
+
+struct mtk_cdrt_idx_param {
+	uint32_t cdrt_idx_inbound;
+	uint32_t cdrt_idx_outbound;
+};
+
+struct mtk_CDRT_DTLS_entry {
+	struct cdrt_entry *cdrt_inbound;
+	struct cdrt_entry *cdrt_outbound;
+};
+
+#if defined(CONFIG_MTK_TOPS_CAPWAP_DTLS)
+extern void (*mtk_submit_SAparam_to_eip_driver)(struct DTLS_param *DTLSParam_p, int TnlIdx);
+extern void (*mtk_remove_SAparam_to_eip_driver)(struct DTLS_param *DTLSParam_p, int TnlIdx);
+extern void (*mtk_update_cdrt_idx_from_eip_driver)(struct mtk_cdrt_idx_param *cdrt_idx_params_p);
+#endif
+
+void mtk_update_dtls_param(struct DTLS_param *DTLSParam_p, int TnlIdx);
+void mtk_remove_dtls_param(struct DTLS_param *DTLSParam_p, int TnlIdx);
+
+/* Netsys */
 void crypto_eth_write(u32 reg, u32 val);
 u32 mtk_crypto_ppe_get_num(void);
 
diff --git a/feed/kernel/crypto-eip/src/inc/crypto-eip/crypto-eip197-inline-ddk.h b/feed/kernel/crypto-eip/src/inc/crypto-eip/crypto-eip197-inline-ddk.h
index a5f6b20..25cd724 100644
--- a/feed/kernel/crypto-eip/src/inc/crypto-eip/crypto-eip197-inline-ddk.h
+++ b/feed/kernel/crypto-eip/src/inc/crypto-eip/crypto-eip197-inline-ddk.h
@@ -18,6 +18,7 @@
 #include <crypto-eip/ddk/kit/builder/sa/sa_builder_ipsec.h>
 #include <crypto-eip/ddk/kit/builder/sa/sa_builder_basic.h>
 #include <crypto-eip/ddk/kit/builder/sa/sa_builder_params_basic.h>
+#include <crypto-eip/ddk/kit/builder/sa/sa_builder_ssltls.h>
 #include <crypto-eip/ddk/kit/builder/token/token_builder.h>
 #include <crypto-eip/ddk/kit/iotoken/iotoken.h>
 #include <crypto-eip/ddk/kit/iotoken/iotoken_ext.h>
diff --git a/feed/kernel/crypto-eip/src/inc/crypto-eip/ddk-wrapper.h b/feed/kernel/crypto-eip/src/inc/crypto-eip/ddk-wrapper.h
index dabc743..1dc32e2 100644
--- a/feed/kernel/crypto-eip/src/inc/crypto-eip/ddk-wrapper.h
+++ b/feed/kernel/crypto-eip/src/inc/crypto-eip/ddk-wrapper.h
@@ -42,6 +42,18 @@
 void crypto_free_pkt(void *pkt);
 void crypto_free_sglist(void *sglist);
 
+bool mtk_capwap_dtls_offload(
+		const bool fVerbose,
+		const bool fCAPWAP,
+		const bool fPktCfy,
+		const bool fInline,
+		const bool fContinuousScatter,
+		struct DTLS_param *DTLSParam_p,
+		struct DTLSResourceMgmt **DTLSResource);
+void mtk_ddk_remove_dtls_param(struct DTLSResourceMgmt **DTLSResource);
+
 int mtk_ddk_pec_init(void);
 void mtk_ddk_pec_deinit(void);
+void mtk_dtls_capwap_init(void);
+void mtk_dtls_capwap_deinit(void);
 #endif /* _CRYPTO_EIP_DDK_WRAPPER_H_ */
diff --git a/feed/kernel/crypto-eip/src/init.c b/feed/kernel/crypto-eip/src/init.c
index 0fb430c..42976ee 100644
--- a/feed/kernel/crypto-eip/src/init.c
+++ b/feed/kernel/crypto-eip/src/init.c
@@ -114,11 +114,13 @@
 	return readl(mcrypto.crypto_base + reg);
 }
 
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_HNAT)
 static bool mtk_crypto_eip_offloadable(struct sk_buff *skb)
 {
 	/* TODO: check is esp */
 	return true;
 }
+#endif // HNAT
 
 u32 mtk_crypto_ppe_get_num(void)
 {
@@ -188,7 +190,9 @@
 {
 	int i;
 
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_HNAT)
 	mtk_crypto_offloadable = NULL;
+#endif // HNAT
 
 	for (i = 0; i < MTK_MAC_COUNT; i++) {
 		eth->netdev[i]->xfrmdev_ops = NULL;
@@ -213,7 +217,9 @@
 		rtnl_unlock();
 	}
 
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_HNAT)
 	mtk_crypto_offloadable = mtk_crypto_eip_offloadable;
+#endif // HNAT
 }
 
 static int __init mtk_crypto_eth_dts_init(struct platform_device *pdev)
@@ -405,6 +411,9 @@
 
 	mtk_crypto_xfrm_offload_init(mcrypto.eth);
 	mtk_crypto_register_algorithms(priv);
+#if defined(CONFIG_MTK_TOPS_CAPWAP_DTLS)
+	mtk_dtls_capwap_init();
+#endif
 
 	CRYPTO_INFO("crypto-eip init done\n");
 
@@ -414,6 +423,9 @@
 static void __exit mtk_crypto_eip_exit(void)
 {
 	/* TODO: deactivate all tunnel */
+#if defined(CONFIG_MTK_TOPS_CAPWAP_DTLS)
+	mtk_dtls_capwap_deinit();
+#endif
 	mtk_crypto_unregister_algorithms();
 	mtk_crypto_xfrm_offload_deinit(mcrypto.eth);
 
diff --git a/feed/kernel/crypto-eip/src/xfrm-offload.c b/feed/kernel/crypto-eip/src/xfrm-offload.c
index 28f4555..4954acc 100644
--- a/feed/kernel/crypto-eip/src/xfrm-offload.c
+++ b/feed/kernel/crypto-eip/src/xfrm-offload.c
@@ -9,8 +9,11 @@
 #include <linux/bitops.h>
 
 #include <mtk_eth_soc.h>
+
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_HNAT)
 #include <mtk_hnat/hnat.h>
 #include <mtk_hnat/nf_hnat_mtk.h>
+#endif // HNAT
 
 #include <pce/cdrt.h>
 #include <pce/cls.h>
@@ -26,6 +29,9 @@
 
 static LIST_HEAD(xfrm_params_head);
 
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_HNAT)
+extern int (*ra_sw_nat_hook_tx)(struct sk_buff *skb, int gmac_no);
+
 static inline bool is_tops_udp_tunnel(struct sk_buff *skb)
 {
 	return skb_hnat_tops(skb) && (ntohs(skb->protocol) == ETH_P_IP) &&
@@ -41,6 +47,7 @@
 {
 	return is_magic_tag_valid(skb) && (skb_hnat_reason(skb) == HIT_UNBIND_RATE_REACH);
 }
+#endif // HNAT
 
 static void mtk_xfrm_offload_cdrt_tear_down(struct mtk_xfrm_params *xfrm_params)
 {
@@ -341,19 +348,26 @@
 	rcu_read_unlock_bh();
 
 	xfrm_params = (struct mtk_xfrm_params *)xs->xso.offload_handle;
-	skb_hnat_cdrt(skb) = xfrm_params->cdrt->idx;
 
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_HNAT)
+	skb_hnat_cdrt(skb) = xfrm_params->cdrt->idx;
 	/*
 	 * EIP197 does not support fragmentation. As a result, we can not bind UDP
 	 * flow since it may cause network fail due to fragmentation
 	 */
-	if ((is_tops_udp_tunnel(skb) || is_tcp(skb)) && is_hnat_rate_reach(skb))
+	if (ra_sw_nat_hook_tx &&
+		((is_tops_udp_tunnel(skb) || is_tcp(skb)) && is_hnat_rate_reach(skb)))
 		hnat_bind_crypto_entry(skb, dst->dev);
 
-	/* Since we're going to tx directly, set skb->dev to dst->dev */
-	skb->dev = dst->dev;
 	/* Set magic tag for tport setting, reset to 0 after tport is set */
 	skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+#else
+	skb_tnl_cdrt(skb) = xfrm_params->cdrt->idx;
+	skb_tnl_magic_tag(skb) = TNL_MAGIC_TAG;
+#endif // HNAT
+
+	/* Since we're going to tx directly, set skb->dev to dst->dev */
+	skb->dev = dst->dev;
 
 	/*
 	 * Since skb headroom may not be copy when segment, we cannot rely on