1. update timeout for both tcp and udp connections
             2. To update udp connections timeout value use ip_conntrack_udp_timeout_stream
             3. To update tcp connection timeout value use ip_conntrack_tcp_timeout_established
             4. Start inotify thread to read update udp/tcp timeout values"

Change-Id: I383e1c9b0b142dc9ad4d630d9f4d1149ccbc97f2
diff --git a/ipacm/inc/IPACM_ConntrackClient.h b/ipacm/inc/IPACM_ConntrackClient.h
old mode 100644
new mode 100755
index 99742a7..715ce6e
--- a/ipacm/inc/IPACM_ConntrackClient.h
+++ b/ipacm/inc/IPACM_ConntrackClient.h
@@ -52,6 +52,7 @@
 {
 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
 #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+#include <sys/inotify.h>
 }
 
 using namespace std;
@@ -59,6 +60,17 @@
 #define UDP_TIMEOUT_UPDATE 20
 #define BROADCAST_IPV4_ADDR 0xFFFFFFFF
 
+
+#define IPACM_DIR_NAME       "/proc/sys/net/ipv4/netfilter"
+#define IPACM_TCP_FILE_NAME  "ip_conntrack_tcp_timeout_established"
+#define IPACM_UDP_FILE_NAME   "ip_conntrack_udp_timeout_stream"
+
+#define IPACM_TCP_FULL_FILE_NAME  "/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established"
+#define IPACM_UDP_FULL_FILE_NAME   "/proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream"
+
+#define INOTIFY_EVENT_SIZE  (sizeof(struct inotify_event))
+#define INOTIFY_BUF_LEN     (INOTIFY_EVENT_SIZE + 2*sizeof(IPACM_TCP_FILE_NAME))
+
 class IPACM_ConntrackClient
 {
 
@@ -83,10 +95,12 @@
 	 static int IPA_Conntrack_TCP_Filter_Init(void);
 	 static void* TCPRegisterWithConnTrack(void *);
 	 static void* UDPRegisterWithConnTrack(void *);
-	 static void* UDPConnTimeoutUpdate(void *ptr);
+	 static void* UDPConnTimeoutUpdate(void *);
+	 static void* TCPUDP_Timeout_monitor(void *);
 
 	 static void UpdateUDPFilters(void *);
 	 static void UpdateTCPFilters(void *);
+	 static void Read_TcpUdp_Timeout(char *in, int len);
 
 	 static IPACM_ConntrackClient* GetInstance();
 
diff --git a/ipacm/inc/IPACM_Conntrack_NATApp.h b/ipacm/inc/IPACM_Conntrack_NATApp.h
old mode 100644
new mode 100755
index 777a23f..530feb9
--- a/ipacm/inc/IPACM_Conntrack_NATApp.h
+++ b/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -85,6 +85,9 @@
 	ipacm_alg *pALGPorts;
 	uint16_t nALGPort;
 
+	uint32_t tcp_timeout;
+	uint32_t udp_timeout;
+
 	uint32_t PwrSaveIfs[IPA_MAX_NUM_WIFI_CLIENTS];
 
 	struct nf_conntrack *ct;
@@ -113,6 +116,8 @@
 
 	int UpdatePwrSaveIf(uint32_t);
 	int ResetPwrSaveIf(uint32_t);
+
+	void UpdateTcpUdpTo(uint32_t, int proto);
 };
 
 
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
old mode 100644
new mode 100755
index 355a3c7..0c0cb50
--- a/ipacm/src/IPACM_ConntrackClient.cpp
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -773,3 +773,125 @@
 
   return;
 }
+
+void IPACM_ConntrackClient::Read_TcpUdp_Timeout(char *in, int len)
+{
+	int proto;
+	FILE *fd = NULL;
+	char to_str[10];
+	uint32_t value;
+
+	if(!strncmp(in, IPACM_TCP_FILE_NAME, len))
+	{
+		proto = IPPROTO_TCP;
+	}
+	else if(!strncmp(in, IPACM_UDP_FILE_NAME, len))
+	{
+		proto = IPPROTO_UDP;
+	}
+	else
+	{
+		return;
+	}
+
+	if(proto == IPPROTO_TCP)
+	{
+		fd = fopen(IPACM_TCP_FULL_FILE_NAME, "r");
+	}
+	else 
+	{
+		fd = fopen(IPACM_UDP_FULL_FILE_NAME, "r");
+	}
+	if(fd < 0)
+	{
+		PERROR("unable to open file");
+		return;
+	}
+
+	fgets(to_str, sizeof(to_str), fd);
+	value = atoi(to_str);
+	IPACMDBG("Protocol %d file \"%s\" value: %d\n", proto, in, value);
+	NatApp::GetInstance()->UpdateTcpUdpTo(value, proto);
+
+	fclose(fd);
+	return;
+}
+
+void *IPACM_ConntrackClient::TCPUDP_Timeout_monitor(void *)
+{
+  int length;
+	int wd;
+	char buffer[INOTIFY_BUF_LEN];
+	int inotify_fd;
+	uint32_t mask = IN_MODIFY;
+	FILE *to_fd = NULL;
+	char to_str[10];
+	uint32_t value=0;
+	
+	to_fd = fopen(IPACM_TCP_FULL_FILE_NAME, "r");
+	if(to_fd < 0)
+	{
+	  PERROR("unable to open file \"ip_conntrack_tcp_timeout_established\" ");
+		return NULL;
+	}
+	memset(to_str, 0, sizeof(to_str));
+	fgets(to_str, sizeof(to_str), to_fd);
+	value = atoi(to_str);
+	IPACMDBG("ip conntrack tcp timeout initial value:%d\n", value);
+	NatApp::GetInstance()->UpdateTcpUdpTo(value, IPPROTO_TCP);
+	fclose(to_fd);
+	
+	to_fd = fopen(IPACM_UDP_FULL_FILE_NAME, "r");
+	if(to_fd < 0)
+	{
+	  PERROR("unable to open file \"ip_conntrack_udp_timeout_stream\" ");
+		return NULL;
+	}
+	memset(to_str, 0, sizeof(to_str));
+	fgets(to_str, sizeof(to_str), to_fd);
+	value = atoi(to_str);
+	IPACMDBG("ip conntrack udp timeout:%d\n", value);
+	NatApp::GetInstance()->UpdateTcpUdpTo(value, IPPROTO_UDP);
+	fclose(to_fd);
+
+	inotify_fd = inotify_init();
+	if (inotify_fd < 0)
+	{
+		PERROR("inotify_init");
+		return NULL;
+	}
+
+	IPACMDBG("Waiting for nofications in dir %s with mask: 0x%x\n",
+					              IPACM_DIR_NAME, mask);
+
+	wd = inotify_add_watch(inotify_fd,
+												 IPACM_DIR_NAME,
+												 mask);
+
+	while (1)
+	{
+		length = read(inotify_fd, buffer, INOTIFY_BUF_LEN);
+		struct inotify_event *event = (struct inotify_event *)buffer;
+
+		if (length < 0)
+		{
+			IPACMERR("inotify read() error return length: %d and mask: 0x%x 0x%x\n",
+							         length, event->mask, mask);
+			return NULL;
+		}
+
+		if( (event->len > 0) && (event->mask & IN_MODIFY) )
+		{
+			if(!(event->mask & IN_ISDIR))
+			{
+				IPACMDBG("Received inotify event for file %s with mask %x value",
+								       event->name, event->mask);
+				Read_TcpUdp_Timeout(event->name, event->len);
+			}
+		}
+	}
+	
+	(void)inotify_rm_watch(inotify_fd, wd);
+	(void)close(inotify_fd);
+	return NULL;
+}
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
old mode 100644
new mode 100755
index da0c732..5d61bc2
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -278,7 +278,7 @@
 int IPACM_ConntrackListener::CreateNatThreads(void)
 {
 	 int ret;
-	 pthread_t tcp_thread = 0, udp_thread = 0, udpcto_thread = 0;
+	 pthread_t tcp_thread = 0, udp_thread = 0, udpcto_thread = 0, to_monitor_thread = 0;
 
 	 if(isCTReg == false)
 	 {
@@ -322,6 +322,19 @@
 				 IPACMDBG("created upd conn timeout thread\n");
 			}
 
+			if(!to_monitor_thread)
+			{
+				ret = pthread_create(&to_monitor_thread, NULL, IPACM_ConntrackClient::TCPUDP_Timeout_monitor, NULL);
+				 if(0 != ret)
+				 {
+						IPACMERR("unable to create tcp/udp timeout monitor thread\n");
+						PERROR("unable to create tcp/udp timeout monitor\n");
+						goto error;
+				 }
+
+				 IPACMDBG("created tcp/udp timeout monitor thread\n");
+			}
+
 			isCTReg = true;
 	 }
 
@@ -347,6 +360,11 @@
 			pthread_cancel(udpcto_thread);
 	 }
 
+	 if(to_monitor_thread)
+	 {
+		 pthread_cancel(to_monitor_thread);
+	 }
+
 	 return -1;
 }
 
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
old mode 100644
new mode 100755
index 28de036..f82d7da
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -29,7 +29,6 @@
 #include "IPACM_Conntrack_NATApp.h"
 #include "IPACM_ConntrackClient.h"
 
-#define UDP_TIMEOUT_VALUE 30
 #define INVALID_IP_ADDR 0x0
 
 /* NatApp class Implementation */
@@ -393,8 +392,16 @@
 	}
 	
 	nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
-	nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_UDP);
-	nfct_set_attr_u32(ct, ATTR_TIMEOUT, UDP_TIMEOUT_VALUE);
+	if(rule->protocol == IPPROTO_UDP)
+	{
+		nfct_set_attr_u8(ct, ATTR_L4PROTO, rule->protocol);
+		nfct_set_attr_u32(ct, ATTR_TIMEOUT, udp_timeout);
+	}
+	else
+	{
+		nfct_set_attr_u8(ct, ATTR_L4PROTO, rule->protocol);
+		nfct_set_attr_u32(ct, ATTR_TIMEOUT, tcp_timeout);
+	}
 
 	if(rule->dst_nat == false)
 	{
@@ -422,7 +429,9 @@
 	IPACMDBG("Source Port: %d, Destination Port: %d\n",
 					 nfct_get_attr_u16(ct, ATTR_PORT_SRC), nfct_get_attr_u16(ct, ATTR_PORT_DST)); 
 	
-	IPACMDBG("updating udp connection with time: %d\n", UDP_TIMEOUT_VALUE);
+	IPACMDBG("updating %d connection with time: %d\n", 
+					 rule->protocol, nfct_get_attr_u32(ct, ATTR_TIMEOUT));
+
 	ret = nfct_query(ct_hdl, NFCT_Q_UPDATE, ct);
 	if(ret == -1)
 	{
@@ -445,8 +454,7 @@
 	for(cnt = 0; cnt < curCnt; cnt++)
 	{
 		ts = 0;
-		if(IPPROTO_UDP == cache[cnt].protocol &&
-			 cache[cnt].enabled == true)
+		if(cache[cnt].enabled == true)
 		{
 			IPACMDBG("\n");
 			if(ipa_nat_query_timestamp(nat_table_hdl, cache[cnt].rule_hdl, &ts) < 0)
@@ -457,6 +465,8 @@
 
 			if(cache[cnt].timestamp == ts)
 			{
+				IPACMERR("No Change in Time Stamp: cahce:%d, ipahw:%d\n",
+								                  cache[cnt].timestamp, ts);
 				continue;
 			}
 			
@@ -608,6 +618,20 @@
 	return -1;
 }
 
+void NatApp::UpdateTcpUdpTo(uint32_t new_value, int proto)
+{
+	if(proto == IPPROTO_TCP)
+	{
+		tcp_timeout = new_value;
+		IPACMDBG("new nat tcp timeout value: %d\n", tcp_timeout);
+	}
+	else if(proto == IPPROTO_UDP)
+	{
+		udp_timeout = new_value;
+		IPACMDBG("new nat udp timeout value: %d\n", udp_timeout);
+	}
+}
+
 uint32_t NatApp::GetTableHdl(uint32_t in_ip_addr)
 {
 	if(in_ip_addr == pub_ip_addr)