[Feature][T106_eSDK]update from T106-V2.01.01.02P56U06.AP.15.11_CAP.15.11.01 to T106-V2.01.01.02P56U06.AP.17.02_CAP.17.02.02 -- code

Only Configure: No
Affected branch: master
Affected module: unknow
Is it affected on both ZXIC and MTK: only ZXIC
Self-test: Yes
Doc Update: No

Change-Id: Ib96b45ce27a9cc1e8e774c42334dfb86aa0da634
diff --git a/upstream/linux-5.10/net/8021q/vlan_dev.c b/upstream/linux-5.10/net/8021q/vlan_dev.c
index 86a1c99..6117e9c 100755
--- a/upstream/linux-5.10/net/8021q/vlan_dev.c
+++ b/upstream/linux-5.10/net/8021q/vlan_dev.c
@@ -94,7 +94,7 @@
 	return NETDEV_TX_OK;
 #endif
 }
-
+extern void fast_update_indev(struct sk_buff *skb, struct net_device *dev);
 static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
 					    struct net_device *dev)
 {
@@ -120,7 +120,7 @@
 	len = skb->len;
 	if (unlikely(netpoll_tx_running(dev)))
 		return vlan_netpoll_send_skb(vlan, skb);
-
+	fast_update_indev(skb, dev);
 	ret = dev_queue_xmit(skb);
 
 	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
diff --git a/upstream/linux-5.10/net/bridge/br_fdb.c b/upstream/linux-5.10/net/bridge/br_fdb.c
index 65a6054..974ee5e 100755
--- a/upstream/linux-5.10/net/bridge/br_fdb.c
+++ b/upstream/linux-5.10/net/bridge/br_fdb.c
@@ -1313,7 +1313,7 @@
 	u16 vid = 0;
 	int ntl_port_id = 0xff;
 	
-	if(!skb->dev)
+	if(!skb->dev || fastbr_level != 1)
 	{
 		//print_sun(SUN_DBG, "fast_br  skb->dev err skb->dev = %x\n", skb->dev);
 		return 0;
diff --git a/upstream/linux-5.10/net/core/SI/net_other.c b/upstream/linux-5.10/net/core/SI/net_other.c
index a6748c7..816686b 100755
--- a/upstream/linux-5.10/net/core/SI/net_other.c
+++ b/upstream/linux-5.10/net/core/SI/net_other.c
@@ -1090,7 +1090,8 @@
 int  fast_local4_output_num = 0;    //±¾µØfast_local4³É¹¦·¢Ëͱ¨ÎÄ
 int  fast_local6_output_num = 0;    //±¾µØfast_local6³É¹¦·¢Ëͱ¨ÎÄ
 int  fast_tcpdump_num = 0;          //fast×¥°üÊýÁ¿
-
+int  skb_expand4 = 0;               //Í·¿Õ¼ä²»¹»ÖØÐÂÉêÇëµÄV4Êý¾Ý°ü
+int  skb_expand6 = 0;               //Í·¿Õ¼ä²»¹»ÖØÐÂÉêÇëµÄV6Êý¾Ý°ü
 
 int double_mac = 0; //mac¼ì²é¿ª¹Ø
 //slabÄÚ´æÊ¹ÓÃÏà¹ØÍ³¼Æ£¬Î´¿¼ÂÇͨÓÃslabµØÖ·³Ø£¬Èçkmalloc
diff --git a/upstream/linux-5.10/net/core/fastproc/fast4_fw.c b/upstream/linux-5.10/net/core/fastproc/fast4_fw.c
index 0ef32e4..a0674f9 100755
--- a/upstream/linux-5.10/net/core/fastproc/fast4_fw.c
+++ b/upstream/linux-5.10/net/core/fastproc/fast4_fw.c
@@ -67,6 +67,7 @@
 /* ******************************** º¯ÊýʵÏÖ ********************************/
 int dst_expire_count = 0;
 extern int no_neighbour;
+extern fast_list_t working_list;
 
 static inline int rt_is_expired(struct rtable *rth)
 {
@@ -555,7 +556,11 @@
 	{
 		ret = ifname_compare_aligned(ct->indev[dir]->name, ipinfo->iniface, ipinfo->iniface_mask);
 	}
-	
+	else
+	{
+		ret=1;
+	}
+
 	if(ipinfo->iniface[0] != '\0')
 		*match_filter = 1;
 		
@@ -583,6 +588,8 @@
 ip_packet_match_neg(const struct ipt_ip *ipinfo,struct nf_conn* ct,int dir, int* match_filter)
 {
 	unsigned long ret;
+	if(!(ct->status & IPS_NAT_MASK))
+		return false;
 	if (NF_INVF(ipinfo, IPT_INV_SRCIP,
 		    (ct->tuplehash[dir].tuple.dst.u3.ip & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
 	    NF_INVF(ipinfo, IPT_INV_DSTIP,
@@ -595,7 +602,11 @@
 	{
 		ret = ifname_compare_aligned(ct->outdev[dir]->name, ipinfo->iniface, ipinfo->iniface_mask);
 	}
-	
+	else
+	{
+		ret = 1;
+	}
+
 	if(ipinfo->iniface[0] != '\0')
 		*match_filter = 1;
 		
@@ -675,7 +686,7 @@
 			e = get_entry(table_base, private->hook_entry[NF_INET_LOCAL_IN]);
 			break;
 		default:
-			break;
+			return;
 	}
 	while(num--)
 	{
@@ -747,8 +758,7 @@
 
 static void ct_iptables_bhfunc(unsigned long param)
 {
-	int hash = 0;
-	struct nf_conntrack_tuple_hash *h;
+	fast_entry_t *ret = NULL;
 	struct hlist_nulls_node *n;
 	struct nf_conn *ct;
 	struct xt_table_info *private;
@@ -756,13 +766,12 @@
 	unsigned int addend;
 	local_bh_disable();
 	addend = xt_write_recseq_begin();
-	for(hash = 0; hash < nf_conntrack_htable_size; hash++)
-    {
-	   	hlist_nulls_for_each_entry_rcu(h,n,&nf_conntrack_hash[hash],hnnode)
+	spin_lock_bh(&fast_fw_spinlock);
+	for (ret = (&working_list)->next; ret; ret = ret->next)
+	{
+		if(ret)
 		{
-	   		if(h)
-			{
-	   			ct = nf_ct_tuplehash_to_ctrack(h);
+	   			ct = ret->ct;
 				if(ct->fast_ct.isFast)
 				{
 					net = nf_ct_net(ct);
@@ -777,19 +786,66 @@
 				}
 				else
 					continue;
-				spin_lock_bh(&fast_fw_spinlock);
+
 				ct->packet_info[IP_CT_DIR_ORIGINAL].bytes = 0;
 				ct->packet_info[IP_CT_DIR_ORIGINAL].packets = 0;
 				ct->packet_info[IP_CT_DIR_REPLY].bytes = 0;
 				ct->packet_info[IP_CT_DIR_REPLY].packets = 0;
-				spin_unlock_bh(&fast_fw_spinlock);
-			}
-	   	}
-    }
+		}
+	}
+	spin_unlock_bh(&fast_fw_spinlock);
 	xt_write_recseq_end(addend);
 	local_bh_enable();
 }
 
+#if 0
+/*ÐÂfastÏÂiptablesͬ²½µÄ´úÂ루±£Áô£©*/
+/* Started by AICoder, pid:bc328v3b69u30bb14fea08b4d0be594808c2486b */
+static void ct_iptables_bhfunc(unsigned long param)
+{
+    unsigned int addend;
+    local_bh_disable();
+    addend = xt_write_recseq_begin();
+    spin_lock_bh(&fast_fw_spinlock);
+    for(int hash = 0; hash < nf_conntrack_htable_size; hash++)
+    {
+        struct nf_conntrack_tuple_hash *h;
+        struct hlist_nulls_node *n;
+        for_each_rcu_safe(h, n, &nf_conntrack_hash[hash])
+        {
+            if(h)
+            {
+                struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
+                if(ct->fast_ct.isFast)
+                {
+                    struct net *net = nf_ct_net(ct);
+                    struct xt_table_info *private;
+                    const char *chain_names[] = {
+                        "IPTABLE_RAW",
+                        "IPTABLE_MANGLE",
+                        "IPTABLE_NAT",
+                        "IPTABLE_FILTER"
+                    };
+                    for (int i = 0; i < 4; i++) {
+                        switch (i) {
+                            case 0: private = READ_ONCE(net->ipv4.iptable_raw->private); break;
+                            case 1: private = READ_ONCE(net->ipv4.iptable_mangle->private); break;
+                            case 2: private = READ_ONCE(net->ipv4.nat_table->private); break;
+                            case 3: private = READ_ONCE(net->ipv4.iptable_filter->private); break;
+                        }
+                        ct_iptables_syn_handle(ct, private, chain_names[i]);
+                    }
+                }
+            }
+        }
+    }
+    spin_unlock_bh(&fast_fw_spinlock);
+    xt_write_recseq_end(addend);
+    local_bh_enable();
+}
+/* Ended by AICoder, pid:bc328v3b69u30bb14fea08b4d0be594808c2486b */
+#endif
+
 
 int fast4_fw_init(void)
 {
diff --git a/upstream/linux-5.10/net/core/fastproc/fast6.c b/upstream/linux-5.10/net/core/fastproc/fast6.c
index d5fab9c..5beebba 100755
--- a/upstream/linux-5.10/net/core/fastproc/fast6.c
+++ b/upstream/linux-5.10/net/core/fastproc/fast6.c
@@ -207,7 +207,9 @@
     __u8 next_hdr = 0;
     unsigned char *l4head;
     struct ipv6hdr *ip6;
-    
+	struct sk_buff *skb2 = NULL;
+	int l4_offset = 0;
+	
     print_sun(SUN_DBG, "enter fast_6_recv \n");
 
     if (fastnat_level == FAST_CLOSE)
@@ -286,13 +288,18 @@
         print_sun(SUN_DBG, "fast_6_recv l4head is null \n");
         return 0;
     }
-
-
-
-    if (!(skb = fast_expand_headroom_v6(skb, dev))){
+	l4_offset = l4head - skb->data;
+	
+    if (!(skb2 = fast_expand_headroom_v6(skb, dev))){
 		rcu_read_unlock();
         return 1;
     }
+	
+	if(skb2 != skb){
+		l4head = skb2->data + l4_offset;
+		skb = skb2;
+		skb_expand6++;
+	}
 
     fast_tcpdump(skb);
     
@@ -316,8 +323,30 @@
     skb->isFastnat = 1;
     skb->priority = fast6_entry_data->priority;
     skb->mark = fast6_entry_data->mark;
-
-
+	if (likely(skb_get_nfct(skb) == 0)){
+		skb_set_nfct(skb, (unsigned long)fast6_entry->ct);
+		nf_conntrack_get(&fast6_entry->ct->ct_general);
+	}
+	spin_lock_bh(&fast_fw_spinlock);
+    //»ùÓÚctÁ´½ÓµÄÁ÷Á¿Í³¼Æ --- ͳ¼ÆIP°ü²»ÊÇMAC°ü
+    if (fast6_entry_data->tuplehash.tuple.dst.dir == IP_CT_DIR_ORIGINAL){
+        fast6_entry->ct->packet_info[IP_CT_DIR_ORIGINAL].packets++;
+        fast6_entry->ct->packet_info[IP_CT_DIR_ORIGINAL].bytes += skb->len;
+		if(unlikely(fast6_entry->ct->indev[IP_CT_DIR_ORIGINAL] == NULL))
+			fast6_entry->ct->indev[IP_CT_DIR_ORIGINAL] = skb->indev;
+		if(unlikely(fast6_entry->ct->outdev[IP_CT_DIR_ORIGINAL] == NULL))
+			fast6_entry->ct->outdev[IP_CT_DIR_ORIGINAL] = dev;
+    } else if (fast6_entry_data->tuplehash.tuple.dst.dir == IP_CT_DIR_REPLY){
+        fast6_entry->ct->packet_info[IP_CT_DIR_REPLY].packets++;
+        fast6_entry->ct->packet_info[IP_CT_DIR_REPLY].bytes += skb->len;
+		if(unlikely(fast6_entry->ct->indev[IP_CT_DIR_REPLY] == NULL))
+			fast6_entry->ct->indev[IP_CT_DIR_REPLY] = skb->indev;
+		if(unlikely(fast6_entry->ct->outdev[IP_CT_DIR_REPLY] == NULL))
+			fast6_entry->ct->outdev[IP_CT_DIR_REPLY] = dev;
+    } else {
+        printk("fast6 packet error\n");
+    }
+	spin_unlock_bh(&fast_fw_spinlock);
     //ÄÚºË×Ô´øµÄ»ùÓÚÁ´½ÓµÄÁ÷Á¿Í³¼Æ
     struct nf_conn_counter *acct = (struct nf_conn_counter*)nf_conn_acct_find(fast6_entry->ct);
     if (acct) {
@@ -348,7 +377,8 @@
 
     //Ö»Óе±ÓÐMACÍ·Ô¤¸³ÖµÊ±£¬²Å×¼¸³Öµ£¬·ñÔòΪIPÍ·
     skb_push(skb, ETH_HLEN);
-
+	
+    if (fast6_entry_data->hh_flag)
     memcpy(skb->data, fast6_entry_data->hh_data, ETH_HLEN);
     /*¸üÐÂÁ¬½Ó³¬Ê±*/
     if (IPPROTO_TCP == tuple.dst.protonum)
@@ -470,12 +500,12 @@
         return NF_ACCEPT;
     }
 	_neighbour = dst_neigh_lookup_skb(dst, skb);
-	if(!_neighbour)
-	{
-		return NF_ACCEPT;
+	if(_neighbour == NULL && ((ipv6_addr_type(&ipv6_hdr(skb)->daddr)) == IPV6_ADDR_ANY 
+		|| ((ipv6_addr_type(&ipv6_hdr(skb)->daddr)) & IPV6_ADDR_LOOPBACK))){
+        return NF_ACCEPT;
 	}
     
-    if (memcmp(_neighbour->ha, zeromac, ETH_ALEN) == 0)
+    if (_neighbour && memcmp(_neighbour->ha, zeromac, ETH_ALEN) == 0)
     {
         goto accept;
     }
@@ -536,9 +566,10 @@
     fast6_entry_data = &fast6_entry->data[dir];
     fast6_entry_data->tuplehash.tuple = ct->tuplehash[dir].tuple;
 
-    memcpy(fast6_entry_data->dmac, _neighbour->ha, ETH_ALEN);
+    //memcpy(fast6_entry_data->dmac, _neighbour->ha, ETH_ALEN);
     fast6_entry_data->priority = skb->priority;
     fast6_entry_data->mark = skb->mark;
+	if(fast6_entry_data->outdev == NULL){
     fast6_entry_data->outdev = out;
 
     if (!record_MAC_header(working_hash6, ct, fast6_entry, fast6_entry_data, _neighbour, out, htons(ETH_P_IPV6)))
@@ -546,7 +577,7 @@
         spin_unlock_bh(&fast6_spinlock);
         goto accept;
     }
-
+	}
     //´Ë´¦±£Ö¤Õý·´Á½¸ö±ê¼Çλ²»³åÍ»
     fast6_entry->flags = fast6_entry->flags | (1 << dir);
     
@@ -563,7 +594,7 @@
     ct->fast_ct.isFast = FAST_CT_WND6;
 
 accept:
-	
+	if(_neighbour)
 	neigh_release(_neighbour);
     return NF_ACCEPT;
 }
diff --git a/upstream/linux-5.10/net/core/fastproc/fast6_fw.c b/upstream/linux-5.10/net/core/fastproc/fast6_fw.c
index 322175b..ec21bc6 100755
--- a/upstream/linux-5.10/net/core/fastproc/fast6_fw.c
+++ b/upstream/linux-5.10/net/core/fastproc/fast6_fw.c
@@ -40,8 +40,23 @@
 #include <net/SI/net_cache.h>
 #include <net/SI/print_sun.h>
 
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+
 MODULE_LICENSE("GPL");
 
+static struct task_struct *ct_ip6tables_syn;
+static struct tasklet_struct ct_ip6tables_bh;
+extern unsigned int ct_iptables_syn_sw;
+enum table6_index {
+	IP6TABLE_RAW,
+	IP6TABLE_MANGLE,
+	IP6TABLE_NAT,
+	IP6TABLE_FILTER
+};
+
+
 /* ***************** ipv6 ¿ìËÙת·¢Ïà¹Ø±äÁ¿ ************************* */
 
 
@@ -53,6 +68,7 @@
 
 int dst_expire_count_v6 = 0;
 extern int no_neighbour;
+extern fast_list_t working_list6;
 extern void ntl_ct_set_iw(struct sk_buff *skb, struct nf_conn *ct, int ct_dir);
 int fast6_fw_recv(struct nf_conn *tmpl,
                   struct sk_buff *skb,
@@ -163,7 +179,8 @@
     skb->isFastnat = 1;
     nf_ct_set(skb, (struct nf_conn *)&ct->ct_general, ctinfo);
 
-
+	ct->packet_info[dir].packets++;
+    ct->packet_info[dir].bytes += skb->len;
     //»ùÓÚÍø¿ÚµÄÁ÷Á¿Í³¼Æ  --- ²Î¿¼linuxÔ­ÉúµÄÇý¶¯£¬Í³¼ÆµÄ¶¼ÊÇIP°ü³¤¶È
     if (fastnat_level == FAST_NET_DEVICE)
     {
@@ -203,6 +220,17 @@
         }
         skb->dev = dev;
         skb->now_location |= FASTNAT_SUCC;
+
+		if(ct->indev[dir] == NULL && skb->indev != NULL)
+		{
+			ct->indev[dir] = skb->indev;
+		}
+		
+		if(ct->outdev[dir] == NULL && skb->dev != NULL)
+		{
+			ct->outdev[dir] = skb->dev;
+		}
+
 		skb->vlan_proto = vlan_proto_raw;
 		skb->vlan_tci = vlan_tci_raw;
         __flush_dcache_area(skb->data, skb->len);
@@ -370,6 +398,372 @@
     .priority = NF_IP6_PRI_LAST,
 };
 
+static inline bool
+port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert)
+{
+	return (port >= min && port <= max) ^ invert;
+}
+
+static bool ctable_mt(struct nf_conn* ct, struct xt_action_param *par,int dir, int* match_filter)
+{
+	const struct xt_tcp *tcpinfo = par->matchinfo;
+
+	if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
+			ntohs(ct->tuplehash[dir].tuple.src.u.tcp.port),
+			!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
+		return false;
+	if((tcpinfo->spts[0] || tcpinfo->spts[1]) ^ (!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
+		*match_filter = 1;
+	if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
+			ntohs(ct->tuplehash[dir].tuple.dst.u.tcp.port),
+			!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
+		return false;
+	if((tcpinfo->dpts[0] || tcpinfo->dpts[1]) ^ (!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
+		*match_filter = 1;
+	return true;
+}
+
+static inline bool
+ip6_packet_match(const struct ip6t_ip6 *ip6info,struct nf_conn* ct,int dir, int* match_filter)
+{
+	unsigned long ret;
+	if (NF_INVF(ip6info, IP6T_INV_SRCIP,
+		    ipv6_masked_addr_cmp((struct in6_addr *)(ct->tuplehash[dir].tuple.src.u3.ip6), &ip6info->smsk,
+					 &ip6info->src)) ||
+	    NF_INVF(ip6info, IP6T_INV_DSTIP,
+		    ipv6_masked_addr_cmp((struct in6_addr *)(ct->tuplehash[dir].tuple.dst.u3.ip6), &ip6info->dmsk,
+					 &ip6info->dst)))
+		return false;
+	if(ip6info->src.in6_u.u6_addr32[0] || ip6info->dst.in6_u.u6_addr32[0])
+	{
+		*match_filter = 1;
+	}
+
+	if(ct->indev[dir] != NULL)
+	{
+		ret = ifname_compare_aligned(ct->indev[dir]->name, ip6info->iniface, ip6info->iniface_mask);
+	}
+	else
+	{
+		ret=1;
+	}
+
+	if(ip6info->iniface[0] != '\0')
+		*match_filter = 1;
+		
+	if (NF_INVF(ip6info, IP6T_INV_VIA_IN, ret != 0))
+		return false;
+	if(ct->outdev[dir] != NULL)
+	{
+		ret = ifname_compare_aligned(ct->outdev[dir]->name, ip6info->outiface, ip6info->outiface_mask);
+	}
+
+	if(ip6info->outiface[0] != '\0')
+		*match_filter = 1;
+
+	if (NF_INVF(ip6info, IP6T_INV_VIA_OUT, ret != 0))
+		return false;
+
+	if (ip6info->flags & IP6T_F_PROTO) {
+		int protohdr;
+
+		protohdr = ct->tuplehash[dir].tuple.dst.protonum;
+
+		if (ip6info->proto == protohdr) {
+			if (ip6info->invflags & IP6T_INV_PROTO)
+				return false;
+
+			return true;
+		}
+
+		/* We need match for the '-p all', too! */
+		if ((ip6info->proto != 0) &&
+			!(ip6info->invflags & IP6T_INV_PROTO))
+			return false;
+	}
+
+	return true;
+}
+
+static inline bool
+ip6_packet_match_neg(const struct ip6t_ip6 *ip6info,struct nf_conn* ct,int dir, int* match_filter)
+{
+	unsigned long ret;
+	if(!(ct->status & IPS_NAT_MASK))
+		return false;
+	if (NF_INVF(ip6info, IP6T_INV_SRCIP,
+		    ipv6_masked_addr_cmp((struct in6_addr *)ct->tuplehash[dir].tuple.src.u3.ip6, &ip6info->smsk,
+					 &ip6info->src)) ||
+	    NF_INVF(ip6info, IP6T_INV_DSTIP,
+		    ipv6_masked_addr_cmp((struct in6_addr *)ct->tuplehash[dir].tuple.dst.u3.ip6, &ip6info->dmsk,
+					 &ip6info->dst)))
+		return false;
+	if(ip6info->src.in6_u.u6_addr32[0] || ip6info->dst.in6_u.u6_addr32[0])
+		*match_filter = 1;
+
+	if(ct->outdev[dir] != NULL)
+	{
+		ret = ifname_compare_aligned(ct->outdev[dir]->name, ip6info->iniface, ip6info->iniface_mask);
+	}
+	else
+	{
+		ret = 1;
+	}
+
+	if(ip6info->iniface[0] != '\0')
+		*match_filter = 1;
+		
+	if (NF_INVF(ip6info, IP6T_INV_VIA_IN, ret != 0))
+		return false;
+	if(ct->indev[dir] != NULL)
+	{
+		ret = ifname_compare_aligned(ct->indev[dir]->name, ip6info->outiface, ip6info->outiface_mask);
+	}
+
+	if(ip6info->outiface[0] != '\0')
+		*match_filter = 1;
+
+	if (NF_INVF(ip6info, IP6T_INV_VIA_OUT, ret != 0))
+		return false;
+
+	if (ip6info->flags & IP6T_F_PROTO) {
+		int protohdr;
+
+		protohdr = ct->tuplehash[dir].tuple.dst.protonum;
+
+		if (ip6info->proto == protohdr) {
+			if (ip6info->invflags & IP6T_INV_PROTO)
+				return false;
+
+			return true;
+		}
+
+		/* We need match for the '-p all', too! */
+		if ((ip6info->proto != 0) &&
+			!(ip6info->invflags & IP6T_INV_PROTO))
+			return false;
+	}
+
+	return true;
+}
+
+static inline struct ip6t_entry *
+get_entry(const void *base, unsigned int offset)
+{
+	return (struct ip6t_entry *)(base + offset);
+}
+
+static inline
+struct ip6t_entry *ip6t_next_entry(const struct ip6t_entry *entry)
+{
+	return (void *)entry + entry->next_offset;
+}
+
+
+
+//ͬ²½ctͳ¼ÆÐÅÏ¢µ½iptables,ͬ²½ÖÜÆÚÔݶ¨1s
+static int ct_ip6tables_syn_thread(void *param)
+{
+	while (1) 
+	{
+		if(ct_iptables_syn_sw)
+		{
+			rcu_read_lock();
+			tasklet_schedule(&ct_ip6tables_bh);
+			rcu_read_unlock();
+			//ÿ´Îͬ²½¼ä¸ôΪ1s.
+		}
+		msleep(1*1000);
+	}
+	return 0;
+}
+
+void ct_ip6tables_syn_handle(struct nf_conn *ct,struct xt_table_info *private,int table_id)
+{
+	void *table_base;
+	struct ip6t_entry *e;
+	const struct xt_entry_match *ematch;
+	struct xt_action_param acpar;
+	struct xt_counters *counter;
+	int match_flag = 0;
+	int match_filter = 0;
+	int num = 0;
+
+
+	table_base = private->entries;
+	num = private->number;
+	switch(table_id)
+	{
+		case 0:
+		case 1:
+		case 2:
+			e = get_entry(table_base, private->hook_entry[NF_INET_PRE_ROUTING]);
+			break;
+		case 3:
+			e = get_entry(table_base, private->hook_entry[NF_INET_LOCAL_IN]);
+			break;
+		default:
+			return;
+	}
+	while(num--)
+	{
+		match_flag = 0;
+		match_filter = 0;
+		if(!ip6_packet_match(&e->ipv6, ct, IP_CT_DIR_ORIGINAL,&match_filter) &&
+			!ip6_packet_match_neg(&e->ipv6, ct, IP_CT_DIR_REPLY,&match_filter))
+		{
+		}
+		else
+		{
+			xt_ematch_foreach(ematch, e) 
+			{
+				acpar.matchinfo = ematch->data;
+				if (!ctable_mt(ct, &acpar, IP_CT_DIR_ORIGINAL,&match_filter))
+				{
+					match_flag = 1;
+					break;
+				}
+				else
+				{
+				}
+			}
+			if(!match_flag)
+			{
+				if(match_filter)
+				{
+					counter = xt_get_this_cpu_counter(&e->counters);
+					ADD_COUNTER(*counter, ct->packet_info[IP_CT_DIR_ORIGINAL].bytes,ct->packet_info[IP_CT_DIR_ORIGINAL].packets);
+				}
+				e = ip6t_next_entry(e);
+				continue;
+			}
+			match_flag = 0;
+			match_filter = 0;
+		}
+		
+		if (!ip6_packet_match(&e->ipv6, ct, IP_CT_DIR_REPLY,&match_filter) &&
+			!ip6_packet_match_neg(&e->ipv6, ct, IP_CT_DIR_ORIGINAL,&match_filter))
+		{
+			e = ip6t_next_entry(e);
+			continue;
+		}
+		else
+		{
+			xt_ematch_foreach(ematch, e) 
+			{
+				acpar.matchinfo = ematch->data;
+				if (!ctable_mt(ct, &acpar, IP_CT_DIR_REPLY,&match_filter))
+				{
+					match_flag = 1;
+					break;
+				}
+			}
+			if(!match_flag)
+			{
+				if(match_filter)
+				{
+					counter = xt_get_this_cpu_counter(&e->counters);
+					ADD_COUNTER(*counter, ct->packet_info[IP_CT_DIR_REPLY].bytes,ct->packet_info[IP_CT_DIR_REPLY].packets);
+				}
+				e = ip6t_next_entry(e);
+				continue;
+			}
+		}
+	}
+
+}
+
+static void ct_ip6tables_bhfunc(unsigned long param)
+{
+	fast_entry_t *ret = NULL;
+	struct hlist_nulls_node *n;
+	struct nf_conn *ct;
+	struct xt_table_info *private;
+	struct net * net;
+	unsigned int addend;
+	local_bh_disable();
+	addend = xt_write_recseq_begin();
+	spin_lock_bh(&fast_fw_spinlock);
+	for (ret = (&working_list6)->next; ret; ret = ret->next)
+	{
+		if(ret)
+		{
+	   			ct = ret->ct;
+				if(ct->fast_ct.isFast)
+				{
+					net = nf_ct_net(ct);
+					private = READ_ONCE(net->ipv6.ip6table_raw->private);
+					ct_ip6tables_syn_handle(ct,private,IP6TABLE_RAW);
+					private = READ_ONCE(net->ipv6.ip6table_mangle->private);
+					ct_ip6tables_syn_handle(ct,private,IP6TABLE_MANGLE);
+					private = READ_ONCE(net->ipv6.ip6table_nat->private);
+					ct_ip6tables_syn_handle(ct,private,IP6TABLE_NAT);
+					private = READ_ONCE(net->ipv6.ip6table_filter->private);	
+					ct_ip6tables_syn_handle(ct,private,IP6TABLE_FILTER);
+				}
+				else
+					continue;
+
+				ct->packet_info[IP_CT_DIR_ORIGINAL].bytes = 0;
+				ct->packet_info[IP_CT_DIR_ORIGINAL].packets = 0;
+				ct->packet_info[IP_CT_DIR_REPLY].bytes = 0;
+				ct->packet_info[IP_CT_DIR_REPLY].packets = 0;
+		}
+	}
+	spin_unlock_bh(&fast_fw_spinlock);
+	xt_write_recseq_end(addend);
+	local_bh_enable();
+}
+
+#if 0
+/*ÐÂfast ip6tablesÁ÷Á¿Í¬²½´úÂë,±£Áô*/
+/* Started by AICoder, pid:b1b62d7ef7md76714807099a103c224334833109 */
+static void ct_ip6tables_bhfunc(unsigned long param)
+{
+    int hash;
+    struct nf_conn *ct;
+    struct xt_table_info *private;
+    struct net *net;
+    unsigned int addend;
+    local_bh_disable();
+    addend = xt_write_recseq_begin();
+    for(hash = 0; hash < nf_conntrack_htable_size; hash++)
+    {
+        struct nf_conntrack_tuple_hash *h;
+        struct hlist_nulls_node *n;
+        hlist_nulls_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash], hnnode)
+        {
+            if(h)
+            {
+                ct = nf_ct_tuplehash_to_ctrack(h);
+                if(ct->fast_ct.isFast)
+                {
+                    net = nf_ct_net(ct);
+                    private = READ_ONCE(net->ipv6.ip6table_raw->private);
+                    ct_ip6tables_syn_handle(ct, private, IP6TABLE_RAW);
+                    private = READ_ONCE(net->ipv6.ip6table_mangle->private);
+                    ct_ip6tables_syn_handle(ct, private, IP6TABLE_MANGLE);
+                    private = READ_ONCE(net->ipv6.ip6table_nat->private);
+                    ct_ip6tables_syn_handle(ct, private, IP6TABLE_NAT);
+                    private = READ_ONCE(net->ipv6.ip6table_filter->private);   
+                    ct_ip6tables_syn_handle(ct, private, IP6TABLE_FILTER);
+                    spin_lock_bh(&fast_fw_spinlock);
+                    for(int i = 0; i < 4; i++)
+                    {
+                        ct->packet_info[i].bytes = 0;
+                        ct->packet_info[i].packets = 0;
+                    }
+                    spin_unlock_bh(&fast_fw_spinlock);
+                }
+            }
+        }
+    }
+    xt_write_recseq_end(addend);
+    local_bh_enable();
+}
+/* Ended by AICoder, pid:b1b62d7ef7md76714807099a103c224334833109 */
+#endif
+
 
 int fast6_fw_init(void)
 {
@@ -383,6 +777,14 @@
     }
     print_sun(SUN_DBG,"init fast6_fw_init done\n");
 
+	ct_ip6tables_bh.func = ct_ip6tables_bhfunc;
+	ct_ip6tables_syn = kthread_create(ct_ip6tables_syn_thread, (void *)0, "ct_ip6tables_syn" );
+    if (!IS_ERR(ct_ip6tables_syn))
+    {
+        printk("ntl_syn_task thread's init is succ");
+        wake_up_process(ct_ip6tables_syn);
+    }
+
     return 0;
 }
 
@@ -390,6 +792,12 @@
 {
     fast_release_all(RELEASE_ALL_DST);
     nf_unregister_net_hook(&init_net, &fast6_fw_hook);
+	if (ct_ip6tables_syn) 
+	{
+    	kthread_stop(ct_ip6tables_syn);
+    	ct_ip6tables_syn = NULL;
+	}
+	tasklet_kill(&ct_ip6tables_bh);
     return 0;
 }
 
diff --git a/upstream/linux-5.10/net/core/fastproc/fast_common.c b/upstream/linux-5.10/net/core/fastproc/fast_common.c
index 69f3761..80ad864 100755
--- a/upstream/linux-5.10/net/core/fastproc/fast_common.c
+++ b/upstream/linux-5.10/net/core/fastproc/fast_common.c
@@ -621,7 +621,7 @@
 
 //²Î¿¼ip6_xmit,À©³äskbÍ·²¿
 struct sk_buff *fast_expand_headroom_v6(struct sk_buff *skb, struct net_device *dev) {
-    unsigned int hh_len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr);
+    unsigned int hh_len = LL_RESERVED_SPACE(dev);//EC616000622279½â¾öv6ÉÏÐÐÊý¾Ý°üÓÉÓÚÍ·¿Õ¼ä²»¹»ÖØÐÂÉêÇëµÄÎÊÌâ + sizeof(struct ipv6hdr);
     struct sk_buff *skb2 = NULL;
     if (unlikely(skb_headroom(skb) < hh_len)) {
         skb2 = skb_realloc_headroom(skb, max(hh_len, NET_SKB_PAD));
@@ -726,6 +726,9 @@
 {
     tcpack_rel(entry);
     //nf_ct_put(entry->ct);
+	spin_lock_bh(&fast_fw_spinlock);
+	entry->ct->fast_entry = NULL;
+	spin_unlock_bh(&fast_fw_spinlock);
     atomic_dec(&(entry->ct->ct_general.use));
     fn_list_del(list_head, entry);
 }
@@ -810,6 +813,7 @@
     netslab_inc(FAST_SLAB);
     memset(ret, 0, sizeof(fast_entry_t));
     ret->ct = ct;
+	ct->fast_entry = ret;
     ret->list_head = list_head;
 
     //ÉèÖö¨Ê±Æ÷
@@ -897,7 +901,7 @@
         goto REL;
 
     //½ö¶ÔÒÔÌ«ÍøÀàÍø¿Ú½øÐÐMACÍ·Ô¤¸³Öµ£¬ÆäËüµÄÈçPPP¡¢PPPoEÕâЩ£¬½ÔÊǿɱäµÄ£¬²»ÄÜÔ¤¸³Öµ£»²Î¼ûalloc_netdevºÍalloc_etherdev½Ó¿Ú
-    if (out->type != ARPHRD_ETHER)
+    if (out->type != ARPHRD_ETHER || neigh == NULL)
         return 1;
 
     //¶ÔÓÚ³ö¿ÚÎªÍøÇÅbrʱ£¬Ö±½Ó»ñÈ¡L2ÍøÂçÉ豸£¬¼´usb0»òwifi0
@@ -906,7 +910,7 @@
         if(out->dev_addr == NULL)
             goto REL;
 
-        if (fastbr_level == 1)
+        if (fastbr_level)
         {
             dst_out = getbrport_bydst(out, neigh->ha);
             if (dst_out == NULL)
@@ -964,6 +968,9 @@
     //»Ö¸´ctµÄ³¬Ê±
     //add_timer(&ct->timeout);
     //nf_ct_put(ct);
+	spin_lock_bh(&fast_fw_spinlock);
+	entry->ct->fast_entry = NULL;
+	spin_unlock_bh(&fast_fw_spinlock);
     atomic_dec(&(ct->ct_general.use));
     del_timer(&entry->timeout);
     fn_list_del(entry->list_head, entry);
@@ -1079,7 +1086,9 @@
         del_timer(&entry->timeout);
 
         workinghash_del_node(entry);
-
+		spin_lock_bh(&fast_fw_spinlock);
+		entry->ct->fast_entry = NULL;
+		spin_unlock_bh(&fast_fw_spinlock);
         //»Ö¸´ctµÄ³¬Ê±
         //add_timer(&entry->ct->timeout);
         fn_list_del(list_head, entry);
@@ -1552,7 +1561,7 @@
         return 1;
     }
     //vlan
-    else if (next_pro == cpu_to_be16(ETH_P_8021Q))
+    else if (next_pro == cpu_to_be16(ETH_P_8021Q) && fastbr_level == 1)
     {
         skb->isvlan = 1;
         skb_pull(skb, VLAN_HLEN);
@@ -1591,7 +1600,7 @@
     //if (((unsigned long)skb->data)%4 != 0)
     //panic("ERR: fast from dev skb->data%4 != 0");
 
-    if (skb->indev == NULL)
+    if (skb->indev == NULL || is_vlan_dev(skb->dev))
         skb->indev = skb->dev;
     //ÐèҪ׼ȷ¶¨Î»µ½IPÍ·£¬ÆÚ¼ä¿ÉÄÜÌø¹ýppp/mac/pppoeµÈ¸÷ÖÖ²ã2Í·²¿
     if (set_skbdata_toip(skb) == 1 && fast_for_ipdata(skb))
@@ -2055,6 +2064,21 @@
     return dst;
 }
 
+void fast_update_indev(struct sk_buff *skb, struct net_device *dev)
+{
+	if(fastbr_level != 1 && skb->isFastnat == 1){
+		enum ip_conntrack_info ctinfo;
+		struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+		
+		if(ct){
+			if(ct->indev[0] == skb->indev && ct->indev[1] == NULL)
+				ct->indev[1] = dev;
+			if(ct->indev[1] == skb->indev && ct->indev[0] == NULL)
+				ct->indev[0] = dev;
+		}
+	}
+}
+
 /*fast³õʼ»¯*/
 static int __init
 tsp_fast_init(void)
diff --git a/upstream/linux-5.10/net/core/fastproc/fast_track.c b/upstream/linux-5.10/net/core/fastproc/fast_track.c
index 37f3cfc..712ff6d 100755
--- a/upstream/linux-5.10/net/core/fastproc/fast_track.c
+++ b/upstream/linux-5.10/net/core/fastproc/fast_track.c
@@ -234,7 +234,7 @@
     if (copy_from_user(char_fastbr, buffer, 1))

         return -EFAULT;

 

-    if (char_fastbr[0] < '0' || char_fastbr[0] > '1')

+    if (char_fastbr[0] < '0' || char_fastbr[0] > '2')

         return -EINVAL;

 

     fastbr_level = (int)(char_fastbr[0] - '0');

@@ -252,8 +252,8 @@
     {

         if (*pos == 0)

         {

-            seq_printf(seq, "fastnat have %d conn!!!\nskb_num4:%d,fastnat_num:%d\n",

-                       working_list.count, skb_num4, fastnat_num);

+            seq_printf(seq, "fastnat have %d conn!!!\nskb_num4:%d,fastnat_num:%d,expand_head4:%d\n",

+                working_list.count, skb_num4, fastnat_num, skb_expand4);

             seq_printf(seq, "fastbr_sum:%d,fastbr_num:%d\n",

                        skb_num4 + skb_num6 + skb_unknown - fastnat_num - fast6_num, fastbr_num);

 

@@ -399,8 +399,8 @@
                        working_list.count,fastnat_recv_count,fastnat_real_count);

             seq_printf(seq, "send_2_ps_failed:%u, send_2_usb_failed:%u\n", send_2_ps_failed, send_2_usb_failed);

 #endif

-            seq_printf(seq, "fast6 have %d conn!!!\nskb_num6:%d,fast6_num:%d\n",

-                       working_list6.count, skb_num6, fast6_num);

+			seq_printf(seq, "fast6 have %d conn!!!\nskb_num6:%d,fast6_num:%d,expand_head6:%d\n",

+				working_list6.count, skb_num6, fast6_num, skb_expand6);

         }

         return &working_hash6[*pos];

     }

@@ -1160,6 +1160,42 @@
     .proc_write = ct_iptables_syn_set,

 };

 

+/* Started by AICoder, pid:i2747j1887i1a311479909db709e49391b4455c1 */

+static ssize_t dev_unreg_set(struct file *file, const char __user *buffer, size_t count, loff_t *pos)

+{

+    struct net_device *dev = NULL;

+    size_t size;

+    char dev_name[MAX_NET_DEVICE_NAME_LEN + 1] = {0};

+

+    // Ensure that the string is null-terminated

+    if (count == 0 || count > MAX_NET_DEVICE_NAME_LEN + 1)

+        return -EINVAL;

+

+    // Copy the device name from user space and ensure it's null terminated

+	size = min(count - 1, MAX_NET_DEVICE_NAME_LEN);

+    if (copy_from_user(dev_name, buffer, size)) {

+        return -EFAULT;

+    }

+    dev_name[size] = '\0'; // Ensure null-termination

+

+    // Try to get the network device by name

+    dev = dev_get_by_name(&init_net, dev_name);

+    if (dev) {

+        // Put the device reference

+        dev_put(dev);

+        // Unregister the network device

+        unregister_netdev(dev);

+    } else {

+        printk("dev_unreg %s not found\n", dev_name);

+    }

+

+    return count;

+}

+

+static const struct proc_ops dev_unreg_file_ops = {

+    .proc_write = dev_unreg_set,

+};

+/* Ended by AICoder, pid:i2747j1887i1a311479909db709e49391b4455c1 */

 

 //¿ìËÙת·¢procÎļþµÄ³õʼ»¯

 int fast_conntrack_init_proc(void)

@@ -1195,6 +1231,7 @@
     proc_create("dev_reset_stats", 0440, init_net.proc_net, &dev_reset_file_ops);

 

 	proc_create("ct_iptables_syn", 0440, init_net.proc_net, &ct_iptables_syn_file_ops);

+    proc_create("dev_unreg", 0440, init_net.proc_net, &dev_unreg_file_ops);

     return 1;

 }

 

diff --git a/upstream/linux-5.10/net/core/fastproc/fastnat.c b/upstream/linux-5.10/net/core/fastproc/fastnat.c
index 717454c..8d585c0 100755
--- a/upstream/linux-5.10/net/core/fastproc/fastnat.c
+++ b/upstream/linux-5.10/net/core/fastproc/fastnat.c
@@ -209,6 +209,7 @@
     {
         iph = (struct iphdr *)skb2->data;
         skb = skb2;
+		skb_expand4++;
     }
 
     fast_tcpdump(skb);
@@ -275,7 +276,8 @@
 
     skb->priority = nat_entry_data->priority;
     skb->mark = nat_entry_data->mark;
-
+	
+	spin_lock_bh(&fast_fw_spinlock);
     //»ùÓÚctÁ´½ÓµÄÁ÷Á¿Í³¼Æ --- ͳ¼ÆIP°ü²»ÊÇMAC°ü
     if (nat_entry_data->tuplehash.tuple.dst.dir == IP_CT_DIR_ORIGINAL){
         nat_entry->ct->packet_info[IP_CT_DIR_ORIGINAL].packets++;
@@ -294,6 +296,7 @@
     } else {
         printk("fastnat packet error\n");
     }
+	spin_unlock_bh(&fast_fw_spinlock);
 
     //ÄÚºË×Ô´øµÄ»ùÓÚÁ´½ÓµÄÁ÷Á¿Í³¼Æ
     struct nf_conn_counter *acct = (struct nf_conn_counter *)nf_conn_acct_find((const struct nf_conn *)nat_entry->ct);
@@ -450,7 +453,8 @@
     }
 
     //¹ã²¥¡¢×é²¥²»½¨Á´
-    if (ipv4_is_multicast(ip_hdr(skb)->daddr) || ipv4_is_lbcast(ip_hdr(skb)->daddr))
+    if (ipv4_is_multicast(ip_hdr(skb)->daddr) || ipv4_is_lbcast(ip_hdr(skb)->daddr)
+		|| ip_hdr(skb)->daddr == 0 || ip_hdr(skb)->saddr == 0)
     {
         return NF_ACCEPT;
     }
@@ -467,13 +471,10 @@
     }
 
     _neighbour = dst_neigh_lookup_skb(dst, skb);
-    if (!_neighbour)
-    {
-        print_sun(SUN_DBG,"napt_handle() _neighbour = null\n");
+	if(_neighbour == NULL && ((ip_hdr(skb)->daddr & 0xff000000) == 0xff000000 )){
         return NF_ACCEPT;
-    }
-
-    if (memcmp(_neighbour->ha, zeromac, ETH_ALEN) == 0)
+	}
+    if (_neighbour && memcmp(_neighbour->ha, zeromac, ETH_ALEN) == 0)
     {
         if (strncmp(out->name, ppp_name, strlen(ppp_name)) != 0)
         {
@@ -557,9 +558,10 @@
 
     entry_data = &nat_entry->data[dir];
     entry_data->tuplehash.tuple = ct->tuplehash[dir].tuple;
-    memcpy(entry_data->dmac, _neighbour->ha, ETH_ALEN);
+    //memcpy(entry_data->dmac, _neighbour->ha, ETH_ALEN);
     entry_data->priority = skb->priority;
     entry_data->mark = skb->mark;
+	if(entry_data->outdev == NULL){
     entry_data->outdev = out;
 
     /*¼Ç¼MACµØÖ·µ½entry_data->hh_data*/
@@ -568,6 +570,7 @@
         spin_unlock_bh(&fastnat_spinlock);
         goto accept;
     }
+	}
     print_sun(SUN_DBG,"napt_handle() ct->status=0x%x\n", ct->status);
     /*»ñÈ¡natת»»ÐèÒªµÄIPºÍportÐÅÏ¢*/
     if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
@@ -624,6 +627,7 @@
     spin_unlock_bh(&fastnat_spinlock);
 
 accept:
+	if(_neighbour)
     neigh_release(_neighbour);
     return NF_ACCEPT;
 }
diff --git a/upstream/linux-5.10/net/netfilter/nf_conntrack_core.c b/upstream/linux-5.10/net/netfilter/nf_conntrack_core.c
index e92413e..d4ae0b7 100755
--- a/upstream/linux-5.10/net/netfilter/nf_conntrack_core.c
+++ b/upstream/linux-5.10/net/netfilter/nf_conntrack_core.c
@@ -1621,6 +1621,11 @@
     ct->packet_info[IP_CT_DIR_ORIGINAL].bytes   = 0;
     ct->packet_info[IP_CT_DIR_REPLY].packets    = 0;
     ct->packet_info[IP_CT_DIR_REPLY].bytes      = 0;
+	ct->indev[IP_CT_DIR_ORIGINAL] = NULL;
+	ct->outdev[IP_CT_DIR_ORIGINAL] = NULL;
+	ct->indev[IP_CT_DIR_REPLY] = NULL;
+	ct->outdev[IP_CT_DIR_REPLY] = NULL;
+	ct->fast_entry = NULL;
 	for(dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++)
 	{
 		ct->indev[dir] = NULL;