ipacm: fix the v6-offload issue on Android

Remove the check on how many ipv6 addresses
are received from modem interface, fix the
client prefix comparison logic which contradicts
with MDM requirement to only offload
tethered-clients who has same prefix as
modem interface.

Test: as follows
    - built
    - flashed
    - booted
    - started tethering and watched for packets via:
      "adb shell tcpdump -n -i wlan0 -l"

Bug: 34361337

Change-Id: Ib4b2f9e67f5c92021956c3ecb963cfed7f016959
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
Signed-off-by: Niranjan Pendharkar <npendhar@codeaurora.org>
(cherry picked from commit 4031d6a7e2dec3f13805f45b082790ac2e9a496c)
diff --git a/msm8998/ipacm/inc/IPACM_Config.h b/msm8998/ipacm/inc/IPACM_Config.h
index 5bcb4eb..ae66c95 100644
--- a/msm8998/ipacm/inc/IPACM_Config.h
+++ b/msm8998/ipacm/inc/IPACM_Config.h
@@ -234,6 +234,8 @@
 
 	int DelNatIfaces(char *dev_name);
 
+	int CheckNatIfaces(const char *dev_name);
+
 	inline void SetQmapId(uint8_t id)
 	{
 		qmap_id = id;
diff --git a/msm8998/ipacm/inc/IPACM_Defs.h b/msm8998/ipacm/inc/IPACM_Defs.h
index 74ed3bf..9ab0893 100644
--- a/msm8998/ipacm/inc/IPACM_Defs.h
+++ b/msm8998/ipacm/inc/IPACM_Defs.h
@@ -166,6 +166,8 @@
 	IPA_WAN_XLAT_CONNECT_EVENT,               /* ipacm_event_data_fid */
 	IPA_TETHERING_STATS_UPDATE_EVENT,         /* ipacm_event_data_fid */
 	IPA_NETWORK_STATS_UPDATE_EVENT,           /* ipacm_event_data_fid */
+	IPA_DOWNSTREAM_ADD,                       /* ipacm_event_ipahal_stream */
+	IPA_DOWNSTREAM_DEL,                       /* ipacm_event_ipahal_stream */
 
 	IPA_EXTERNAL_EVENT_MAX,
 
@@ -185,8 +187,6 @@
 	IPA_ETH_BRIDGE_CLIENT_DEL,                /* ipacm_event_eth_bridge*/
 	IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH,       /* ipacm_event_eth_bridge*/
 	IPA_LAN_DELETE_SELF,                      /* ipacm_event_data_fid */
-	IPA_DOWNSTREAM_ADD,                       /* ipacm_event_ipahal_stream */
-	IPA_DOWNSTREAM_DEL,                       /* ipacm_event_ipahal_stream */
 	IPACM_EVENT_MAX
 } ipa_cm_event_id;
 
diff --git a/msm8998/ipacm/inc/IPACM_Wan.h b/msm8998/ipacm/inc/IPACM_Wan.h
index fbfaba3..fa4114b 100644
--- a/msm8998/ipacm/inc/IPACM_Wan.h
+++ b/msm8998/ipacm/inc/IPACM_Wan.h
@@ -131,6 +131,11 @@
 	static bool isWanUP_V6(int ipa_if_num_tether)
 	{
 #ifdef FEATURE_IPA_ANDROID
+#ifdef FEATURE_IPACM_HAL
+		/*To avoid -Wall -Werror error */
+		IPACMDBG_H("ipa_if_num_tether: %d\n",ipa_if_num_tether);
+		return wan_up_v6;
+#else
 		uint32_t i;
 		for (i=0; i < ipa_if_num_tether_v6_total;i++)
 		{
@@ -143,6 +148,7 @@
 			}
 		}
 		return false;
+#endif
 #else
 		return wan_up_v6;
 #endif
diff --git a/msm8998/ipacm/src/IPACM_Config.cpp b/msm8998/ipacm/src/IPACM_Config.cpp
index 6218fb6..895005f 100644
--- a/msm8998/ipacm/src/IPACM_Config.cpp
+++ b/msm8998/ipacm/src/IPACM_Config.cpp
@@ -88,6 +88,8 @@
 	__stringify(IPA_WAN_XLAT_CONNECT_EVENT),               /* ipacm_event_data_fid */
 	__stringify(IPA_TETHERING_STATS_UPDATE_EVENT),         /* ipacm_event_data_fid */
 	__stringify(IPA_NETWORK_STATS_UPDATE_EVENT),           /* ipacm_event_data_fid */
+	__stringify(IPA_DOWNSTREAM_ADD),                       /* ipacm_event_ipahal_stream */
+	__stringify(IPA_DOWNSTREAM_DEL),                       /* ipacm_event_ipahal_stream */
 	__stringify(IPA_EXTERNAL_EVENT_MAX),
 	__stringify(IPA_HANDLE_WAN_UP),                        /* ipacm_event_iface_up  */
 	__stringify(IPA_HANDLE_WAN_DOWN),                      /* ipacm_event_iface_up  */
@@ -499,7 +501,7 @@
 	{
 		if (strcmp(dev_name, pNatIfaces[i].iface_name) == 0)
 		{
-			IPACMDBG_H("Find Nat IfaceName: %s ,previous nat-ifaces number: %d\n",
+			IPACMDBG_H("Found Nat IfaceName: %s with nat-ifaces number: %d\n",
 							 pNatIfaces[i].iface_name, ipa_nat_iface_entries);
 
 			/* Reset the matched entry */
@@ -524,6 +526,26 @@
 	return 0;
 }
 
+int IPACM_Config::CheckNatIfaces(const char *dev_name)
+{
+	int i = 0;
+	IPACMDBG_H("Check iface %s from NAT-ifaces, currently it has %d nat ifaces\n",
+					 dev_name, ipa_nat_iface_entries);
+
+	for (i = 0; i < ipa_nat_iface_entries; i++)
+	{
+		if (strcmp(dev_name, pNatIfaces[i].iface_name) == 0)
+		{
+			IPACMDBG_H("Find Nat IfaceName: %s ,previous nat-ifaces number: %d\n",
+							 pNatIfaces[i].iface_name, ipa_nat_iface_entries);
+			return 0;
+		}
+	}
+	IPACMDBG_H("Can't find Nat IfaceName: %s with total nat-ifaces number: %d\n",
+					    dev_name, ipa_nat_iface_entries);
+	return -1;
+}
+
 /* for IPACM resource manager dependency usage
    add either Tx or Rx ipa_rm_resource_name and
    also indicate that endpoint property if valid */
diff --git a/msm8998/ipacm/src/IPACM_Iface.cpp b/msm8998/ipacm/src/IPACM_Iface.cpp
index 0582d67..4e0dc9e 100644
--- a/msm8998/ipacm/src/IPACM_Iface.cpp
+++ b/msm8998/ipacm/src/IPACM_Iface.cpp
@@ -851,7 +851,11 @@
 
 		if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA)
 		{
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<9);
+#else
 			flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
+#endif
 			flt_rule_entry.rule.eq_attrib.metadata_meq32_present = 1;
 			flt_rule_entry.rule.eq_attrib.metadata_meq32.offset = 0;
 			flt_rule_entry.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
@@ -862,7 +866,11 @@
 		flt_rule_entry.rule.eq_attrib.protocol_eq_present = 1;
 		flt_rule_entry.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
 
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<7);
+#else
 		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
+#endif
 		flt_rule_entry.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
 		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
 
diff --git a/msm8998/ipacm/src/IPACM_Lan.cpp b/msm8998/ipacm/src/IPACM_Lan.cpp
index 36d4b74..5a8f0e6 100644
--- a/msm8998/ipacm/src/IPACM_Lan.cpp
+++ b/msm8998/ipacm/src/IPACM_Lan.cpp
@@ -183,6 +183,21 @@
 	memset(is_downstream_set, 0, sizeof(is_downstream_set));
 	memset(is_upstream_set, 0, sizeof(is_upstream_set));
 	memset(&prefix, 0, sizeof(prefix));
+
+#ifdef FEATURE_IPACM_HAL
+		/* check if Upstream was set before */
+		if (IPACM_Wan::isWanUP(ipa_if_num))
+		{
+				IPACMDBG_H("Upstream was set previously for ipv4, change is_upstream_set flag\n");
+				is_upstream_set[IPA_IP_v4] = true;
+		}
+
+		if (IPACM_Wan::isWanUP_V6(ipa_if_num))
+		{
+				IPACMDBG_H("Upstream was set previously for ipv6, change is_upstream_set flag\n");
+				is_upstream_set[IPA_IP_v6] = true;
+		}
+#endif
 	return;
 }
 
@@ -368,6 +383,7 @@
 						handle_private_subnet(data->iptype);
 #endif
 
+#ifndef FEATURE_IPACM_HAL
 						if (IPACM_Wan::isWanUP(ipa_if_num))
 						{
 							if(data->iptype == IPA_IP_v4 || data->iptype == IPA_IP_MAX)
@@ -408,7 +424,7 @@
 						} else {
 							IPACMDBG_H("Wan_V6 haven't up yet\n");
 						}
-
+#endif
 						/* Post event to NAT */
 						if (data->iptype == IPA_IP_v4)
 						{
@@ -656,7 +672,13 @@
 					if (ip_type == IPA_IP_MAX || ip_type == data->prefix.iptype)
 					{
 						if (data->prefix.iptype == IPA_IP_v6) /* ipv6 only */
-							install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
+						{
+							/* Only offload clients has same prefix as Android gave */
+							ipv6_prefix[0] = data->prefix.v6Addr[0];
+							ipv6_prefix[1] = data->prefix.v6Addr[1];
+							IPACMDBG_H("ipv6_prefix0x%x:%x\n", ipv6_prefix[0], ipv6_prefix[1]);
+							install_ipv6_prefix_flt_rule(ipv6_prefix);
+						}
 
 						if (IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
 						{
@@ -1033,7 +1055,7 @@
 		return IPACM_FAILURE;
 	}
 
-	if(is_sta_mode == false)
+	if(is_sta_mode == false && modem_ul_v4_set == true) //sky
 	{
 		if (num_wan_ul_fl_rule_v4 > MAX_WAN_UL_FILTER_RULES)
 		{
@@ -1511,14 +1533,14 @@
 /* only offload UL traffic of certain clients */
 #ifdef FEATURE_IPACM_HAL
 		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
-		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = prefix[IPA_IP_v6].v6Mask[0];
-		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = prefix[IPA_IP_v6].v6Mask[1];
-		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = prefix[IPA_IP_v6].v6Mask[2];
-		flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = prefix[IPA_IP_v6].v6Mask[3];
-		flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = prefix[IPA_IP_v6].v6Addr[0];
-		flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = prefix[IPA_IP_v6].v6Addr[1];
-		flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = prefix[IPA_IP_v6].v6Addr[2];
-		flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = prefix[IPA_IP_v6].v6Addr[3];
+		flt_rule_entry.rule.attrib.u.v6.src_addr_mask[0] = ntohl(prefix[IPA_IP_v6].v6Mask[0]);
+		flt_rule_entry.rule.attrib.u.v6.src_addr_mask[1] = ntohl(prefix[IPA_IP_v6].v6Mask[1]);
+		flt_rule_entry.rule.attrib.u.v6.src_addr_mask[2] = ntohl(prefix[IPA_IP_v6].v6Mask[2]);
+		flt_rule_entry.rule.attrib.u.v6.src_addr_mask[3] = ntohl(prefix[IPA_IP_v6].v6Mask[3]);
+		flt_rule_entry.rule.attrib.u.v6.src_addr[0] = ntohl(prefix[IPA_IP_v6].v6Addr[0]);
+		flt_rule_entry.rule.attrib.u.v6.src_addr[1] = ntohl(prefix[IPA_IP_v6].v6Addr[1]);
+		flt_rule_entry.rule.attrib.u.v6.src_addr[2] = ntohl(prefix[IPA_IP_v6].v6Addr[2]);
+		flt_rule_entry.rule.attrib.u.v6.src_addr[3] = ntohl(prefix[IPA_IP_v6].v6Addr[3]);
 
 #endif
 		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
@@ -1575,7 +1597,7 @@
 	}
 
 	/* check only add static UL filter rule once */
-	if (num_dft_rt_v6 ==1 && iptype ==IPA_IP_v6 && modem_ul_v6_set == false)
+	if (iptype ==IPA_IP_v6 && modem_ul_v6_set == false)
 	{
 		IPACMDBG_H("IPA_IP_v6 num_dft_rt_v6 %d xlat_mux_id: %d modem_ul_v6_set: %d\n", num_dft_rt_v6, xlat_mux_id, modem_ul_v6_set);
 		ret = handle_uplink_filter_rule(ext_prop, iptype, xlat_mux_id);
@@ -3056,6 +3078,7 @@
 			if(flt_rule_entry.rule.eq_attrib.num_offset_meq_32 <= IPA_IPFLTR_NUM_MEQ_32_EQNS)
 			{
 				eq_index = flt_rule_entry.rule.eq_attrib.num_offset_meq_32 - 1;
+#ifdef FEATURE_IPA_V3
 				if(eq_index == 0)
 				{
 					flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<5);
@@ -3064,6 +3087,16 @@
 				{
 					flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<6);
 				}
+#else
+				if(eq_index == 0)
+				{
+					flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<2);
+				}
+				else
+				{
+					flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<3);
+				}
+#endif
 				flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].offset = 12;
 				flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].mask = prefix[IPA_IP_v4].v4Mask;
 				flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].value = prefix[IPA_IP_v4].v4Addr;
@@ -3080,6 +3113,7 @@
 			if(flt_rule_entry.rule.eq_attrib.num_offset_meq_128 <= IPA_IPFLTR_NUM_MEQ_128_EQNS)
 			{
 				eq_index = flt_rule_entry.rule.eq_attrib.num_offset_meq_128 - 1;
+#ifdef FEATURE_IPA_V3
 				if(eq_index == 0)
 				{
 					flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<3);
@@ -3088,23 +3122,33 @@
 				{
 					flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<4);
 				}
+#else
+				if(eq_index == 0)
+				{
+					flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<9);
+				}
+				else
+				{
+					flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<10);
+				}
+#endif
 				flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].offset = 8;
 				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 0)
-					= prefix[IPA_IP_v6].v6Mask[0];
-				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 4)
-					= prefix[IPA_IP_v6].v6Mask[1];
-				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 8)
-					= prefix[IPA_IP_v6].v6Mask[2];
-				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 12)
 					= prefix[IPA_IP_v6].v6Mask[3];
+				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 4)
+					= prefix[IPA_IP_v6].v6Mask[2];
+				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 8)
+					= prefix[IPA_IP_v6].v6Mask[1];
+				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 12)
+					= prefix[IPA_IP_v6].v6Mask[0];
 				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 0)
-					= prefix[IPA_IP_v6].v6Addr[0];
-				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 4)
-					= prefix[IPA_IP_v6].v6Addr[1];
-				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 8)
-					= prefix[IPA_IP_v6].v6Addr[2];
-				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 12)
 					= prefix[IPA_IP_v6].v6Addr[3];
+				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 4)
+					= prefix[IPA_IP_v6].v6Addr[2];
+				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 8)
+					= prefix[IPA_IP_v6].v6Addr[1];
+				*(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 12)
+					= prefix[IPA_IP_v6].v6Addr[0];
 			}
 			else
 			{
@@ -3200,7 +3244,7 @@
 
 	memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
 
-	if(is_sta_mode == false)
+	if(is_sta_mode == false && modem_ul_v6_set == true)
 	{
 		if (num_wan_ul_fl_rule_v6 > MAX_WAN_UL_FILTER_RULES)
 		{
diff --git a/msm8998/ipacm/src/IPACM_OffloadManager.cpp b/msm8998/ipacm/src/IPACM_OffloadManager.cpp
index 95e44bf..3679669 100644
--- a/msm8998/ipacm/src/IPACM_OffloadManager.cpp
+++ b/msm8998/ipacm/src/IPACM_OffloadManager.cpp
@@ -45,6 +45,7 @@
 #include "IPACM_ConntrackListener.h"
 #include "IPACM_Iface.h"
 #include "IPACM_Config.h"
+#include <unistd.h>
 
 const char *IPACM_OffloadManager::DEVICE_NAME = "/dev/wwan_ioctl";
 
@@ -120,8 +121,14 @@
 		return FAIL_HARDWARE;
 	}
 
+	/* add the check if getting FDs already or not */
+	if(cc->fd_tcp > -1 && cc->fd_udp > -1) {
+		IPACMDBG_H("has valid FDs fd_tcp %d, fd_udp %d, ignore fd %d.\n", cc->fd_tcp, cc->fd_udp, fd);
+		return SUCCESS;
+	}
+
 	if (groups == cc->subscrips_tcp) {
-		cc->fd_tcp = fd;
+		cc->fd_tcp = dup(fd);
 		IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups);
 		/* set netlink buf */
 		rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
@@ -130,7 +137,7 @@
 			IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) );
 		}
 	} else if (groups == cc->subscrips_udp) {
-		cc->fd_udp = fd;
+		cc->fd_udp = dup(fd);
 		IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups);
 		/* set netlink buf */
 		rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
@@ -150,16 +157,9 @@
 
 RET IPACM_OffloadManager::clearAllFds()
 {
-	IPACM_ConntrackClient *cc;
 
-	cc = IPACM_ConntrackClient::GetInstance();
-	if(!cc)
-	{
-		IPACMERR("Init clear: cc %p \n", cc);
-		return FAIL_HARDWARE;
-	}
-	cc->UNRegisterWithConnTrack();
-
+	/* IPACM needs to kee old FDs, can't clear */
+	IPACMDBG_H("Still use old Fds, can't clear \n");
 	return SUCCESS;
 }
 
@@ -181,6 +181,14 @@
 	ipacm_event_ipahal_stream *evt_data;
 
 	IPACMDBG_H("addDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
+
+	/* ideal behavior: ipacm should return try-again if downstream netdev driver not ready */
+	if (IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name))
+	{
+		IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", downstream_name);
+		return FAIL_TRY_AGAIN;
+	}
+
 	if (prefix.fam == V4) {
 		IPACMDBG_H("subnet info v4Addr (%x) v4Mask (%x)\n", prefix.v4Addr, prefix.v4Mask);
 	} else {
@@ -265,7 +273,6 @@
 			IPACMERR("no previous upstream set before\n");
 			return FAIL_INPUT_CHECK;
 		}
-
 		if (gw_addr_v4.fam == V4 && upstream_v4_up == true) {
 			IPACMDBG_H("clean upstream(%s) for ipv4-fam(%d) upstream_v4_up(%d)\n", upstream_name, gw_addr_v4.fam, upstream_v4_up);
 			post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
@@ -280,6 +287,14 @@
 	}
 	else
 	{
+
+		/* ideal behavior: ipacm should return try-again if upstream netdev driver not ready */
+		if (IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name))
+		{
+			IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", upstream_name);
+			return FAIL_TRY_AGAIN;
+		}
+
 		if(ipa_get_if_index(upstream_name, &index))
 		{
 			IPACMERR("fail to get iface index.\n");
@@ -360,7 +375,13 @@
 
 RET IPACM_OffloadManager::stopAllOffload()
 {
-	return SUCCESS;
+	Prefix v4gw, v6gw;
+	memset(&v4gw, 0, sizeof(v4gw));
+	memset(&v6gw, 0, sizeof(v6gw));
+	v4gw.fam = V4;
+	v6gw.fam = V6;
+	IPACMDBG_H("posting setUpstream(NULL), ipv4-fam(%d) ipv6-fam(%d)\n", v4gw.fam, v6gw.fam);
+	return setUpstream(NULL, v4gw, v6gw);
 }
 
 RET IPACM_OffloadManager::setQuota(const char * upstream_name /* upstream */, uint64_t mb/* limit */)
diff --git a/msm8998/ipacm/src/IPACM_Wan.cpp b/msm8998/ipacm/src/IPACM_Wan.cpp
index 4c4ad69..968f562 100644
--- a/msm8998/ipacm/src/IPACM_Wan.cpp
+++ b/msm8998/ipacm/src/IPACM_Wan.cpp
@@ -3769,7 +3769,11 @@
 		flt_rule_entry.rule.eq_attrib.protocol_eq_present = 1;
 		flt_rule_entry.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
 
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<7);
+#else
 		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
+#endif
 		flt_rule_entry.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
 		flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
 
diff --git a/msm8998/ipacm/src/IPACM_Wlan.cpp b/msm8998/ipacm/src/IPACM_Wlan.cpp
index 887e9ee..53e56cf 100644
--- a/msm8998/ipacm/src/IPACM_Wlan.cpp
+++ b/msm8998/ipacm/src/IPACM_Wlan.cpp
@@ -267,6 +267,7 @@
 					handle_private_subnet(data->iptype);
 #endif
 
+#ifndef FEATURE_IPACM_HAL
 					if (IPACM_Wan::isWanUP(ipa_if_num))
 					{
 						if(data->iptype == IPA_IP_v4 || data->iptype == IPA_IP_MAX)
@@ -308,6 +309,7 @@
 					} else {
 						IPACMDBG_H("Wan_V6 haven't up yet \n");
 					}
+#endif
 					/* checking if SW-RT_enable */
 					if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true)
 					{
@@ -535,7 +537,13 @@
 					if(ip_type == IPA_IP_MAX || ip_type == data->prefix.iptype)
 					{
 						if (data->prefix.iptype == IPA_IP_v6) /* ipv6 only */
-							install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
+						{
+							/* Only offload clients has same prefix as Andorid gave */
+							ipv6_prefix[0] = data->prefix.v6Addr[0];
+							ipv6_prefix[1] = data->prefix.v6Addr[1];
+							IPACMDBG_H("ipv6_prefix0x%x:%x\n", ipv6_prefix[0], ipv6_prefix[1]);
+							install_ipv6_prefix_flt_rule(ipv6_prefix);
+						}
 
 						if (IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
 						{
@@ -1257,6 +1265,7 @@
 				memcmp(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix)) != 0)
 			{
 				IPACMDBG_H("This IPv6 address is not global IPv6 address with correct prefix, ignore.\n");
+				IPACMDBG_H("ipv6 address: 0x%x:%x ipv6_prefix0x%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], ipv6_prefix[0], ipv6_prefix[1]);
 				return IPACM_FAILURE;
 			}