Merge "[qca-nss-drv]: Add Jumbo frame support"
diff --git a/nss_connmgr_ipv4.c b/nss_connmgr_ipv4.c
index 853fc6a..5dcb828 100755
--- a/nss_connmgr_ipv4.c
+++ b/nss_connmgr_ipv4.c
@@ -114,7 +114,7 @@
 typedef uint8_t mac_addr_t[6];
 typedef uint32_t ipv4_addr_t;
 
-#define is_bridge_port(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
+#define is_bridge_port(dev) (dev && (dev->priv_flags & IFF_BRIDGE_PORT))
 #define is_bridge_device(dev) (dev->priv_flags & IFF_EBRIDGE)
 #define is_lag_master(dev)	((dev->flags & IFF_MASTER)		\
 				 && (dev->priv_flags & IFF_BONDING))
@@ -556,6 +556,14 @@
 	nss_tx_status_t	nss_tx_status;
 
 	/*
+	 * Only process IPV4 packets in bridge hook
+	 */
+	if(skb->protocol != htons(ETH_P_IP)){
+		NSS_CONNMGR_DEBUG_TRACE("non ipv4 , ignoring: %p\n", skb);
+		return NF_ACCEPT;
+	}
+
+	/*
 	 * Don't process broadcast or multicast
 	 */
 	if (skb->pkt_type == PACKET_BROADCAST) {
@@ -604,6 +612,17 @@
 	}
 	NSS_CONNMGR_DEBUG_TRACE("skb: %p tracked by connection: %p\n", skb, ct);
 
+
+	/*
+	 * Ignore packets that are related to a valid connection, such as ICMP destination
+	 * unreachable error packets
+	 */
+	if ((ctinfo == IP_CT_RELATED) || (ctinfo == IP_CT_RELATED_REPLY)) {
+		dev_put(in);
+		NSS_CONNMGR_DEBUG_TRACE("skb: Related packet %p tracked by connection: %p\n", skb, ct);
+		return NF_ACCEPT;
+	}
+
 	/*
 	 * Special untracked connection is not monitored
 	 */
@@ -633,11 +652,16 @@
 	/*
 	 * If destination is not reachable, ignore.
 	 */
-	if (skb_mac_header_was_set(skb)
-	    && br_port_dev_get(out->master, eth_hdr(skb)->h_dest) == NULL) {
-		dev_put(in);
-		NSS_CONNMGR_DEBUG_TRACE("Dest not reachable, skb(%p)\n", skb);
-		return NF_ACCEPT;
+	if (skb_mac_header_was_set(skb)) {
+		struct net_device *dest_dev = br_port_dev_get(out->master, eth_hdr(skb)->h_dest);
+
+		if (dest_dev == NULL) {
+			dev_put(in);
+			NSS_CONNMGR_DEBUG_TRACE("Dest not reachable, skb(%p)\n", skb);
+			return NF_ACCEPT;
+		} else {
+			dev_put(dest_dev);
+		}
 	}
 
 	/*
@@ -803,11 +827,17 @@
 		 * Configure the MAC addresses for the flow
 		 */
 		eh = (struct ethhdr *)skb->mac_header;
-
-		memcpy(unic.src_mac, eh->h_source, ETH_HLEN);
-		memcpy(unic.src_mac_xlate, eh->h_source, ETH_HLEN);
-		memcpy(unic.dest_mac, eh->h_dest, ETH_HLEN);
-		memcpy(unic.dest_mac_xlate, eh->h_dest, ETH_HLEN);
+		if (ctinfo < IP_CT_IS_REPLY) {
+			memcpy(unic.src_mac, eh->h_source, ETH_HLEN);
+			memcpy(unic.dest_mac, eh->h_dest, ETH_HLEN);
+			memcpy(unic.src_mac_xlate, eh->h_source, ETH_HLEN);
+			memcpy(unic.dest_mac_xlate, eh->h_dest, ETH_HLEN);
+		} else {
+			memcpy(unic.src_mac, eh->h_dest, ETH_HLEN);
+			memcpy(unic.dest_mac, eh->h_source, ETH_HLEN);
+			memcpy(unic.src_mac_xlate, eh->h_dest, ETH_HLEN);
+			memcpy(unic.dest_mac_xlate, eh->h_source, ETH_HLEN);
+		}
 	} else {
 		/*
 		 * This is a routed + bridged flow
@@ -1436,6 +1466,15 @@
 	NSS_CONNMGR_DEBUG_TRACE("skb: %p tracked by connection: %p\n", skb, ct);
 
 	/*
+	 * Ignore packets that are related to a valid connection, such as ICMP destination
+	 * unreachable error packets
+	 */
+	if ((ctinfo == IP_CT_RELATED) || (ctinfo == IP_CT_RELATED_REPLY)) {
+		NSS_CONNMGR_DEBUG_TRACE("skb: Related packet %p tracked by connection: %p\n", skb, ct);
+		goto out;
+	}
+
+	/*
 	 * Special untracked connection is not monitored
 	 */
 	if (ct == &nf_conntrack_untracked) {
@@ -2047,48 +2086,65 @@
 	struct rtnl_link_stats64 stats;
 
 	indev = nss_get_interface_dev(nss_connmgr_ipv4.nss_context, connection->src_interface);
+	if (indev == NULL) {
+		/*
+		 * Possible sync for a deleted interface
+		 */
+		return;
+	}
 
 	if (is_lag_slave(indev)) {
-		if (indev->master) {
-			indev = indev->master;
-		} else {
+		if (indev->master == NULL) {
+			NSS_CONNMGR_DEBUG_TRACE("Could not find master for LAG slave %s\n", indev->name);
 			return;
 		}
+		indev = indev->master;
 	} else if (connection->ingress_vlan_tag != NSS_CONNMGR_VLAN_ID_NOT_CONFIGURED) {
 		indev = __vlan_find_dev_deep(indev, connection->ingress_vlan_tag);
+		if (indev == NULL) {
+			/*
+			 * Possible sync for a deleted VLAN interface
+			 */
+			return;
+		}
 	}
 
 	outdev = nss_get_interface_dev(nss_connmgr_ipv4.nss_context, connection->dest_interface);
-	if (is_lag_slave(outdev)) {
-		if (outdev->master) {
-			outdev = outdev->master;
-		} else {
-			return;
-		}
-	} else if (connection->egress_vlan_tag != NSS_CONNMGR_VLAN_ID_NOT_CONFIGURED) {
-		outdev = __vlan_find_dev_deep(outdev, connection->egress_vlan_tag);
+	if (outdev == NULL) {
+		/*
+		 * Possible sync for a deleted interface
+		 */
+		return;
 	}
 
-	/*
-	 * Check if we have a bridge to update
-	 */
-	if (!is_bridge_port(indev) && !is_bridge_port(outdev))
-		return;
+	if (is_lag_slave(outdev)) {
+		if (outdev->master == NULL) {
+			NSS_CONNMGR_DEBUG_TRACE("Could not find master for LAG slave %s\n", outdev->name);
+			return;
+		}
+		outdev = outdev->master;
+	} else if (connection->egress_vlan_tag != NSS_CONNMGR_VLAN_ID_NOT_CONFIGURED) {
+		outdev = __vlan_find_dev_deep(outdev, connection->egress_vlan_tag);
+		if (outdev == NULL) {
+			/*
+			 * Possible sync for a deleted VLAN interface
+			 */
+			return;
+		}
+	}
 
-	/*
-	 * Update bridge device statistics for routing flows that have
-	 * a bridge in the path. We should avoid updating bridge device
-	 * for flows that are forwrded within the bridge.
-	 */
 	if (is_bridge_port(indev))
 	{
 		/*
 		 * Refresh bridge MAC table if necessary
 		 */
-		if (!final_sync) {
+		if (!final_sync && sync->flow_rx_packet_count) {
 			br_refresh_fdb_entry(indev, connection->src_mac_addr);
 		}
 
+		/*
+		 * Update bridge interface stats for L3 flows involving a bridge
+		 */
 		if (indev->master != outdev->master) {
 			stats.rx_packets = sync->flow_rx_packet_count;
 			stats.rx_bytes = sync->flow_rx_byte_count;
@@ -2103,10 +2159,13 @@
 		/*
 		 * Refresh bridge MAC table if necessary
 		 */
-		if (!final_sync) {
+		if (!final_sync && sync->return_rx_packet_count) {
 			br_refresh_fdb_entry(outdev, connection->dest_mac_addr);
 		}
 
+		/*
+		 * Update bridge interface stats for L3 flows involving a bridge
+		 */
 		if (indev->master != outdev->master) {
 			stats.rx_packets = sync->return_rx_packet_count;
 			stats.rx_bytes = sync->return_rx_byte_count;
diff --git a/nss_connmgr_ipv6.c b/nss_connmgr_ipv6.c
index 9519f71..8f62f86 100755
--- a/nss_connmgr_ipv6.c
+++ b/nss_connmgr_ipv6.c
@@ -159,7 +159,7 @@
 typedef uint8_t mac_addr_t[6];
 typedef uint32_t ipv6_addr_t[4];
 
-#define is_bridge_port(dev) (dev->priv_flags & IFF_BRIDGE_PORT)
+#define is_bridge_port(dev) (dev && (dev->priv_flags & IFF_BRIDGE_PORT))
 #define is_bridge_device(dev) (dev->priv_flags & IFF_EBRIDGE)
 #define is_lag_master(dev)	((dev->flags & IFF_MASTER)		\
 				 && (dev->priv_flags & IFF_BONDING))
@@ -815,6 +815,14 @@
 	nss_tx_status_t nss_tx_status;
 
 	/*
+	 * Only process IPV6 packets in bridge hook
+	 */
+	if(skb->protocol != htons(ETH_P_IPV6)){
+		NSS_CONNMGR_DEBUG_TRACE("non ipv6 , ignoring: %p\n", skb);
+		return NF_ACCEPT;
+	}
+
+	/*
 	 * Don't process broadcast or multicast
 	 */
 	if (skb->pkt_type == PACKET_BROADCAST) {
@@ -864,6 +872,16 @@
 	NSS_CONNMGR_DEBUG_TRACE("skb: %p tracked by connection: %p\n", skb, ct);
 
 	/*
+	 * Ignore packets that are related to a valid connection, such as ICMP destination
+	 * unreachable error packets
+	 */
+	if ((ctinfo == IP_CT_RELATED) || (ctinfo == IP_CT_RELATED_REPLY)) {
+		dev_put(in);
+		NSS_CONNMGR_DEBUG_TRACE("skb: Related packet %p tracked by connection: %p\n", skb, ct);
+		return NF_ACCEPT;
+	}
+
+	/*
 	 * Special untracked connection is not monitored
 	 */
 	if (ct == &nf_conntrack_untracked) {
@@ -892,11 +910,16 @@
 	/*
 	 * If destination is not reachable, ignore.
 	 */
-	if (skb_mac_header_was_set(skb)
-	    && br_port_dev_get(out->master, eth_hdr(skb)->h_dest) == NULL) {
-		dev_put(in);
-		NSS_CONNMGR_DEBUG_TRACE("Dest not reachable, skb(%p)\n", skb);
-		return NF_ACCEPT;
+	if (skb_mac_header_was_set(skb)) {
+		struct net_device *dest_dev = br_port_dev_get(out->master, eth_hdr(skb)->h_dest);
+
+		if (dest_dev == NULL) {
+			dev_put(in);
+			NSS_CONNMGR_DEBUG_TRACE("Dest not reachable, skb(%p)\n", skb);
+			return NF_ACCEPT;
+		} else {
+			dev_put(dest_dev);
+		}
 	}
 
 	/*
@@ -1044,9 +1067,13 @@
 		 * Configure the MAC addresses for the flow
 		 */
 		eh = (struct ethhdr *)skb->mac_header;
-
-		memcpy(unic.src_mac, eh->h_source, ETH_HLEN);
-		memcpy(unic.dest_mac, eh->h_dest, ETH_HLEN);
+		if (ctinfo < IP_CT_IS_REPLY) {
+			memcpy(unic.src_mac, eh->h_source, ETH_HLEN);
+			memcpy(unic.dest_mac, eh->h_dest, ETH_HLEN);
+		} else {
+			memcpy(unic.src_mac, eh->h_dest, ETH_HLEN);
+			memcpy(unic.dest_mac, eh->h_source, ETH_HLEN);
+		}
 	} else {
 		/*
 		 * This is a routed + bridged flow
@@ -1436,6 +1463,15 @@
 	NSS_CONNMGR_DEBUG_TRACE("skb: %p tracked by connection: %p\n", skb, ct);
 
 	/*
+	 * Ignore packets that are related to a valid connection, such as ICMP destination
+	 * unreachable error packets
+	 */
+	if ((ctinfo == IP_CT_RELATED) || (ctinfo == IP_CT_RELATED_REPLY)) {
+		NSS_CONNMGR_DEBUG_TRACE("skb: Related packet %p tracked by connection: %p\n", skb, ct);
+		goto out;
+	}
+
+	/*
 	 * Special untracked connection is not monitored
 	 */
 	if (ct == &nf_conntrack_untracked) {
@@ -1986,48 +2022,65 @@
 	struct rtnl_link_stats64 stats;
 
 	indev = nss_get_interface_dev(nss_connmgr_ipv6.nss_context, connection->src_interface);
+	if (indev == NULL) {
+		/*
+		 * Possible sync for a deleted interface
+		 */
+		return;
+	}
 
 	if (is_lag_slave(indev)) {
-		if (indev->master) {
-			indev = indev->master;
-		} else {
+		if (indev->master == NULL) {
+			NSS_CONNMGR_DEBUG_TRACE("Could not find master for LAG slave %s\n", indev->name);
 			return;
 		}
+		indev = indev->master;
 	} else if (connection->ingress_vlan_tag != NSS_CONNMGR_VLAN_ID_NOT_CONFIGURED) {
 		indev = __vlan_find_dev_deep(indev, connection->ingress_vlan_tag);
+		if (indev == NULL) {
+			/*
+			 * Possible sync for a deleted VLAN interface
+			 */
+			return;
+		}
 	}
 
 	outdev = nss_get_interface_dev(nss_connmgr_ipv6.nss_context, connection->dest_interface);
-	if (is_lag_slave(outdev)) {
-		if (outdev->master) {
-			outdev = outdev->master;
-		} else {
-			return;
-		}
-	} else if (connection->egress_vlan_tag != NSS_CONNMGR_VLAN_ID_NOT_CONFIGURED) {
-		outdev = __vlan_find_dev_deep(outdev, connection->egress_vlan_tag);
+	if (outdev == NULL) {
+		/*
+		 * Possible sync for a deleted interface
+		 */
+		return;
 	}
 
-	/*
-	 * Check if we have a bridge to update
-	 */
-	if (!is_bridge_port(indev) && !is_bridge_port(outdev))
-		return;
+	if (is_lag_slave(outdev)) {
+		if (outdev->master == NULL) {
+			NSS_CONNMGR_DEBUG_TRACE("Could not find master for LAG slave %s\n", outdev->name);
+			return;
+		}
+		outdev = outdev->master;
+	} else if (connection->egress_vlan_tag != NSS_CONNMGR_VLAN_ID_NOT_CONFIGURED) {
+		outdev = __vlan_find_dev_deep(outdev, connection->egress_vlan_tag);
+		if (outdev == NULL) {
+			/*
+			 * Possible sync for a deleted VLAN interface
+			 */
+			return;
+		}
+	}
 
-	/*
-	 * Update bridge device statistics for routing flows that have
-	 * a bridge in the path. We should avoid updating bridge device
-	 * for flows that are forwrded within the bridge.
-	 */
 	if (is_bridge_port(indev))
 	{
 		/*
 		 * Refresh bridge MAC table if necessary
 		 */
-		if (!sync->final_sync) {
+		if (!sync->final_sync && sync->flow_rx_packet_count) {
 			br_refresh_fdb_entry(indev, connection->src_mac_addr);
 		}
 
+		/*
+		 * Update bridge interface stats for L3 flows involving a bridge
+		 */
 		if (indev->master != outdev->master) {
 			stats.rx_packets = sync->flow_rx_packet_count;
 			stats.rx_bytes = sync->flow_rx_byte_count;
@@ -2042,10 +2095,13 @@
 		/*
 		 * Refresh bridge MAC table if necessary
 		 */
-		if (!sync->final_sync) {
+		if (!sync->final_sync && sync->return_rx_packet_count) {
 			br_refresh_fdb_entry(outdev, connection->dest_mac_addr);
 		}
 
+		/*
+		 * Update bridge interface stats for L3 flows involving a bridge
+		 */
 		if (indev->master != outdev->master) {
 			stats.rx_packets = sync->return_rx_packet_count;
 			stats.rx_bytes = sync->return_rx_byte_count;
diff --git a/nss_tun6rd.c b/nss_tun6rd.c
index b664b7e..dd8fffb 100755
--- a/nss_tun6rd.c
+++ b/nss_tun6rd.c
@@ -405,6 +405,15 @@
 	 * Packet after Decap/Encap Did not find the Rule.
 	 */
 	if (iph->version == 4) {
+		if(iph->protocol == IPPROTO_IPV6){
+			skb_pull(skb, sizeof(struct iphdr));
+			skb->protocol = htons(ETH_P_IPV6);
+			skb_reset_network_header(skb);
+			skb->pkt_type = PACKET_HOST;
+			skb->ip_summed = CHECKSUM_NONE;
+			dev_queue_xmit(skb);
+			return;
+		}
 		skb->protocol = htons(ETH_P_IP);
 	} else {
 		skb->protocol = htons(ETH_P_IPV6);