[][openwrt][mt7988][crypto][Fix session disconnected when transfering IPSec tunnel]

[Description]
Fix session disconnected when transfering IPSec tunnel.
The root cause of this problem is memory consistency. When a Transform
Record is prepared, the data is only on CPU cache. DMA controller in
EIP197 may fetch incomplete data from main memory since the TR in CPU
cache didn't totally sync to main memory.
After this commit, when a Transform Record is built, we'll sync to main
memory immediately with PCL_Transform_Register().

[Release-log]
N/A


Change-Id: I7085d6fa76f60e75a883645e08af1298bdf62b98
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/9808508
diff --git a/feed/kernel/crypto-eip/src/ddk-wrapper.c b/feed/kernel/crypto-eip/src/ddk-wrapper.c
index a0559db..e704e77 100644
--- a/feed/kernel/crypto-eip/src/ddk-wrapper.c
+++ b/feed/kernel/crypto-eip/src/ddk-wrapper.c
@@ -1955,7 +1955,8 @@
 	SABuilder_Params_t params;
 	bool set_auth_success = false;
 	unsigned int SAWords = 0;
-	uint8_t *inner, *outer;
+	uint8_t *inner = NULL;
+	uint8_t *outer = NULL;
 
 	DMABuf_Status_t dma_status;
 	DMABuf_Properties_t dma_properties = {0, 0, 0, 0};
@@ -1963,6 +1964,8 @@
 
 	DMABuf_Handle_t sa_handle = {0};
 
+	PCL_Status_t pcl_status;
+
 	sa_status = SABuilder_Init_ESP(&params,
 				       &ipsec_params,
 				       be32_to_cpu(xs->id.spi),
@@ -1972,22 +1975,22 @@
 
 	if (sa_status != SAB_STATUS_OK) {
 		pr_err("SABuilder_Init_ESP failed\n");
-		sa_handle.p = NULL;
-		return (u32 *) sa_handle.p;
+		sa_host_addr.p = NULL;
+		goto error_ret;
 	}
 
 	/* No support for aead now */
 	if (xs->aead) {
 		CRYPTO_ERR("AEAD not supported\n");
-		sa_handle.p = NULL;
-		return (u32 *) sa_handle.p;
+		sa_host_addr.p = NULL;
+		goto error_ret;
 	}
 
 	/* Check algorithm exist in xfrm state*/
 	if (!xs->ealg || !xs->aalg) {
 		CRYPTO_ERR("NULL algorithm in xfrm state\n");
-		sa_handle.p = NULL;
-		return (u32 *) sa_handle.p;
+		sa_host_addr.p = NULL;
+		goto error_ret;
 	}
 
 	/* Add crypto key and parameters */
@@ -2000,8 +2003,8 @@
 	set_auth_success = set_auth_algo(xs->aalg, &params, inner, outer);
 	if (set_auth_success != true) {
 		CRYPTO_ERR("Set Auth Algo failed\n");
-		sa_handle.p = NULL;
-		return (u32 *) sa_handle.p;
+		sa_host_addr.p = NULL;
+		goto error_ret;
 	}
 
 	ipsec_params.IPsecFlags |= (SAB_IPSEC_PROCESS_IP_HEADERS
@@ -2014,8 +2017,8 @@
 	sa_status = SABuilder_GetSizes(&params, &SAWords, NULL, NULL);
 	if (sa_status != SAB_STATUS_OK) {
 		CRYPTO_ERR("SA not created because of size errors\n");
-		sa_handle.p = NULL;
-		return (u32 *) sa_handle.p;
+		sa_host_addr.p = NULL;
+		goto error_ret;
 	}
 
 	dma_properties.fCached = true;
@@ -2026,18 +2029,29 @@
 	dma_status = DMABuf_Alloc(dma_properties, &sa_host_addr, &sa_handle);
 	if (dma_status != DMABUF_STATUS_OK) {
 		CRYPTO_ERR("Allocation of SA failed\n");
-		/* goto error_exit; */
-		sa_handle.p = NULL;
-		return (u32 *) sa_handle.p;
+		sa_host_addr.p = NULL;
+		goto error_ret;
 	}
 
 	sa_status = SABuilder_BuildSA(&params, (u32 *) sa_host_addr.p, NULL, NULL);
 	if (sa_status != SAB_STATUS_OK) {
 		CRYPTO_ERR("SA not created because of errors\n");
-		sa_handle.p = NULL;
-		return (u32 *) sa_handle.p;
+		DMABuf_Release(sa_handle);
+		sa_host_addr.p = NULL;
+		goto error_ret;
+	}
+
+	pcl_status = PCL_Transform_Register(sa_handle);
+	if (pcl_status != PCL_STATUS_OK) {
+		CRYPTO_ERR("%s: PCL_Transform_Register failed\n", __func__);
+		DMABuf_Release(sa_handle);
+		sa_host_addr.p = NULL;
+		goto error_ret;
 	}
 
+	xfrm_params->p_handle = (u32 *) sa_handle.p;
+
+error_ret:
 	kfree(inner);
 	kfree(outer);
 	return (u32 *) sa_host_addr.p;
@@ -2358,7 +2372,7 @@
 
 bool
 mtk_ddk_invalidate_rec(
-		const DMABuf_Handle_t Rec_p,
+		void *sa_p,
 		const bool IsTransform)
 {
 	PEC_Status_t PEC_Rc;
@@ -2373,7 +2387,9 @@
 	void *OutTokenDscrExt_p = NULL;
 	IOToken_Input_Dscr_Ext_t InTokenDscrExt;
 	IOToken_Output_Dscr_Ext_t OutTokenDscrExt;
+	DMABuf_Handle_t Rec_p;
 
+	Rec_p.p = sa_p;
 	ZEROINIT(InTokenDscrExt);
 	InTokenDscrExt_p = &InTokenDscrExt;
 	OutTokenDscrExt_p = &OutTokenDscrExt;
@@ -2684,7 +2700,7 @@
 	}
 	return 0;
 unregister_exit:
-	mtk_ddk_invalidate_rec(sa, true);
+	mtk_ddk_invalidate_rec(sa.p, true);
 	PCL_Transform_UnRegister(sa);
 	return -1;
 }
@@ -2726,7 +2742,7 @@
 		return;
 
 	pcl_status = PCL_DTL_Transform_Remove(PCL_INTERFACE_ID, 0, sa);
-	ret = mtk_ddk_invalidate_rec(sa, true);
+	ret = mtk_ddk_invalidate_rec(sa.p, true);
 	pcl_status = PCL_Transform_UnRegister(sa);
 
 	return;
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 9286b6e..8d1d4fd 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
@@ -50,6 +50,7 @@
 	struct cdrt_entry *cdrt;
 
 	u32 *p_tr;			/* pointer to transform record */
+	u32 *p_handle;		/* pointer to eip dma handle */
 	u32 dir;			/* SABuilder_Direction_t */
 };
 
@@ -162,5 +163,7 @@
 void mtk_xfrm_offload_state_free(struct xfrm_state *xs);
 void mtk_xfrm_offload_state_tear_down(void);
 int mtk_xfrm_offload_policy_add(struct xfrm_policy *xp);
+void mtk_xfrm_offload_policy_delete(struct xfrm_policy *xp);
+void mtk_xfrm_offload_policy_free(struct xfrm_policy *xp);
 bool mtk_xfrm_offload_ok(struct sk_buff *skb, struct xfrm_state *xs);
 #endif /* _CRYPTO_EIP_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 f6240e6..e1e4da2 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
@@ -43,6 +43,7 @@
 void crypto_free_pkt(void *pkt);
 void crypto_free_sglist(void *sglist);
 void mtk_crypto_req_expired_timer(struct timer_list *t);
+bool mtk_ddk_invalidate_rec(void *sa_p, const bool IsTransform);
 
 void *mtk_ddk_tr_capwap_dtls_build(const bool capwap,
 				struct DTLS_param *DTLSParam_p, u32 dir);
diff --git a/feed/kernel/crypto-eip/src/init.c b/feed/kernel/crypto-eip/src/init.c
index 9dfa7ad..7a7ec27 100644
--- a/feed/kernel/crypto-eip/src/init.c
+++ b/feed/kernel/crypto-eip/src/init.c
@@ -133,6 +133,8 @@
 
 	/* Not support at v5.4*/
 	.xdo_dev_policy_add = mtk_xfrm_offload_policy_add,
+	.xdo_dev_policy_delete = mtk_xfrm_offload_policy_delete,
+	.xdo_dev_policy_free = mtk_xfrm_offload_policy_free,
 };
 
 static int mtk_crypto_register_algorithms(struct mtk_crypto_priv *priv)
diff --git a/feed/kernel/crypto-eip/src/xfrm-offload.c b/feed/kernel/crypto-eip/src/xfrm-offload.c
index 34b4ecc..4e7a55c 100644
--- a/feed/kernel/crypto-eip/src/xfrm-offload.c
+++ b/feed/kernel/crypto-eip/src/xfrm-offload.c
@@ -132,11 +132,8 @@
 static void mtk_xfrm_offload_context_tear_down(struct mtk_xfrm_params *xfrm_params)
 {
 	mtk_xfrm_offload_cdrt_tear_down(xfrm_params);
-
-	/* TODO: free context */
-	devm_kfree(crypto_dev, xfrm_params->p_tr);
-
-	/* TODO: transform record tear down */
+	mtk_ddk_invalidate_rec((void *) xfrm_params->p_handle, true);
+	crypto_free_sa((void *) xfrm_params->p_handle, 0);
 }
 
 static int mtk_xfrm_offload_context_setup(struct mtk_xfrm_params *xfrm_params)
@@ -144,11 +141,6 @@
 	u32 *tr;
 	int ret;
 
-	xfrm_params->p_tr = devm_kcalloc(crypto_dev, sizeof(u32),
-					 TRANSFORM_RECORD_LEN, GFP_KERNEL);
-	if (unlikely(!xfrm_params->p_tr))
-		return -ENOMEM;
-
 	switch (xfrm_params->xs->outer_mode.encap) {
 	case XFRM_MODE_TUNNEL:
 		tr = mtk_ddk_tr_ipsec_build(xfrm_params, SAB_IPSEC_TUNNEL);
@@ -166,15 +158,11 @@
 		goto err_out;
 	}
 
-	memcpy(xfrm_params->p_tr, tr, sizeof(u32) * TRANSFORM_RECORD_LEN);
-
-	/* TODO: free tr */
+	xfrm_params->p_tr = tr;
 
 	return mtk_xfrm_offload_cdrt_setup(xfrm_params);
 
 err_out:
-	devm_kfree(crypto_dev, xfrm_params->p_tr);
-
 	return ret;
 }
 
@@ -234,7 +222,6 @@
 int mtk_xfrm_offload_state_add(struct xfrm_state *xs)
 {
 	struct mtk_xfrm_params *xfrm_params;
-	unsigned long flags;
 	int ret = 0;
 
 	/* TODO: maybe support IPv6 in the future? */
@@ -277,11 +264,12 @@
 
 	xs->xso.offload_handle = (unsigned long)xfrm_params;
 
-	spin_lock_irqsave(&xfrm_params_list.lock, flags);
+	spin_lock_bh(&xfrm_params_list.lock);
 
 	list_add_tail(&xfrm_params->node, &xfrm_params_list.list);
 
+	spin_unlock_bh(&xfrm_params_list.lock);
+
-	spin_unlock_irqrestore(&xfrm_params_list.lock, flags);
 out:
 	return ret;
 }
@@ -298,31 +286,33 @@
 		return;
 
 	xfrm_params = (struct mtk_xfrm_params *)xs->xso.offload_handle;
+	xs->xso.offload_handle = 0;
 
+	spin_lock_bh(&xfrm_params_list.lock);
 	list_del(&xfrm_params->node);
+	spin_unlock_bh(&xfrm_params_list.lock);
 
 	if (xs->xso.flags & XFRM_OFFLOAD_INBOUND)
 		mtk_xfrm_offload_cls_entry_tear_down(xfrm_params);
 
-	mtk_xfrm_offload_context_tear_down(xfrm_params);
-
 	if (xfrm_params->cdrt)
 		mtk_pce_cdrt_entry_free(xfrm_params->cdrt);
 
+	mtk_xfrm_offload_context_tear_down(xfrm_params);
+
 	devm_kfree(crypto_dev, xfrm_params);
 }
 
 void mtk_xfrm_offload_state_tear_down(void)
 {
 	struct mtk_xfrm_params *xfrm_params, *tmp;
-	unsigned long flags;
 
-	spin_lock_irqsave(&xfrm_params_list.lock, flags);
+	spin_lock_bh(&xfrm_params_list.lock);
 
 	list_for_each_entry_safe(xfrm_params, tmp, &xfrm_params_list.list, node)
 		mtk_xfrm_offload_state_free(xfrm_params->xs);
 
-	spin_unlock_irqrestore(&xfrm_params_list.lock, flags);
+	spin_unlock_bh(&xfrm_params_list.lock);
 }
 
 int mtk_xfrm_offload_policy_add(struct xfrm_policy *xp)
@@ -330,6 +320,18 @@
 	return 0;
 }
 
+void mtk_xfrm_offload_policy_delete(struct xfrm_policy *xp)
+{
+}
+
+void mtk_xfrm_offload_policy_free(struct xfrm_policy *xp)
+{
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_HNAT)
+	foe_clear_crypto_entry(xp->selector);
+	return;
+#endif
+}
+
 static inline struct neighbour *mtk_crypto_find_dst_mac(struct sk_buff *skb,  struct xfrm_state *xs)
 {
 	struct neighbour *neigh;