Merge "IPACM: get upstream and tethered iface in Android"
diff --git a/ipacm/inc/IPACM_ConntrackListener.h b/ipacm/inc/IPACM_ConntrackListener.h
index e5827f2..c1249c2 100644
--- a/ipacm/inc/IPACM_ConntrackListener.h
+++ b/ipacm/inc/IPACM_ConntrackListener.h
@@ -76,8 +76,6 @@
 	 int  CreateNatThreads(void);
 	 int  CreateConnTrackThreads(void);
 
-	 void HandleNeighIpAddrAddEvt(void *);
-	 void HandleNeighIpAddrDelEvt(void *);
 #ifdef CT_OPT
 	 void ProcessCTV6Message(void *);
 #endif
@@ -93,6 +91,9 @@
 	 {
 		return WanUp;
 	 }
+
+   void HandleNeighIpAddrAddEvt(ipacm_event_data_all *);
+   void HandleNeighIpAddrDelEvt(uint32_t);
 };
 
 extern IPACM_ConntrackListener *CtList;
diff --git a/ipacm/inc/IPACM_Conntrack_NATApp.h b/ipacm/inc/IPACM_Conntrack_NATApp.h
index 63af013..9eb9b4f 100644
--- a/ipacm/inc/IPACM_Conntrack_NATApp.h
+++ b/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -1,4 +1,4 @@
-/* 
+/*
 Copyright (c) 2013, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -112,6 +112,7 @@
 
 	int UpdatePwrSaveIf(uint32_t);
 	int ResetPwrSaveIf(uint32_t);
+        int DelEntriesOnClntDiscon(uint32_t);
 
 	void UpdateTcpUdpTo(uint32_t, int proto);
 
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index ae11d34..3559a8c 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -56,10 +56,6 @@
 	 IPACM_EvtDispatcher::registr(IPA_PROCESS_CT_MESSAGE_V6, this);
 	 IPACM_EvtDispatcher::registr(IPA_HANDLE_WLAN_UP, this);
 	 IPACM_EvtDispatcher::registr(IPA_HANDLE_LAN_UP, this);
-	 IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, this);
-	 IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, this);
-
-	IPACMDBG("creating conntrack threads\n");
 
 #ifdef CT_OPT
 	 p_lan2lan = IPACM_LanToLan::getLan2LanInstance();
@@ -121,28 +117,13 @@
 			IPACM_ConntrackClient::UpdateTCPFilters(data, false);
 			break;
 
-	 case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
-		 {
-			 IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT event\n");
-			 HandleNeighIpAddrAddEvt(data);
-		 }
-		 break;
-
-	 case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
-		 {
-			 IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT event\n");
-			 HandleNeighIpAddrDelEvt(data);
-		 }
-		 break;
-
 	 default:
 			IPACMDBG("Ignore cmd %d\n", evt);
 			break;
 	 }
 }
-void IPACM_ConntrackListener::HandleNeighIpAddrAddEvt(void *in_param)
+void IPACM_ConntrackListener::HandleNeighIpAddrAddEvt(ipacm_event_data_all *data)
 {
-	ipacm_event_data_all *data = (ipacm_event_data_all *)in_param;
 	int fd = 0, len = 0, cnt, i, j;
 	struct ifreq ifr;
 	bool isNatIface = false;
@@ -152,6 +133,8 @@
 		IPACMDBG("Ignoring IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT EVENT\n");
 		return;
 	}
+
+  IPACMDBG("\n");
 	IPACMDBG("Received interface index %d with ip type: %d", data->if_index, data->iptype);
 	iptodot(" and ipv4 address", data->ipv4_addr);
 
@@ -165,9 +148,8 @@
 		}
 	}
 
+
 	cnt = pConfig->GetNatIfacesCnt();
-	if(NatIfaceCnt != cnt)
-	{
 		NatIfaceCnt = cnt;
 		if(pNatIfaces != NULL)
 		{
@@ -189,9 +171,8 @@
 			IPACMERR("Unable to retrieve non nat ifaces\n");
 			return;
 		}
+  IPACMDBG("Update %d Nat ifaces\n", NatIfaceCnt);
 
-		IPACMDBG("Update %d Nat ifaces", NatIfaceCnt);
-	}
 
 	/* Search/Configure linux interface-index and map it to IPA interface-index */
 	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
@@ -265,37 +246,39 @@
 
 }
 
-void IPACM_ConntrackListener::HandleNeighIpAddrDelEvt(void *in_param)
+void IPACM_ConntrackListener::HandleNeighIpAddrDelEvt(uint32_t ipv4_addr)
 {
-	ipacm_event_data_all *data = (ipacm_event_data_all *)in_param;
 	int cnt;
 
-	if(data->ipv4_addr == 0 || data->iptype != IPA_IP_v4)
+	if(ipv4_addr == 0)
 	{
 		IPACMDBG("Ignoring IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT EVENT\n");
 		return;
 	}
-	IPACMDBG("Received interface index %d with ip type:%d", data->if_index, data->iptype);
+
+  IPACMDBG("\n");
+  iptodot("Received ip addr", ipv4_addr);
 	IPACMDBG("Entering NAT entry deletion checking\n");
 
 	for(cnt = 0; cnt<MAX_NAT_IFACES; cnt++)
 	{
-		if(nat_iface_ipv4_addr[cnt] == data->ipv4_addr)
+		if(nat_iface_ipv4_addr[cnt] == ipv4_addr)
 		{
-			IPACMDBG("Reseting ct filters of Interface (%d), entry (%d) ", data->if_index, cnt);
+			IPACMDBG("Reseting ct nat iface, entry (%d) ", cnt);
 			iptodot("with ipv4 address", nat_iface_ipv4_addr[cnt]);
 			nat_iface_ipv4_addr[cnt] = 0;
 		}
 
-		if(nonnat_iface_ipv4_addr[cnt] == data->ipv4_addr)
+		if(nonnat_iface_ipv4_addr[cnt] == ipv4_addr)
 		{
-			IPACMDBG("Reseting ct filters of Interface (%d), entry (%d) ", data->if_index, cnt);
+			IPACMDBG("Reseting ct filters, entry (%d) ", cnt);
 			iptodot("with ipv4 address", nonnat_iface_ipv4_addr[cnt]);
 			nonnat_iface_ipv4_addr[cnt] = 0;
 		}
 	}
 
-	nat_inst->FlushTempEntries(data->ipv4_addr, false);
+	nat_inst->FlushTempEntries(ipv4_addr, false);
+  nat_inst->DelEntriesOnClntDiscon(ipv4_addr);
 	return;
 }
 
@@ -303,7 +286,7 @@
 {
 	 ipacm_event_iface_up *wanup_data = (ipacm_event_iface_up *)in_param;
 
-	 IPACMDBG("Recevied below information during wanup, ");
+	 IPACMDBG("Recevied below information during wanup,\n");
 	 IPACMDBG("if_name:%s, ipv4_address:0x%x\n",
 						wanup_data->ifname, wanup_data->ipv4_addr);
 
@@ -362,6 +345,7 @@
 
 				 IPACMDBG("created UDP conntrack event listner thread\n");
 			}
+
 			isCTReg = true;
 	 }
 
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
index d6bbc19..b55d7e9 100644
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -714,3 +714,49 @@
 
 	return;
 }
+
+int NatApp::DelEntriesOnClntDiscon(uint32_t ip_addr)
+{
+ 	int cnt, tmp = curCnt;
+	IPACMDBG("Received IP address: 0x%x\n", ip_addr);
+
+	if(ip_addr == INVALID_IP_ADDR)
+	{
+		IPACMERR("Invalid ip address received\n");
+		return -1;
+	}
+
+	CHK_TBL_HDL();
+
+  for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+  {
+    if(PwrSaveIfs[cnt] == ip_addr)
+    {
+      PwrSaveIfs[cnt] = 0;
+      IPACMDBG("Remove %d power save entry\n", cnt);
+      break;
+    }
+  }
+
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		if(cache[cnt].private_ip == ip_addr)
+		{
+
+      if(cache[cnt].enabled == true)
+      {
+			if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+			{
+				IPACMERR("unable to delete the rule\n");
+				continue;
+			}
+      }
+
+			memset(&cache[cnt], 0, sizeof(cache[cnt]));
+      curCnt--;
+		}
+	}
+
+  IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
+	return 0;
+}
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 0bfe4c7..851b181 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -49,6 +49,8 @@
 #include "linux/rmnet_ipa_fd_ioctl.h"
 #include "linux/ipa_qmi_service_v01.h"
 #include "linux/msm_ipa.h"
+#include "IPACM_ConntrackListener.h"
+
 
 IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index)
 {
@@ -413,6 +415,11 @@
 					return;
 				}
 				handle_eth_client_route_rule(data->mac_addr, data->iptype);
+				if (data->iptype == IPA_IP_v4)
+				{
+					/* Add NAT rules after ipv4 RT rules are set */
+					CtList->HandleNeighIpAddrAddEvt(data);
+				}
 				return;
 			}
 		}
@@ -1284,11 +1291,13 @@
 			   }
 			   else
 			   {
-			     IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
-			     delete_eth_rtrules(clnt_indx,IPA_IP_v4);
-		         get_client_memptr(eth_client, clnt_indx)->route_rule_set_v4 = false;
-			     get_client_memptr(eth_client, clnt_indx)->v4_addr = data->ipv4_addr;
-			}
+					IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
+					/* delete NAT rules first */
+					CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, clnt_indx)->v4_addr);
+					delete_eth_rtrules(clnt_indx,IPA_IP_v4);
+					get_client_memptr(eth_client, clnt_indx)->route_rule_set_v4 = false;
+					get_client_memptr(eth_client, clnt_indx)->v4_addr = data->ipv4_addr;
+				}
 		}
 	}
 	else
@@ -1555,19 +1564,19 @@
 	/* First reset nat rules and then route rules */
 	if(get_client_memptr(eth_client, clt_indx)->ipv4_set == true)
 	{
-	        IPACMDBG_H("Deleting Nat Rules\n");
-	        Nat_App->UpdatePwrSaveIf(get_client_memptr(eth_client, clt_indx)->v4_addr);
+			IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(eth_client, clt_indx)->v4_addr);
+			CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, clt_indx)->v4_addr);
  	}
 
 	if (delete_eth_rtrules(clt_indx, IPA_IP_v4))
 	{
-		IPACMERR("unbale to delete ecm-client v4 route rules\n");
+		IPACMERR("unbale to delete ecm-client v4 route rules for index: %d\n", clt_indx);
 		return IPACM_FAILURE;
 	}
 
 	if (delete_eth_rtrules(clt_indx, IPA_IP_v6))
 	{
-		IPACMERR("unbale to delete ecm-client v6 route rules\n");
+		IPACMERR("unbale to delete ecm-client v6 route rules for index: %d\n", clt_indx);
 		return IPACM_FAILURE;
 	}
 
@@ -1704,8 +1713,26 @@
 	IPACMDBG_H("left %d eth clients need to be deleted \n ", num_eth_client);
 	for (i = 0; i < num_eth_client; i++)
 	{
-			delete_eth_rtrules(i, IPA_IP_v4);
-			delete_eth_rtrules(i, IPA_IP_v6);
+			/* First reset nat rules and then route rules */
+			if(get_client_memptr(eth_client, i)->ipv4_set == true)
+			{
+				IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(eth_client, i)->v4_addr);
+				CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, i)->v4_addr);
+			}
+
+			if (delete_eth_rtrules(i, IPA_IP_v4))
+			{
+				IPACMERR("unbale to delete ecm-client v4 route rules for index %d\n", i);
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+
+			if (delete_eth_rtrules(i, IPA_IP_v6))
+			{
+				IPACMERR("unbale to delete ecm-client v6 route rules for index %d\n", i);
+				res = IPACM_FAILURE;
+				goto fail;
+			}
 
 			IPACMDBG_H("Delete %d client header\n", num_eth_client);
 
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
index 670599a..badcc7e 100644
--- a/ipacm/src/IPACM_Main.cpp
+++ b/ipacm/src/IPACM_Main.cpp
@@ -707,7 +707,8 @@
 ===========================================================================*/
 /*!
 @brief
-  Determine if IPACM process exists from its previous Process ID
+  Determine whether there's already an IPACM process running, if so, terminate
+  the current one
 
 @return
 	None
@@ -724,62 +725,43 @@
 
 void ipa_is_ipacm_running(void) {
 
-	FILE *fp = NULL;
-	pid_t ipacm_pid =0;
-	char string[IPA_MAX_FILE_LEN];
+	int fd;
+	struct flock lock;
+	int retval;
 
-	/* find the latest pid of executed IPACM */
-	fp = fopen(IPACM_PID_FILE, "r");
-	if ( fp == NULL )
+	fd = open(IPACM_PID_FILE, O_RDWR | O_CREAT, 0600);
+	if ( fd <= 0 )
 	{
-		IPACMDBG_H("1st IPACM running \n");
+		IPACMERR("Failed to open %s, error is %d - %s\n",
+				 IPACM_PID_FILE, errno, strerror(errno));
+		exit(0);
 	}
-	else if (fscanf(fp, "%d", &ipacm_pid) != 1)
+
+	/*
+	 * Getting an exclusive Write lock on the file, if it fails,
+	 * it means that another instance of IPACM is running and it
+	 * got the lock before us.
+	 */
+	memset(&lock, 0, sizeof(lock));
+	lock.l_type = F_WRLCK;
+	retval = fcntl(fd, F_SETLK, &lock);
+
+	if (retval != 0)
 	{
-		IPACMERR("Error reading ipacm_pid file \n");
-		ipacm_pid = 0;
-		fclose(fp);
+		retval = fcntl(fd, F_GETLK, &lock);
+		if (retval == 0)
+		{
+			IPACMERR("Unable to get lock on file %s (my PID %d), PID %d already has it\n",
+					 IPACM_PID_FILE, getpid(), lock.l_pid);
+			close(fd);
+			exit(0);
+		}
 	}
 	else
 	{
-		IPACMDBG_H("Primary IPACM PID = %d\n",ipacm_pid);
-		fclose(fp);
-		if (0 == kill(ipacm_pid, 0)) /* Process exists */
-		{
-			/* check that process is IPACM */
-			memset(string, 0, IPA_MAX_FILE_LEN);
-			snprintf(string, IPA_MAX_FILE_LEN, "/proc/%d/cmdline", ipacm_pid);
-			IPACMDBG_H("open pid file %s \n",string);
-			fp = fopen(string, "r");
-			if ( fp == NULL )
-			{
-				IPACMDBG_H("open pid file failed \n");
-				return;
-			}
-			else if (fgets(string, IPA_MAX_FILE_LEN, fp) != NULL)
-			{
-				IPACMDBG_H("get pid process name (%s)\n",string);
-				if( strcmp(string, IPACM_NAME) == 0)
-				{
-					if(ipacm_pid != getpid())
-					{
-						IPACMDBG_H("found IPACM already in PID (%d), new PID(%d) exit(0)\n",ipacm_pid, getpid());
-			exit(0);
-		}
-					IPACMDBG_H("same IPACM PID(%d) is running\n", getpid());
-				}
-			}
-			fclose(fp);
-		}
+		IPACMERR("PID %d is IPACM main process\n", getpid());
 	}
-	ipacm_pid = getpid();
-	fp = fopen(IPACM_PID_FILE, "w");
-	if ( fp != NULL )
-	{
-		IPACMDBG_H(" IPACM current PID: %d \n",ipacm_pid);
-		fprintf(fp, "%d", ipacm_pid);
-		fclose(fp);
-	}
+
 	return;
 }
 
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 5cbcc4c..8c23025 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -48,6 +48,8 @@
 #include <IPACM_Wan.h>
 #include <IPACM_Lan.h>
 #include <IPACM_IfaceManager.h>
+#include <IPACM_ConntrackListener.h>
+
 
 /* static member to store the number of total wifi clients within all APs*/
 int IPACM_Wlan::total_num_wifi_clients = 0;
@@ -496,7 +498,9 @@
 				handle_wlan_client_route_rule(data->mac_addr, data->iptype);
 				if (data->iptype == IPA_IP_v4)
 				{
-					Nat_App->ResetPwrSaveIf(data->ipv4_addr);
+					/* Add NAT rules after ipv4 RT rules are set */
+					CtList->HandleNeighIpAddrAddEvt(data);
+//					Nat_App->ResetPwrSaveIf(data->ipv4_addr);
 				}
 			}
 		}
@@ -1407,6 +1411,8 @@
 			   else
 			   {
 			     IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
+				 /* delete NAT rules first */
+				 CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, clnt_indx)->v4_addr);
 			     delete_default_qos_rtrules(clnt_indx,IPA_IP_v4);
 		         get_client_memptr(wlan_client, clnt_indx)->route_rule_set_v4 = false;
 			     get_client_memptr(wlan_client, clnt_indx)->v4_addr = data->ipv4_addr;
@@ -1721,19 +1727,19 @@
 	/* First reset nat rules and then route rules */
 	if(get_client_memptr(wlan_client, clt_indx)->ipv4_set == true)
 	{
-	        IPACMDBG_H("Deleting Nat Rules\n");
-	        Nat_App->UpdatePwrSaveIf(get_client_memptr(wlan_client, clt_indx)->v4_addr);
+	        IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wlan_client, clt_indx)->v4_addr);
+			CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, clt_indx)->v4_addr);
  	}
 
 	if (delete_default_qos_rtrules(clt_indx, IPA_IP_v4))
 	{
-		IPACMERR("unbale to delete v4 default qos route rules\n");
+		IPACMERR("unbale to delete v4 default qos route rules for index: %d\n", clt_indx);
 		return IPACM_FAILURE;
 	}
 
 	if (delete_default_qos_rtrules(clt_indx, IPA_IP_v6))
 	{
-		IPACMERR("unbale to delete v6 default qos route rules\n");
+		IPACMERR("unbale to delete v6 default qos route rules for indexn: %d\n", clt_indx);
 		return IPACM_FAILURE;
 	}
 
@@ -1996,8 +2002,26 @@
 
 	for (i = 0; i < num_wifi_client; i++)
 	{
-		delete_default_qos_rtrules(i, IPA_IP_v4);
-		delete_default_qos_rtrules(i, IPA_IP_v6);
+		/* First reset nat rules and then route rules */
+		if(get_client_memptr(wlan_client, i)->ipv4_set == true)
+		{
+	        IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wlan_client, i)->v4_addr);
+			CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, i)->v4_addr);
+		}
+
+		if (delete_default_qos_rtrules(i, IPA_IP_v4))
+		{
+			IPACMERR("unbale to delete v4 default qos route rules for index: %d\n", i);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+
+		if (delete_default_qos_rtrules(i, IPA_IP_v6))
+		{
+			IPACMERR("unbale to delete v6 default qos route rules for index: %d\n", i);
+			res = IPACM_FAILURE;
+			goto fail;
+		}
 
 		IPACMDBG_H("Delete %d client header\n", num_wifi_client);