Merge "ipacm: Fix reading the conntrack dump"
diff --git a/ipacm/inc/IPACM_ConntrackListener.h b/ipacm/inc/IPACM_ConntrackListener.h
index 6cc4188..7831498 100644
--- a/ipacm/inc/IPACM_ConntrackListener.h
+++ b/ipacm/inc/IPACM_ConntrackListener.h
@@ -119,7 +119,7 @@
 	void HandleSTAClientAddEvt(uint32_t);
 	void HandleSTAClientDelEvt(uint32_t);
 	int  CreateConnTrackThreads(void);
-	void readConntrack(void);
+	void readConntrack(int fd);
 	void processConntrack(void);
 };
 
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
index dabd8e6..f6bc9a6 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)
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index baddb4d..9d06442 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -1219,25 +1219,26 @@
 	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);
-
-	pClient = IPACM_ConntrackClient::GetInstance();
-	if(pClient == NULL)
-	{
-		IPACMERR("unable to get conntrack client instance\n");
-		return;
-	}
+	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,
+	};
 
 	len = MAX_CONNTRACK_ENTRIES * sizeof(struct nf_conntrack **);
 
@@ -1249,17 +1250,18 @@
 	}
 	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));
@@ -1267,42 +1269,45 @@
 		}
 		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)
+					{
+						ct_entries[index++] = ct;
+					}
+					else
+					{
+						IPACMDBG_H("error in parsing  %d%s \n", errno, strerror(errno));
+					}
 				}
 				else
 				{
-					IPACMDBG_H("error in parsing  %d%s \n", errno, strerror(errno));
+					IPACMDBG_H("ct allocation failed");
 				}
+				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");
@@ -1324,7 +1329,7 @@
 		while(ct_entries[index] != 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),
+			if((AF_INET == 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)))
 			{
 				IPACMDBG_H(" loopback entry \n");
@@ -1372,6 +1377,6 @@
 	}
 	isProcessCTDone = true;
 	free(ct_entries);
-	IPACMDBG_H("process conntrack ended \n");
+	IPACMDBG_H("process conntrack ended. Number of entries:%d \n", index);
 	return;
 }
diff --git a/ipacm/src/IPACM_OffloadManager.cpp b/ipacm/src/IPACM_OffloadManager.cpp
index 7919413..b5afda7 100644
--- a/ipacm/src/IPACM_OffloadManager.cpp
+++ b/ipacm/src/IPACM_OffloadManager.cpp
@@ -120,6 +120,7 @@
 
 RET IPACM_OffloadManager::provideFd(int fd, unsigned int groups)
 {
+	struct timeval tv;
 	IPACM_ConntrackClient *cc;
 	int on = 1, rel;
 	struct sockaddr_nl	local;
@@ -158,11 +159,30 @@
 		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));
 		}
+
+		/* 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);
 	} else {
 		IPACMERR("Received unexpected fd with groups %d.\n", groups);
 	}