Merge e0ad041f1575b9ff77ebc2ac85e21a8a9084e868 on remote branch

Change-Id: Id1f15775ffabcb5d635d1fb6fcbac77e0cd26405
diff --git a/ipacm/inc/IPACM_ConntrackListener.h b/ipacm/inc/IPACM_ConntrackListener.h
index 6cc4188..2977af7 100644
--- a/ipacm/inc/IPACM_ConntrackListener.h
+++ b/ipacm/inc/IPACM_ConntrackListener.h
@@ -61,6 +61,13 @@
 
 }nat_entry_bundle;
 
+typedef struct _ct_entry
+{
+	struct nf_conntrack *ct;
+	u_int8_t  protocol;
+	enum nf_conntrack_msg_type type;
+}ct_entry;
+
 class IPACM_ConntrackListener : public IPACM_Listener
 {
 
@@ -78,13 +85,14 @@
 	uint32_t nonnat_iface_ipv4_addr[MAX_IFACE_ADDRESS];
 	uint32_t sta_clnt_ipv4_addr[MAX_STA_CLNT_IFACES];
 	IPACM_Config *pConfig;
-	struct nf_conntrack **ct_entries;
+	ct_entry *ct_entries;
+	ct_entry ct_cache[MAX_CONNTRACK_ENTRIES];
 #ifdef CT_OPT
 	IPACM_LanToLan *p_lan2lan;
 #endif
 
 	void ProcessCTMessage(void *);
-	void ProcessTCPorUDPMsg(struct nf_conntrack *,
+	bool ProcessTCPorUDPMsg(struct nf_conntrack *,
 	enum nf_conntrack_msg_type, u_int8_t);
 	void TriggerWANUp(void *);
 	void TriggerWANDown(uint32_t);
@@ -119,8 +127,11 @@
 	void HandleSTAClientAddEvt(uint32_t);
 	void HandleSTAClientDelEvt(uint32_t);
 	int  CreateConnTrackThreads(void);
-	void readConntrack(void);
+	void readConntrack(int fd);
 	void processConntrack(void);
+	void CacheORDeleteConntrack(struct nf_conntrack *ct,
+		enum nf_conntrack_msg_type type, u_int8_t protocol);
+	void processCacheConntrack(void);
 };
 
 extern IPACM_ConntrackListener *CtList;
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
index dabd8e6..29afd50 100644
--- a/ipacm/src/IPACM_ConntrackClient.cpp
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -421,17 +421,6 @@
 	unsigned subscrips = 0;
 
 	IPACMDBG("\n");
-	/* In Android we get conntrack handles once after tethering is enabled but we
-	   loose connections info for embedded traffic if running before. So no NAT
-	   entries are added for embedded traffic due to which we see NAT exception and
-	   data takes S/W path which results in less throughput. Hence for embedded
-	   traffic info, framework sends conntrack dump before providing handles. Here
-	   reading ct entries before creating filter on Fd in order to have NAT entries
-	   for both TCP/UDP embedded traffic. */
-	if(CtList != NULL && !CtList->isReadCTDone)
-	{
-		CtList->readConntrack();
-	}
 
 	pClient = IPACM_ConntrackClient::GetInstance();
 	if(pClient == NULL)
@@ -585,7 +574,8 @@
 	/* Block to catch events from net filter connection track */
 ctcatch:
 	ret = nfct_catch(pClient->udp_hdl);
-	if((ret == -1) && (errno != ENOMSG))
+	/* Due to conntrack dump, sequence number might mismatch for initial events. */
+	if((ret == -1) && (errno != ENOMSG) && (errno != EILSEQ))
 	{
 		IPACMDBG("(%d)(%d)(%s)\n", ret, errno, strerror(errno));
 		return NULL;
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index baddb4d..b991324 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -40,7 +40,6 @@
 IPACM_ConntrackListener::IPACM_ConntrackListener()
 {
 	 IPACMDBG("\n");
-
 	 isNatThreadStart = false;
 	 isCTReg = false;
 	 WanUp = false;
@@ -70,6 +69,9 @@
 #ifdef CT_OPT
 	 p_lan2lan = IPACM_LanToLan::getLan2LanInstance();
 #endif
+
+	 /* Initialize the CT cache. */
+	 memset(ct_cache, 0, sizeof(ct_cache));
 }
 
 void IPACM_ConntrackListener::event_callback(ipa_cm_event_id evt,
@@ -105,6 +107,8 @@
 			{
 				processConntrack();
 			}
+			/* Process the cached entries. */
+			processCacheConntrack();
 			break;
 
 	 case IPA_HANDLE_WAN_DOWN:
@@ -675,6 +679,7 @@
 {
 	 ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
 	 u_int8_t l4proto = 0;
+	 bool cache_ct = false;
 
 #ifdef IPACM_DEBUG
 	 char buf[1024];
@@ -696,11 +701,14 @@
 	 }
 	 else
 	 {
-			ProcessTCPorUDPMsg(evt_data->ct, evt_data->type, l4proto);
+			cache_ct = ProcessTCPorUDPMsg(evt_data->ct, evt_data->type, l4proto);
 	 }
 
 	 /* Cleanup item that was allocated during the original CT callback */
-	 nfct_destroy(evt_data->ct);
+	 if (!cache_ct)
+		nfct_destroy(evt_data->ct);
+	 else
+	 	CacheORDeleteConntrack(evt_data->ct, evt_data->type, l4proto);
 	 return;
 }
 
@@ -847,7 +855,7 @@
 	}
 	else if (IPPROTO_UDP == input->rule->protocol)
 	{
-		if (NFCT_T_NEW == input->type)
+		if (NFCT_T_NEW == input->type || NFCT_T_UPDATE == input->type)
 		{
 			IPACMDBG("New UDP connection at time %ld\n", time(NULL));
 			if (!CtList->isWanUp())
@@ -1037,7 +1045,7 @@
 }
 
 /* conntrack send in host order and ipa expects in host order */
-void IPACM_ConntrackListener::ProcessTCPorUDPMsg(
+bool IPACM_ConntrackListener::ProcessTCPorUDPMsg(
 	 struct nf_conntrack *ct,
 	 enum nf_conntrack_msg_type type,
 	 u_int8_t l4proto)
@@ -1046,6 +1054,7 @@
 	 uint32_t status = 0;
 	 uint32_t orig_src_ip, orig_dst_ip;
 	 bool isAdd = false;
+	 bool cache_ct = false;
 
 	 nat_entry_bundle nat_entry;
 	 nat_entry.isTempEntry = false;
@@ -1075,7 +1084,7 @@
 		 if(orig_src_ip == 0)
 		 {
 			 IPACMERR("unable to retrieve orig src ip address\n");
-			 return;
+			 return cache_ct;
 		 }
 
 		 orig_dst_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST);
@@ -1083,7 +1092,7 @@
 		 if(orig_dst_ip == 0)
 		 {
 			 IPACMERR("unable to retrieve orig dst ip address\n");
-			 return;
+			 return cache_ct;
 		 }
 
 		if(orig_src_ip == wan_ipaddr)
@@ -1104,8 +1113,11 @@
 #ifdef CT_OPT
 			HandleLan2Lan(ct, type, &rule);
 #endif
-		 	IPACMDBG("Neither source Nor destination nat\n");
-		 	goto IGNORE;
+		 	IPACMDBG("Neither source Nor destination nat.\n");
+			/* If WAN is not up, cache the event. */
+			if(!CtList->isWanUp())
+				cache_ct = true;
+			goto IGNORE;
 		}
 	}
 
@@ -1137,7 +1149,7 @@
 	CheckSTAClient(&rule, &nat_entry.isTempEntry);
 	nat_entry.rule = &rule;
 	AddORDeleteNatEntry(&nat_entry);
-	return;
+	return cache_ct;
 
 IGNORE:
 	IPACMDBG_H("ignoring below Nat Entry\n");
@@ -1147,7 +1159,7 @@
 	IPACMDBG("private port or src port: 0x%x, Decimal:%d\n", rule.private_port, rule.private_port);
 	IPACMDBG("public port or reply dst port: 0x%x, Decimal:%d\n", rule.public_port, rule.public_port);
 	IPACMDBG("Protocol: %d, destination nat flag: %d\n", rule.protocol, rule.dst_nat);
-	return;
+	return cache_ct;
 }
 
 void IPACM_ConntrackListener::HandleSTAClientAddEvt(uint32_t clnt_ip_addr)
@@ -1219,29 +1231,30 @@
 	return false;
 }
 
-void IPACM_ConntrackListener::readConntrack() {
+void IPACM_ConntrackListener::readConntrack(int fd) {
 
-	IPACM_ConntrackClient *pClient;
-	int len_fil = 0, recv_bytes = -1, index = 0, len =0;
+	int recv_bytes = -1, index = 0, len =0;
 	char buffer[CT_ENTRIES_BUFFER_SIZE];
-	char *buf = &buffer[0];
 	struct nf_conntrack *ct;
 	struct nlmsghdr *nl_header;
-	static struct sockaddr_nl nlAddr = {
-		.nl_family = AF_NETLINK
+   	struct iovec iov = {
+		.iov_base	= buffer,
+		.iov_len	= CT_ENTRIES_BUFFER_SIZE,
 	};
-	unsigned int addr_len = sizeof(nlAddr);
+	struct sockaddr_nl addr;
+	struct msghdr msg = {
+		.msg_name	= &addr,
+		.msg_namelen	= sizeof(struct sockaddr_nl),
+		.msg_iov	= &iov,
+		.msg_iovlen	= 1,
+		.msg_control	= NULL,
+		.msg_controllen	= 0,
+		.msg_flags	= 0,
+	};
 
-	pClient = IPACM_ConntrackClient::GetInstance();
-	if(pClient == NULL)
-	{
-		IPACMERR("unable to get conntrack client instance\n");
-		return;
-	}
+	len = MAX_CONNTRACK_ENTRIES * sizeof(ct_entry);
 
-	len = MAX_CONNTRACK_ENTRIES * sizeof(struct nf_conntrack **);
-
-	ct_entries = (struct nf_conntrack **) malloc(len);
+	ct_entries = (ct_entry *) malloc(len);
 	if(ct_entries == NULL)
 	{
 		IPACMERR("unable to allocate ct_entries memory \n");
@@ -1249,60 +1262,66 @@
 	}
 	memset(ct_entries, 0, len);
 
-	if( pClient->fd_tcp < 0)
+	if( fd < 0)
 	{
-		IPACMDBG_H("Invalid fd %d \n",pClient->fd_tcp);
+		IPACMDBG_H("Invalid fd %d \n",fd);
 		free(ct_entries);
 		return;
 	}
-
 	IPACMDBG_H("receiving conntrack entries started.\n");
-	while(len_fil < sizeof(buffer) && index <  MAX_CONNTRACK_ENTRIES)
+	len = CT_ENTRIES_BUFFER_SIZE;
+	while (len > 0)
 	{
-	 	recv_bytes = recvfrom( pClient->fd_tcp, buf, sizeof(buffer)-len_fil, 0, (struct sockaddr *)&nlAddr, (socklen_t *)&addr_len);
+		memset(buffer, 0, CT_ENTRIES_BUFFER_SIZE);
+		recv_bytes = recvmsg(fd, &msg, 0);
 		if(recv_bytes < 0)
 		{
-			IPACMDBG_H("error in receiving conntrack entries %d%s",errno, strerror(errno));
+			IPACMDBG_H("error in receiving conntrack entries %d%s\n",errno, strerror(errno));
 			break;
 		}
 		else
 		{
-			nl_header = (struct nlmsghdr *)buf;
-
-			if (NLMSG_OK(nl_header, recv_bytes) == 0 || nl_header->nlmsg_type == NLMSG_ERROR)
+			len -= recv_bytes;
+			nl_header = (struct nlmsghdr *)buffer;
+			IPACMDBG_H("Number of bytes:%d to parse\n", recv_bytes);
+			while(NLMSG_OK(nl_header, recv_bytes) && (index < MAX_CONNTRACK_ENTRIES))
 			{
-				IPACMDBG_H("recv_bytes is %d\n",recv_bytes);
-				break;
-			}
-			ct = nfct_new();
-			if (ct != NULL)
-			{
-				int parseResult =  nfct_parse_conntrack((nf_conntrack_msg_type) NFCT_T_ALL,nl_header, ct);
-				if(parseResult != NFCT_T_ERROR)
+				if (nl_header->nlmsg_type == NLMSG_ERROR)
 				{
-					ct_entries[index++] = ct;
+					IPACMDBG_H("Error, recv_bytes is %d\n",recv_bytes);
+					break;
+				}
+				ct = nfct_new();
+				if (ct != NULL)
+				{
+					int parseResult =  nfct_parse_conntrack((nf_conntrack_msg_type) NFCT_T_ALL,nl_header, ct);
+					if(parseResult != NFCT_T_ERROR && parseResult != 0)
+					{
+						ct_entries[index].ct = ct;
+						ct_entries[index++].type = (nf_conntrack_msg_type)parseResult;
+					}
+					else
+					{
+						IPACMDBG_H("error in parsing  %d%s \n", errno, strerror(errno));
+						nfct_destroy(ct);
+					}
 				}
 				else
 				{
-					IPACMDBG_H("error in parsing  %d%s \n", errno, strerror(errno));
+					IPACMDBG_H("ct allocation failed\n");
 				}
+				if (nl_header->nlmsg_type == NLMSG_DONE)
+				{
+					IPACMDBG_H("Message is done.\n");
+					break;
+				}
+				nl_header = NLMSG_NEXT(nl_header, recv_bytes);
 			}
-			else
-			{
-				IPACMDBG_H("ct allocation failed");
-				continue;
-			}
-
-			if((nl_header->nlmsg_type & NLM_F_MULTI) == 0)
-			{
-				break;
-			}
-			len_fil += recv_bytes;
-			buf = buf + recv_bytes;
 		}
 	}
+
 	isReadCTDone = true;
-	IPACMDBG_H("receiving conntrack entries ended.\n");
+	IPACMDBG_H("receiving conntrack entries ended. No of entries: %d\n", index);
 	if(isWanUp() && !isProcessCTDone)
 	{
 		IPACMDBG_H("wan is up, process ct entries \n");
@@ -1317,15 +1336,14 @@
 	uint8_t ip_type;
 	int index = 0;
 	ipacm_ct_evt_data *ct_data;
-	enum nf_conntrack_msg_type type = NFCT_T_ALL;
 	IPACMDBG_H("process conntrack started \n");
 	if(ct_entries != NULL)
 	{
-		while(ct_entries[index] != NULL)
+		while(ct_entries[index].ct != NULL)
 		{
-			ip_type = nfct_get_attr_u8(ct_entries[index], ATTR_REPL_L3PROTO);
-			if(!(AF_INET6 == ip_type) && isLocalHostAddr(nfct_get_attr_u32(ct_entries[index], ATTR_ORIG_IPV4_SRC),
-					nfct_get_attr_u32(ct_entries[index], ATTR_ORIG_IPV4_DST)))
+			ip_type = nfct_get_attr_u8(ct_entries[index].ct, ATTR_REPL_L3PROTO);
+			if((AF_INET == ip_type) && isLocalHostAddr(nfct_get_attr_u32(ct_entries[index].ct, ATTR_ORIG_IPV4_SRC),
+					nfct_get_attr_u32(ct_entries[index].ct, ATTR_ORIG_IPV4_DST)))
 			{
 				IPACMDBG_H(" loopback entry \n");
 				goto IGNORE;
@@ -1346,8 +1364,8 @@
 				goto IGNORE;
 			}
 
-			ct_data->ct = ct_entries[index];
-			ct_data->type = type;
+			ct_data->ct = ct_entries[index].ct;
+			ct_data->type = ct_entries[index].type;
 
 #ifdef CT_OPT
 			if(AF_INET6 == ip_type)
@@ -1361,7 +1379,7 @@
 		free(ct_data);
 		continue;
 IGNORE:
-		nfct_destroy(ct_entries[index]);
+		nfct_destroy(ct_entries[index].ct);
 		index++;
 		}
 	}
@@ -1372,6 +1390,114 @@
 	}
 	isProcessCTDone = true;
 	free(ct_entries);
-	IPACMDBG_H("process conntrack ended \n");
+	ct_entries = NULL;
+	IPACMDBG_H("process conntrack ended. Number of entries:%d \n", index);
 	return;
 }
+
+void IPACM_ConntrackListener::CacheORDeleteConntrack
+(
+	struct nf_conntrack *ct,
+	enum nf_conntrack_msg_type type,
+	u_int8_t protocol
+)
+{
+	u_int8_t tcp_state;
+	int i = 0, free_idx = -1;
+
+	IPACMDBG("CT entry, type (%d), protocol(%d)\n", type, protocol);
+	/* Check for duplicate entry and in parallel find first free index. */
+	for(; i < MAX_CONNTRACK_ENTRIES; i++)
+	{
+		if (ct_cache[i].ct != NULL)
+		{
+			if (nfct_cmp(ct_cache[i].ct, ct, NFCT_CMP_ORIG | NFCT_CMP_REPL))
+			{
+				/* Duplicate entry. */
+				IPACMDBG("Duplicate CT entry, type (%d), protocol(%d)\n",
+					type, protocol);
+				break;
+			}
+		}
+		else if ((ct_cache[i].ct == NULL) && (free_idx == -1))
+		{
+			/* Cache the first free index. */
+			free_idx = i;
+		}
+	}
+
+	/* Duplicate entry handling. */
+	if (i < MAX_CONNTRACK_ENTRIES)
+	{
+		if (IPPROTO_TCP == protocol)
+		{
+			tcp_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+			if (TCP_CONNTRACK_FIN_WAIT == tcp_state || type == NFCT_T_DESTROY)
+			{
+				IPACMDBG("TCP state TCP_CONNTRACK_FIN_WAIT(%d) "
+							 "or type NFCT_T_DESTROY\n", tcp_state);
+				nfct_destroy(ct_cache[i].ct);
+				nfct_destroy(ct);
+				memset(&ct_cache[i], 0, sizeof(ct_cache[i]));
+				return ;
+			}
+		}
+		if ((IPPROTO_UDP == protocol) && (type == NFCT_T_DESTROY))
+		{
+			IPACMDBG("UDP type NFCT_T_DESTROY\n");
+			nfct_destroy(ct_cache[i].ct);
+			nfct_destroy(ct);
+			memset(&ct_cache[i], 0, sizeof(ct_cache[i]));
+			return;
+		}
+	}
+	else if ((i == MAX_CONNTRACK_ENTRIES) &&
+		(type != NFCT_T_DESTROY) && (free_idx != -1))
+	{
+		if (IPPROTO_TCP == protocol)
+		{
+			tcp_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+			if (TCP_CONNTRACK_ESTABLISHED == tcp_state)
+			{
+				IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED\n");
+				/* Cache the entry. */
+				ct_cache[free_idx].ct = ct;
+				ct_cache[free_idx].protocol = protocol;
+				ct_cache[free_idx].type = type;
+				return;
+			}
+		}
+		if (IPPROTO_UDP == protocol)
+		{
+			if (NFCT_T_NEW  == type)
+			{
+				IPACMDBG("New UDP connection\n");
+				/* Cache the entry. */
+				ct_cache[free_idx].ct = ct;
+				ct_cache[free_idx].protocol = protocol;
+				ct_cache[free_idx].type = type;
+				return;
+			}
+		}
+	}
+	/* In all other cases, free the conntracy entry. */
+	nfct_destroy(ct);
+	return ;
+}
+void IPACM_ConntrackListener::processCacheConntrack(void)
+{
+	int i = 0;
+
+	IPACMDBG("Entry:\n");
+	for(; i < MAX_CONNTRACK_ENTRIES; i++)
+	{
+		if (ct_cache[i].ct != NULL)
+		{
+			ProcessTCPorUDPMsg(ct_cache[i].ct, ct_cache[i].type, ct_cache[i].protocol);
+			nfct_destroy(ct_cache[i].ct);
+			memset(&ct_cache[i], 0, sizeof(ct_cache[i]));
+		}
+	}
+	IPACMDBG("Exit:\n");
+}
+
diff --git a/ipacm/src/IPACM_Filtering.cpp b/ipacm/src/IPACM_Filtering.cpp
index b230c36..875a794 100644
--- a/ipacm/src/IPACM_Filtering.cpp
+++ b/ipacm/src/IPACM_Filtering.cpp
@@ -1006,17 +1006,18 @@
 	}
 
 	ret = ioctl(fd, IPA_IOC_MDFY_FLT_RULE, ruleTable);
+
+	for (i = 0; i < ruleTable->num_rules; i++)
+	{
+		if (ruleTable->rules[i].status != 0)
+		{
+			IPACMERR("Modifying filter rule %d failed\n", i);
+		}
+	}
+
 	if (ret != 0)
 	{
-		IPACMERR("Failed modifying filtering rule %pK\n", ruleTable);
-
-		for (i = 0; i < ruleTable->num_rules; i++)
-		{
-			if (ruleTable->rules[i].status != 0)
-			{
-				IPACMERR("Modifying filter rule %d failed\n", i);
-			}
-		}
+		IPACMERR("Failed modifying filtering rule IOCTL for %pK\n", ruleTable);
 		return false;
 	}
 
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 0a532fd..65bd3ca 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -4205,9 +4205,14 @@
 			mtu[i] = IPACM_Wan::queryMTU(ipa_if_num, IPA_IP_v4);
 
 			if (mtu[i] > 0)
+			{
 				mtu_rule_cnt++;
+				IPACMDBG_H("MTU[%d] is %d\n", i, mtu[i]);
+			}
 			else
-				IPACMERR("MTU is zero\n");
+			{
+				IPACMERR("MTU is 0");
+			}
 		}
 		IPACMDBG_H("total %d MTU rules are needed\n", mtu_rule_cnt);
 
@@ -4237,16 +4242,16 @@
 
 		flt_rule.rule.retain_hdr = 1;
 		flt_rule.rule.to_uc = 0;
-		flt_rule.rule.action = IPA_PASS_TO_ROUTING;
-		flt_rule.rule.eq_attrib_type = 0;
-		flt_rule.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
 		IPACMDBG_H("Private filter rule use table: %s\n",IPACM_Iface::ipacmcfg->rt_tbl_default_v4.name);
 
 		for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
 		{
 			/* add private subnet rule for ipv4 */
+			/* these 3 properties below will be reset during construct_mtu_rule */
 			flt_rule.rule.action = IPA_PASS_TO_ROUTING;
 			flt_rule.rule.eq_attrib_type = 0;
+			flt_rule.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
+
 			flt_rule.rule_hdl = private_fl_rule_hdl[i];
 			memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule.rule.attrib));
 			flt_rule.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
@@ -4264,7 +4269,9 @@
 				flt_rule.rule.attrib.u.v4.src_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
 				flt_rule.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
 				if (construct_mtu_rule(&flt_rule.rule, IPA_IP_v4, mtu[i]))
+				{
 					IPACMERR("Failed to modify MTU filtering rule.\n");
+				}
 				memcpy(&(pFilteringTable->rules[mtu_rule_idx + i]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
 				IPACMDBG_H("Adding MTU rule for private subnet 0x%x.\n", flt_rule.rule.attrib.u.v4.src_addr);
 			}
@@ -4302,7 +4309,14 @@
 
 	uint16_t mtu = IPACM_Wan::queryMTU(ipa_if_num, IPA_IP_v6);
 	if (mtu > 0)
+	{
+		IPACMDBG_H("MTU is %d\n", mtu);
 		rule_cnt ++;
+	}
+	else
+	{
+		IPACMERR("MTU is 0");
+	}
 
 	if(rx_prop != NULL)
 	{
diff --git a/ipacm/src/IPACM_OffloadManager.cpp b/ipacm/src/IPACM_OffloadManager.cpp
index 7919413..708725b 100644
--- a/ipacm/src/IPACM_OffloadManager.cpp
+++ b/ipacm/src/IPACM_OffloadManager.cpp
@@ -120,8 +120,9 @@
 
 RET IPACM_OffloadManager::provideFd(int fd, unsigned int groups)
 {
+	struct timeval tv;
 	IPACM_ConntrackClient *cc;
-	int on = 1, rel;
+	int on = 1, rel = 0;
 	struct sockaddr_nl	local;
 	unsigned int addr_len;
 
@@ -155,13 +156,39 @@
 			IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) );
 		}
 	} else if (groups == cc->subscrips_udp) {
+		/* Set receive timeout to 1s on the FD which is used to read conntrack dump. */
+		memset(&tv,0, sizeof(struct timeval));
+		tv.tv_sec = 1; /* 1s timeout */
+		rel = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
+		if (rel == -1)
+		{
+			IPACMERR("setsockopt returned error code %d ( %s )\n", errno, strerror(errno));
+		}
+
+		/* In Android we get conntrack handles once after tethering is enabled but we
+		   loose connections info for embedded traffic if running before. So no NAT
+		   entries are added for embedded traffic due to which we see NAT exception and
+		   data takes S/W path which results in less throughput. Hence for embedded
+		   traffic info, framework sends conntrack dump before providing handles. Here
+		   reading ct entries before creating filter on Fd in order to have NAT entries
+		   for both TCP/UDP embedded traffic.
+		*/
+		CtList->readConntrack(fd);
+		/* Reset receive timeout on the FD which is used to read conntrack dump. */
+		memset(&tv,0, sizeof(struct timeval));
+		rel = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
+		if (rel == -1)
+		{
+			IPACMERR("setsockopt returned error code %d ( %s )\n", errno, strerror(errno));
+		}
+
 		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) );
+		rel = setsockopt(cc->fd_udp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
 		if (rel == -1)
 		{
-			IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) );
+			IPACMERR("setsockopt returned error code %d ( %s )\n", errno, strerror(errno));
 		}
 	} else {
 		IPACMERR("Received unexpected fd with groups %d.\n", groups);
diff --git a/ipacm_vendor_product.mk b/ipacm_vendor_product.mk
index 9fe88b1..5c0fc23 100644
--- a/ipacm_vendor_product.mk
+++ b/ipacm_vendor_product.mk
@@ -11,8 +11,15 @@
 endif #TARGET_USES_QMAA_OVERRIDE_DATA
 endif #TARGET_USES_QMAA
 
+BOARD_IPA_LOW_RAM_EXCP_LIST := bengal
+
+ifeq ($(TARGET_HAS_LOW_RAM),true)
+ifneq ($(call is-board-platform-in-list,$(BOARD_IPA_LOW_RAM_EXCP_LIST)),true)
+	TARGET_DISABLE_IPACM := true
+endif
+endif
+
 ifneq ($(TARGET_DISABLE_IPACM),true)
-ifneq ($(TARGET_HAS_LOW_RAM),true)
 BOARD_PLATFORM_LIST := msm8909
 BOARD_PLATFORM_LIST += msm8916
 BOARD_PLATFORM_LIST += msm8917
@@ -40,4 +47,3 @@
 endif
 endif
 endif
-endif
\ No newline at end of file