[][kernel][mt7988][hnat][add L2TP iface flow offload check]

[Description]
Add l2tp interface flow offload check

[Release-log]
N/A

Change-Id: I90a636db0120c908bb53db8adf7093fb568ca174
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7596212
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
index 95e5e3c..ef6946f 100644
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -825,6 +825,9 @@
 mtk_hnat_ipv4_nf_pre_routing(void *priv, struct sk_buff *skb,
 			     const struct nf_hook_state *state)
 {
+	struct flow_offload_hw_path hw_path = { .dev = skb->dev,
+						.virt_dev = skb->dev };
+
 	if (!skb)
 		goto drop;
 
@@ -835,6 +838,19 @@
 
 	hnat_set_head_frags(state, skb, -1, hnat_set_iif);
 
+	/*
+	 * Avoid mistakenly binding of outer IP, ports in SW L2TP decap flow.
+	 * In pre-routing, if dev is virtual iface, TOPS module is not loaded,
+	 * and it's L2TP flow, then do not bind.
+	 */
+	if (skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL
+	    && skb->dev->netdev_ops->ndo_flow_offload_check) {
+		skb->dev->netdev_ops->ndo_flow_offload_check(&hw_path);
+
+		if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL)
+			skb_hnat_alg(skb) = 1;
+	}
+
 	pre_routing_print(skb, state->in, state->out, __func__);
 
 	/* packets from external devices -> xxx ,step 1 , learning stage & bound stage*/
diff --git a/target/linux/mediatek/patches-5.4/999-2726-mtkhnat-tnl-interface-offload-check.patch b/target/linux/mediatek/patches-5.4/999-2726-mtkhnat-tnl-interface-offload-check.patch
new file mode 100644
index 0000000..e94185f
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/999-2726-mtkhnat-tnl-interface-offload-check.patch
@@ -0,0 +1,62 @@
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -96,6 +96,7 @@ struct flow_offload {
+ #define FLOW_OFFLOAD_PATH_DSA		BIT(3)
+ #define FLOW_OFFLOAD_PATH_DSLITE	BIT(4)
+ #define FLOW_OFFLOAD_PATH_6RD		BIT(5)
++#define FLOW_OFFLOAD_PATH_TNL		BIT(6)
+ 
+ struct flow_offload_hw_path {
+ 	struct net_device *dev;
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -89,6 +89,7 @@
+ #include <linux/nsproxy.h>
+ #include <net/net_namespace.h>
+ #include <net/netns/generic.h>
++#include <net/netfilter/nf_flow_table.h>
+ #include <net/ip.h>
+ #include <net/udp.h>
+ #include <net/inet_common.h>
+@@ -124,9 +125,14 @@ struct pppol2tp_session {
+ };
+ 
+ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
++static int l2tp_ppp_flow_offload_check(struct ppp_channel *chan,
++				       struct flow_offload_hw_path *path);
+ 
+ static const struct ppp_channel_ops pppol2tp_chan_ops = {
+ 	.start_xmit =  pppol2tp_xmit,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.flow_offload_check = l2tp_ppp_flow_offload_check,
++#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
+ };
+ 
+ static const struct proto_ops pppol2tp_ops;
+@@ -335,6 +341,26 @@ error:
+ 	return error;
+ }
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int l2tp_ppp_flow_offload_check(struct ppp_channel *chan,
++				       struct flow_offload_hw_path *path)
++{
++	struct sock *sk = (struct sock *)chan->private;
++	struct l2tp_session *session;
++
++	if (path->flags & FLOW_OFFLOAD_PATH_TNL)
++		return -EEXIST;
++
++	session = pppol2tp_sock_to_session(sk);
++	if (!session)
++		return -EINVAL;
++
++	path->flags |= FLOW_OFFLOAD_PATH_TNL;
++
++	return 0;
++}
++#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
++
+ /* Transmit function called by generic PPP driver.  Sends PPP frame
+  * over PPPoL2TP socket.
+  *