ipacm: buffer downstream and upstream events am: 86a1a35809
am: c98e58f560

Change-Id: Ice0f7e96b3934ffa68746d2117ca900f1187460c
diff --git a/msm8998/ipacm/inc/IPACM_OffloadManager.h b/msm8998/ipacm/inc/IPACM_OffloadManager.h
index 85a2063..9d94253 100644
--- a/msm8998/ipacm/inc/IPACM_OffloadManager.h
+++ b/msm8998/ipacm/inc/IPACM_OffloadManager.h
@@ -43,7 +43,17 @@
 //using UDP = ::IOffloadManager::ConntrackTimeoutUpdater::UDP;
 //using TCP = ::IOffloadManager::ConntrackTimeoutUpdater::TCP;
 
+#define MAX_EVENT_CACHE  10
 
+typedef struct _framework_event_cache
+{
+	/* IPACM interface name */
+	ipa_cm_event_id event;
+	char dev_name[IF_NAME_LEN];
+	Prefix prefix_cache;
+	Prefix prefix_cache_v6; //for setupstream use
+	bool valid;
+}framework_event_cache;
 
 class IPACM_OffloadManager : public IOffloadManager
 {
@@ -82,6 +92,8 @@
 
 	ConntrackTimeoutUpdater *touInstance;
 
+	bool search_framwork_cache(char * interface_name);
+
 private:
 
 	bool upstream_v4_up;
@@ -98,6 +110,12 @@
 
 	static const char *DEVICE_NAME;
 
+	/* cache the add_downstream events if netdev is not ready */
+	framework_event_cache event_cache[MAX_EVENT_CACHE];
+
+	/* latest update cache entry */
+	int latest_cache_index;
+
 }; /* IPACM_OffloadManager */
 
 #endif /* _IPACM_OFFLOAD_MANAGER_H_ */
diff --git a/msm8998/ipacm/src/IPACM_Conntrack_NATApp.cpp b/msm8998/ipacm/src/IPACM_Conntrack_NATApp.cpp
index a22a026..f6dda67 100644
--- a/msm8998/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/msm8998/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -976,8 +976,13 @@
 }
 
 void NatApp::Read_TcpUdp_Timeout(void) {
+#ifdef FEATURE_IPACM_HAL
+	tcp_timeout = 432000;
+	udp_timeout = 180;
+	IPACMDBG_H("udp timeout value: %d\n", udp_timeout);
+	IPACMDBG_H("tcp timeout value: %d\n", tcp_timeout);
+#else
 	FILE *udp_fd = NULL, *tcp_fd = NULL;
-
 	/* Read UDP timeout value */
 	udp_fd = fopen(IPACM_UDP_FULL_FILE_NAME, "r");
 	if (udp_fd == NULL) {
@@ -1011,6 +1016,6 @@
 	if (tcp_fd) {
 		fclose(tcp_fd);
 	}
-
+#endif
 	return;
 }
diff --git a/msm8998/ipacm/src/IPACM_Lan.cpp b/msm8998/ipacm/src/IPACM_Lan.cpp
index 5a8f0e6..cd0ff99 100644
--- a/msm8998/ipacm/src/IPACM_Lan.cpp
+++ b/msm8998/ipacm/src/IPACM_Lan.cpp
@@ -52,7 +52,9 @@
 #include "IPACM_ConntrackListener.h"
 #include <sys/ioctl.h>
 #include <fcntl.h>
-
+#ifdef FEATURE_IPACM_HAL
+#include "IPACM_OffloadManager.h"
+#endif
 bool IPACM_Lan::odu_up = false;
 
 IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index)
@@ -1055,7 +1057,7 @@
 		return IPACM_FAILURE;
 	}
 
-	if(is_sta_mode == false && modem_ul_v4_set == true) //sky
+	if(is_sta_mode == false && modem_ul_v4_set == true)
 	{
 		if (num_wan_ul_fl_rule_v4 > MAX_WAN_UL_FILTER_RULES)
 		{
@@ -1122,6 +1124,9 @@
 	const int NUM_RULES = 1;
 	uint32_t num_ipv6_addr;
 	int res = IPACM_SUCCESS;
+#ifdef FEATURE_IPACM_HAL
+	IPACM_OffloadManager* OffloadMng;
+#endif
 
 	IPACMDBG_H("set route/filter rule ip-type: %d \n", data->iptype);
 
@@ -1287,6 +1292,17 @@
 		IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
 	}
 
+#ifdef FEATURE_IPACM_HAL
+	/* check if having pending add_downstream cache*/
+	OffloadMng = IPACM_OffloadManager::GetInstance();
+	if (OffloadMng == NULL) {
+		IPACMERR("failed to get IPACM_OffloadManager instance !\n");
+	} else {
+		IPACMDBG_H(" check iface %s if having add_downstream cache events\n", dev_name);
+		OffloadMng->search_framwork_cache(dev_name);
+	}
+#endif
+
 	IPACMDBG_H("finish route/filter rule ip-type: %d, res(%d)\n", data->iptype, res);
 
 fail:
diff --git a/msm8998/ipacm/src/IPACM_OffloadManager.cpp b/msm8998/ipacm/src/IPACM_OffloadManager.cpp
index 3679669..f2cc16c 100644
--- a/msm8998/ipacm/src/IPACM_OffloadManager.cpp
+++ b/msm8998/ipacm/src/IPACM_OffloadManager.cpp
@@ -57,16 +57,20 @@
 	default_gw_index = INVALID_IFACE;
 	upstream_v4_up = false;
 	upstream_v6_up = false;
+	memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache));
+	latest_cache_index = 0;
 	return ;
 }
 
 RET IPACM_OffloadManager::registerEventListener(IpaEventListener* eventlistener)
 {
 	RET result = SUCCESS;
-	if (elrInstance == NULL)
+	if (elrInstance == NULL) {
+		IPACMDBG_H("get registerEventListener \n");
 		elrInstance = eventlistener;
-	else {
-		IPACMDBG_H("already register EventListener previously \n");
+	} else {
+		IPACMDBG_H("already have EventListener previously, override \n");
+		elrInstance = eventlistener;
 		result = FAIL_INPUT_CHECK;
 	}
 	return SUCCESS;
@@ -88,9 +92,12 @@
 {
 	RET result = SUCCESS;
 	if (touInstance == NULL)
+	{
+		IPACMDBG_H("get ConntrackTimeoutUpdater \n");
 		touInstance = timeoutupdater;
-	else {
-		IPACMDBG_H("already register ConntrackTimeoutUpdater previously \n");
+	} else {
+		IPACMDBG_H("already have ConntrackTimeoutUpdater previously, override \n");
+		touInstance = timeoutupdater;
 		result = FAIL_INPUT_CHECK;
 	}
 	return SUCCESS;
@@ -112,6 +119,8 @@
 {
 	IPACM_ConntrackClient *cc;
 	int on = 1, rel;
+	struct sockaddr_nl	local;
+	unsigned int addr_len;
 
 	cc = IPACM_ConntrackClient::GetInstance();
 
@@ -121,6 +130,12 @@
 		return FAIL_HARDWARE;
 	}
 
+	/* check socket name */
+	memset(&local, 0, sizeof(struct sockaddr_nl));
+	addr_len = sizeof(local);
+	getsockname(fd, (struct sockaddr *)&local, &addr_len);
+	IPACMDBG_H(" FD %d, nl_pad %d nl_pid %u\n", fd, local.nl_pad, local.nl_pid);
+
 	/* 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);
@@ -182,13 +197,6 @@
 
 	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 {
@@ -198,11 +206,62 @@
 							prefix.v6Mask[0], prefix.v6Mask[1], prefix.v6Mask[2], prefix.v6Mask[3]);
 	}
 
+	/* check if netdev valid on device */
 	if(ipa_get_if_index(downstream_name, &index))
 	{
 		IPACMERR("fail to get iface index.\n");
+		return FAIL_INPUT_CHECK;
+	}
+
+	/* check if downstream netdev driver finished its configuration on IPA-HW */
+	if (IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name))
+	{
+		IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", downstream_name);
+		/* copy to the cache */
+		for(int i = 0; i < MAX_EVENT_CACHE ;i++)
+		{
+			if(event_cache[latest_cache_index].valid == false)
+			{
+				//do the copy
+				event_cache[latest_cache_index].valid = true;
+				event_cache[latest_cache_index].event = IPA_DOWNSTREAM_ADD;
+				memcpy(event_cache[latest_cache_index].dev_name, downstream_name, sizeof(event_cache[latest_cache_index].dev_name));
+				memcpy(&event_cache[latest_cache_index].prefix_cache, &prefix, sizeof(event_cache[latest_cache_index].prefix_cache));
+				if (prefix.fam == V4) {
+					IPACMDBG_H("cache event(%d) subnet info v4Addr (%x) v4Mask (%x) dev(%s) on entry (%d)\n",
+						event_cache[latest_cache_index].event,
+						event_cache[latest_cache_index].prefix_cache.v4Addr,
+						event_cache[latest_cache_index].prefix_cache.v4Mask,
+						event_cache[latest_cache_index].dev_name,
+						latest_cache_index);
+				} else {
+					IPACMDBG_H("cache event (%d) v6Addr: %08x:%08x:%08x:%08x \n",
+						event_cache[latest_cache_index].event,
+						event_cache[latest_cache_index].prefix_cache.v6Addr[0],
+						event_cache[latest_cache_index].prefix_cache.v6Addr[1],
+						event_cache[latest_cache_index].prefix_cache.v6Addr[2],
+						event_cache[latest_cache_index].prefix_cache.v6Addr[3]);
+					IPACMDBG_H("subnet v6Mask: %08x:%08x:%08x:%08x dev(%s) on entry(%d), \n",
+						event_cache[latest_cache_index].prefix_cache.v6Mask[0],
+						event_cache[latest_cache_index].prefix_cache.v6Mask[1],
+						event_cache[latest_cache_index].prefix_cache.v6Mask[2],
+						event_cache[latest_cache_index].prefix_cache.v6Mask[3],
+						event_cache[latest_cache_index].dev_name,
+						latest_cache_index);
+				}
+				latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
+				break;
+			}
+			latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
+			if(i == MAX_EVENT_CACHE - 1)
+			{
+				IPACMDBG_H(" run out of event cache (%d)\n", i);
 		return FAIL_HARDWARE;
 	}
+		}
+
+		return SUCCESS;
+	}
 
 	evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
 	if(evt_data == NULL)
@@ -287,20 +346,60 @@
 	}
 	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;
-		}
-
+		/* check if netdev valid on device */
 		if(ipa_get_if_index(upstream_name, &index))
 		{
 			IPACMERR("fail to get iface index.\n");
 			return FAIL_INPUT_CHECK;
 		}
 
+		/* check if downstream netdev driver finished its configuration on IPA-HW */
+		if (IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name))
+		{
+			IPACMDBG_H("setUpstream name(%s) currently not support in ipa \n", upstream_name);
+			/* copy to the cache */
+			for(int i = 0; i < MAX_EVENT_CACHE ;i++)
+			{
+				if(event_cache[latest_cache_index].valid == false)
+				{
+					//do the copy
+					event_cache[latest_cache_index].valid = true;
+					event_cache[latest_cache_index].event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT;
+					memcpy(event_cache[latest_cache_index].dev_name, upstream_name, sizeof(event_cache[latest_cache_index].dev_name));
+					memcpy(&event_cache[latest_cache_index].prefix_cache, &gw_addr_v4, sizeof(event_cache[latest_cache_index].prefix_cache));
+					memcpy(&event_cache[latest_cache_index].prefix_cache_v6, &gw_addr_v6, sizeof(event_cache[latest_cache_index].prefix_cache_v6));
+					if (gw_addr_v4.fam == V4) {
+						IPACMDBG_H("cache event(%d) ipv4 fateway: (%x) dev(%s) on entry (%d)\n",
+							event_cache[latest_cache_index].event,
+							event_cache[latest_cache_index].prefix_cache.v4Addr,
+							event_cache[latest_cache_index].dev_name,
+							latest_cache_index);
+		}
+
+					if (gw_addr_v6.fam == V6)
+		{
+						IPACMDBG_H("cache event (%d) ipv6 gateway: %08x:%08x:%08x:%08x dev(%s) on entry(%d)\n",
+							event_cache[latest_cache_index].event,
+							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[0],
+							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[1],
+							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[2],
+							event_cache[latest_cache_index].prefix_cache_v6.v6Addr[3],
+							event_cache[latest_cache_index].dev_name,
+							latest_cache_index);
+					}
+					latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
+					break;
+				}
+				latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
+				if(i == MAX_EVENT_CACHE - 1)
+				{
+					IPACMDBG_H(" run out of event cache (%d) \n", i);
+					return FAIL_HARDWARE;
+				}
+			}
+			return SUCCESS;
+		}
+
 		/* reset the stats when switch from LTE->STA */
 		if (index != default_gw_index) {
 			IPACMDBG_H(" interface switched to %s\n", upstream_name);
@@ -557,3 +656,36 @@
 
 	return pInstance;
 }
+
+bool IPACM_OffloadManager::search_framwork_cache(char * interface_name)
+{
+	bool rel = false;
+
+	/* IPACM needs to kee old FDs, can't clear */
+	IPACMDBG_H("check netdev(%s)\n", interface_name);
+
+	for(int i = 0; i < MAX_EVENT_CACHE ;i++)
+	{
+		if(event_cache[i].valid == true)
+		{
+			//do the compare
+			if (strncmp(event_cache[i].dev_name,
+					interface_name,
+					sizeof(event_cache[i].dev_name)) == 0)
+			{
+				IPACMDBG_H("found netdev (%s) in entry (%d) with event (%d)\n", interface_name, i, event_cache[i].event);
+				/* post event again */
+				if (event_cache[i].event == IPA_DOWNSTREAM_ADD)
+					addDownstream(interface_name, event_cache[i].prefix_cache);
+				else if (event_cache[i].event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT)
+					setUpstream(interface_name, event_cache[i].prefix_cache, event_cache[i].prefix_cache_v6);
+				else
+					IPACMERR("wrong event cached (%d)", event_cache[i].event);
+				event_cache[i].valid = false;
+				rel = true;
+			}
+		}
+	}
+	IPACMDBG_H(" not found netdev (%s) has cached event\n", interface_name);
+	return rel;
+}
diff --git a/msm8998/ipacm/src/IPACM_Wan.cpp b/msm8998/ipacm/src/IPACM_Wan.cpp
index 968f562..2df9d80 100644
--- a/msm8998/ipacm/src/IPACM_Wan.cpp
+++ b/msm8998/ipacm/src/IPACM_Wan.cpp
@@ -50,6 +50,9 @@
 #include "IPACM_Defs.h"
 #include <IPACM_ConntrackListener.h>
 #include "linux/ipa_qmi_service_v01.h"
+#ifdef FEATURE_IPACM_HAL
+#include "IPACM_OffloadManager.h"
+#endif
 
 bool IPACM_Wan::wan_up = false;
 bool IPACM_Wan::wan_up_v6 = false;
@@ -203,6 +206,9 @@
 	const int NUM_RULES = 1;
 	uint32_t num_ipv6_addr;
 	int res = IPACM_SUCCESS,len;
+#ifdef FEATURE_IPACM_HAL
+	IPACM_OffloadManager* OffloadMng;
+#endif
 
 	memset(&hdr, 0, sizeof(hdr));
 	if(tx_prop == NULL || rx_prop == NULL)
@@ -502,6 +508,16 @@
 		IPACMDBG_H("Receved wan ipv4-addr:0x%x\n",wan_v4_addr);
 	}
 
+#ifdef FEATURE_IPACM_HAL
+	/* check if having pending add_downstream cache*/
+	OffloadMng = IPACM_OffloadManager::GetInstance();
+	if (OffloadMng == NULL) {
+		IPACMERR("failed to get IPACM_OffloadManager instance !\n");
+	} else {
+		IPACMDBG_H(" check iface %s if having add_downstream cache events\n", dev_name);
+		OffloadMng->search_framwork_cache(dev_name);
+	}
+#endif
 	IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
 
 fail: