[][MAC80211][hnat][Add WiFi Roaming feature]
[Description]
Add WiFi Roaming feature.
Without this patch, the traffic may stop over 30 seconds when the
WiFi roams.
[Release-log]
N/A
Change-Id: I22d8b003b538d5cb4bfd063d864da409875827e2
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8915195
diff --git a/21.02/files/target/linux/mediatek/mt7981/config-5.4 b/21.02/files/target/linux/mediatek/mt7981/config-5.4
index 045b2d0..6ca512d 100644
--- a/21.02/files/target/linux/mediatek/mt7981/config-5.4
+++ b/21.02/files/target/linux/mediatek/mt7981/config-5.4
@@ -308,6 +308,7 @@
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NETFILTER=y
+CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_XTABLES=m
CONFIG_NETFILTER_XT_NAT=m
CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
@@ -321,6 +322,8 @@
CONFIG_NET_MEDIATEK_SOC=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NET_VENDOR_MEDIATEK=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_FLOW_TABLE=y
CONFIG_NLS=y
CONFIG_NMBM=y
# CONFIG_NMBM_LOG_LEVEL_DEBUG is not set
diff --git a/21.02/files/target/linux/mediatek/mt7986/config-5.4 b/21.02/files/target/linux/mediatek/mt7986/config-5.4
index 880e675..fa956d1 100644
--- a/21.02/files/target/linux/mediatek/mt7986/config-5.4
+++ b/21.02/files/target/linux/mediatek/mt7986/config-5.4
@@ -351,6 +351,7 @@
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NETFILTER=y
+CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_XTABLES=m
CONFIG_NETFILTER_XT_NAT=m
CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
@@ -367,6 +368,7 @@
CONFIG_NET_VENDOR_MEDIATEK=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_FLOW_TABLE=y
CONFIG_NF_NAT=m
CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NLS=y
diff --git a/21.02/files/target/linux/mediatek/mt7988/config-5.4 b/21.02/files/target/linux/mediatek/mt7988/config-5.4
index 747c9d2..dcd85c1 100644
--- a/21.02/files/target/linux/mediatek/mt7988/config-5.4
+++ b/21.02/files/target/linux/mediatek/mt7988/config-5.4
@@ -328,6 +328,11 @@
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_INGRESS=y
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_NAT=m
+CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
# CONFIG_NET_DSA_AN8855 is not set
@@ -338,6 +343,10 @@
CONFIG_NET_MEDIATEK_SOC=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NET_VENDOR_MEDIATEK=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_FLOW_TABLE=y
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NLS=y
CONFIG_NMBM=y
# CONFIG_NMBM_LOG_LEVEL_DEBUG is not set
diff --git a/autobuild_mac80211_release/target/linux/mediatek/patches-5.4/999-3025-flow-offload-add-mtkhnat-roaming.patch b/autobuild_mac80211_release/target/linux/mediatek/patches-5.4/999-3025-flow-offload-add-mtkhnat-roaming.patch
new file mode 100644
index 0000000..c4056d8
--- /dev/null
+++ b/autobuild_mac80211_release/target/linux/mediatek/patches-5.4/999-3025-flow-offload-add-mtkhnat-roaming.patch
@@ -0,0 +1,259 @@
+From c48cf95d7a02fe00bcc5b761901a587653eda7ac Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Tue, 9 Apr 2024 18:06:36 +0800
+Subject: [PATCH] 999-3025-flow-offload-add-mtkhnat-roaming
+
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 +
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 3 +
+ drivers/net/ethernet/mediatek/mtk_ppe.c | 169 ++++++++++++++++++++
+ drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +
+ 4 files changed, 182 insertions(+)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+index 755a5c9..a508fa9 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -4042,6 +4042,12 @@ static int mtk_open(struct net_device *dev)
+ if (err)
+ return err;
+
++ if (eth->soc->offload_version) {
++ err = mtk_ppe_roaming_start(eth);
++ if (err)
++ netdev_err(dev, "%s: could not start ppe roaming work: %d\n",
++ __func__, err);
++ }
+
+ /* Indicates CDM to parse the MTK special tag from CPU */
+ if (netdev_uses_dsa(dev)) {
+@@ -4220,6 +4226,8 @@ static int mtk_stop(struct net_device *dev)
+ if (eth->soc->offload_version) {
+ for (i = 0; i < eth->ppe_num; i++)
+ mtk_ppe_stop(eth->ppe[i]);
++
++ mtk_ppe_roaming_stop(eth);
+ }
+
+ return 0;
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+index d958aec..811ee58 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -1963,6 +1963,9 @@ struct mtk_eth {
+ u8 ppe_num;
+ struct mtk_ppe *ppe[MTK_MAX_PPE_NUM];
+ struct rhashtable flow_table;
++ struct socket *ppe_roam_sock;
++ struct work_struct ppe_roam_work;
++ unsigned char ppe_roam_buf[1024];
+ };
+
+ /* struct mtk_mac - the structure that holds the info about the MACs of the
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
+index c054df0..bc30a1a 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -11,6 +11,7 @@
+ #include <linux/ip.h>
+ #include <net/dsa.h>
+ #include <net/route.h>
++#include <net/netfilter/nf_flow_table.h>
+ #include "mtk_eth_soc.h"
+ #include "mtk_ppe.h"
+ #include "mtk_ppe_regs.h"
+@@ -582,6 +583,28 @@ bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data
+ return !memcmp(&entry->data, &data->data, len - 4);
+ }
+
++static bool mtk_foe_mac_match(struct mtk_foe_entry *entry, u8 *mac)
++{
++ int type;
++
++ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
++ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
++ if(((swab32(entry->ipv6.l2.dest_mac_hi) == *(u32 *)mac) &&
++ (swab16(entry->ipv6.l2.dest_mac_lo) == *(u16 *)&mac[4])) ||
++ ((swab32(entry->ipv6.l2.src_mac_hi) == *(u32 *)mac) &&
++ (swab16(entry->ipv6.l2.src_mac_lo) == *(u16 *)&mac[4])))
++ return true;
++ } else {
++ if(((swab32(entry->ipv4.l2.dest_mac_hi) == *(u32 *)mac) &&
++ (swab16(entry->ipv4.l2.dest_mac_lo) == *(u16 *)&mac[4])) ||
++ ((swab32(entry->ipv4.l2.src_mac_hi) == *(u32 *)mac) &&
++ (swab16(entry->ipv4.l2.src_mac_lo) == *(u16 *)&mac[4])))
++ return true;
++ }
++
++ return false;
++}
++
+ int mtk_foe_entry_set_sp(struct mtk_ppe *ppe, struct mtk_foe_entry *entry)
+ {
+ struct mtk_foe_entry *hwe;
+@@ -1184,3 +1207,149 @@ int mtk_ppe_stop(struct mtk_ppe *ppe)
+
+ return 0;
+ }
++
++int mtk_flow_offload_teardown_by_mac(struct mtk_ppe *ppe, u8 *mac)
++{
++ int i, j, count = 0;
++
++ for (i = 0; i < MTK_PPE_ENTRIES; i++) {
++ struct mtk_foe_entry *entry = &ppe->foe_table[i];
++ struct flow_offload_tuple tuple;
++ int type, state;
++
++ state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1);
++ if (state != MTK_FOE_STATE_BIND || !mtk_foe_mac_match(entry, mac))
++ continue;
++
++ memset(&tuple, 0, sizeof(tuple));
++
++ if (entry->ib1 & MTK_FOE_IB1_UDP)
++ tuple.l4proto = IPPROTO_UDP;
++ else
++ tuple.l4proto = IPPROTO_TCP;
++
++ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
++ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
++ tuple.l3proto = NFPROTO_IPV6;
++ tuple.src_port = htons(entry->ipv6.src_port);
++ tuple.dst_port = htons(entry->ipv6.src_port);
++ for (j = 0; j < 4; j ++) {
++ tuple.src_v6.s6_addr32[j] = htonl(entry->ipv6.src_ip[j]);
++ tuple.dst_v6.s6_addr32[j] = htonl(entry->ipv6.dest_ip[j]);
++ }
++ } else {
++ tuple.l3proto = NFPROTO_IPV4;
++ tuple.src_port = htons(entry->ipv4.orig.src_port);
++ tuple.dst_port = htons(entry->ipv4.orig.dest_port);
++ tuple.src_v4.s_addr = htonl(entry->ipv4.orig.src_ip);
++ tuple.dst_v4.s_addr = htonl(entry->ipv4.orig.dest_ip);
++ }
++
++ flow_offload_teardown_by_tuple(&tuple);
++ count++;
++
++ pr_info("mtk_ppe: the roamiing entry (%x) has been deleted\n", i);
++ }
++
++ if (!count)
++ pr_warn("mtk_ppe: the roaming entry is not found\n");
++
++ return count;
++}
++
++static void mtk_ppe_roam_handler(struct work_struct *work)
++{
++ struct mtk_eth *eth = container_of(work, struct mtk_eth, ppe_roam_work);
++ struct kvec iov;
++ struct msghdr msg;
++ struct nlmsghdr *nlh;
++ struct ndmsg *ndm;
++ struct nlattr *nla;
++ int len, ifindex, i;
++ u8 mac[ETH_ALEN];
++
++ if (!eth->ppe_roam_sock)
++ return;
++
++ iov.iov_base = eth->ppe_roam_buf;
++ iov.iov_len = sizeof(eth->ppe_roam_buf);
++ memset(&msg, 0, sizeof(msg));
++ msg.msg_namelen = sizeof(struct sockaddr_nl);
++
++ len = kernel_recvmsg(eth->ppe_roam_sock, &msg, &iov, 1, iov.iov_len, 0);
++ if (len <= 0)
++ goto out;
++
++ nlh = (struct nlmsghdr*)eth->ppe_roam_buf;
++ if (!NLMSG_OK(nlh, len) || nlh->nlmsg_type != RTM_NEWNEIGH)
++ goto out;
++
++ len = nlh->nlmsg_len - NLMSG_HDRLEN;
++ ndm = (struct ndmsg *)NLMSG_DATA(nlh);
++ if (ndm->ndm_family != PF_BRIDGE)
++ goto out;
++
++ ifindex = ndm->ndm_ifindex;
++ nla = (struct nlattr *)((unsigned char *)ndm + sizeof(struct ndmsg));
++ len -= NLMSG_LENGTH(sizeof(struct ndmsg));
++ while (nla_ok(nla, len)) {
++ if (nla_type(nla) == NDA_LLADDR) {
++ memcpy(mac, nla_data(nla), ETH_ALEN);
++ for (i = 0; i < eth->ppe_num; i++)
++ mtk_flow_offload_teardown_by_mac(eth->ppe[i], mac);
++ pr_info("mtk_ppe: the neighbor (%pM) has been updated\n", mac);
++ }
++ nla = nla_next(nla, &len);
++ }
++
++out:
++ schedule_work(ð->ppe_roam_work);
++}
++
++int mtk_ppe_roaming_start(struct mtk_eth *eth)
++{
++ struct socket *sock = NULL;
++ struct sockaddr_nl addr;
++ int ret;
++
++ INIT_WORK(ð->ppe_roam_work, mtk_ppe_roam_handler);
++
++ ret = sock_create_kern(&init_net, AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, &sock);
++ if (ret < 0)
++ goto out;
++
++ eth->ppe_roam_sock = sock;
++
++ addr.nl_family = AF_NETLINK;
++ addr.nl_pad = 0;
++ addr.nl_pid = 65534;
++ addr.nl_groups = 1 << (RTNLGRP_NEIGH - 1);
++ ret = kernel_bind(sock, (struct sockaddr *)&addr, sizeof(addr));
++ if (ret < 0)
++ goto out;
++
++ schedule_work(ð->ppe_roam_work);
++
++ pr_info("mtk_ppe: roaming work has been activated\n");
++
++ return 0;
++
++out:
++ if (sock)
++ sock_release(sock);
++
++ return ret;
++}
++
++int mtk_ppe_roaming_stop(struct mtk_eth *eth)
++{
++ if (!eth->ppe_roam_sock)
++ return -ENOENT;
++
++ sock_release(eth->ppe_roam_sock);
++ eth->ppe_roam_sock = NULL;
++
++ pr_info("mtk_ppe: roaming work has been deactivated\n");
++
++ return 0;
++}
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
+index bafbffc..68295b0 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
+@@ -396,6 +396,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int versio
+ int accounting);
+ int mtk_ppe_start(struct mtk_ppe *ppe);
+ int mtk_ppe_stop(struct mtk_ppe *ppe);
++int mtk_ppe_roaming_start(struct mtk_eth *eth);
++int mtk_ppe_roaming_stop(struct mtk_eth *eth);
+
+ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash);
+
+--
+2.18.0
+