ipacm: cache framework event if IPACM not ready

When set_upstream/add_downstream events received from framework,
IPACM can't handle them if those events are coming earlier than
the new_address netlink event. The fix is to cache those framework
events in offload_manager if IPACM haven't got the netdev
ip-address.

Change-Id: I7826ada63fdc093632b06fba5b43c7a4cf101fb0
diff --git a/ipacm/inc/IPACM_Config.h b/ipacm/inc/IPACM_Config.h
index a9524f6..ec15b30 100644
--- a/ipacm/inc/IPACM_Config.h
+++ b/ipacm/inc/IPACM_Config.h
@@ -47,6 +47,8 @@
 typedef struct
 {
   char iface_name[IPA_IFACE_NAME_LEN];
+  bool v4_up;
+  bool v6_up;
 }NatIfaces;
 
 /* for IPACM rm dependency use*/
@@ -230,11 +232,11 @@
 
 	void DelRmDepend(ipa_rm_resource_name rm1);
 
-	int AddNatIfaces(char *dev_name);
+	int AddNatIfaces(char *dev_name, ipa_ip_type ip_type);
 
 	int DelNatIfaces(char *dev_name);
 
-	int CheckNatIfaces(const char *dev_name);
+	int CheckNatIfaces(const char *dev_name, ipa_ip_type ip_type);
 
 	inline void SetQmapId(uint8_t id)
 	{
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
index babc847..ad0cdd3 100644
--- a/ipacm/src/IPACM_Config.cpp
+++ b/ipacm/src/IPACM_Config.cpp
@@ -467,7 +467,7 @@
 }
 
 
-int IPACM_Config::AddNatIfaces(char *dev_name)
+int IPACM_Config::AddNatIfaces(char *dev_name, ipa_ip_type ip_type)
 {
 	int i;
 	/* Check if this iface already in NAT-iface*/
@@ -477,7 +477,15 @@
 							 pNatIfaces[i].iface_name,
 							 sizeof(pNatIfaces[i].iface_name)) == 0)
 		{
-			IPACMDBG("Interface (%s) is add to nat iface already\n", dev_name);
+			IPACMDBG_H("Interface (%s) is add to nat iface already\n", dev_name);
+			if (ip_type == IPA_IP_v4) {
+				pNatIfaces[i].v4_up = true;
+				IPACMDBG_H("Change v4_up to (%d) \n", pNatIfaces[i].v4_up);
+			}
+			if (ip_type == IPA_IP_v6) {
+				pNatIfaces[i].v6_up = true;
+				IPACMDBG_H("Change v6_up to (%d) \n", pNatIfaces[i].v6_up);
+			}
 				return 0;
 		}
 	}
@@ -494,8 +502,15 @@
 		IPACMDBG_H("Add Nat IfaceName: %s ,update nat-ifaces number: %d\n",
 						 pNatIfaces[ipa_nat_iface_entries - 1].iface_name,
 						 ipa_nat_iface_entries);
+		if (ip_type == IPA_IP_v4) {
+			pNatIfaces[ipa_nat_iface_entries - 1].v4_up = true;
+			IPACMDBG_H("Change v4_up to (%d) \n", pNatIfaces[ipa_nat_iface_entries - 1].v4_up);
+		}
+		if (ip_type == IPA_IP_v6) {
+			pNatIfaces[ipa_nat_iface_entries - 1].v6_up = true;
+			IPACMDBG_H("Change v6_up to (%d) \n", pNatIfaces[ipa_nat_iface_entries - 1].v6_up);
+		}				 
 	}
-
 	return 0;
 }
 
@@ -514,14 +529,20 @@
 
 			/* Reset the matched entry */
 			memset(pNatIfaces[i].iface_name, 0, IPA_IFACE_NAME_LEN);
+			pNatIfaces[i].v4_up = false;
+			pNatIfaces[i].v6_up = false;
 
 			for (; i < ipa_nat_iface_entries - 1; i++)
 			{
 				memcpy(pNatIfaces[i].iface_name,
 							 pNatIfaces[i + 1].iface_name, IPA_IFACE_NAME_LEN);
+				pNatIfaces[i].v4_up = pNatIfaces[i + 1].v4_up;
+				pNatIfaces[i].v6_up = pNatIfaces[i + 1].v6_up;
 
 				/* Reset the copied entry */
 				memset(pNatIfaces[i + 1].iface_name, 0, IPA_IFACE_NAME_LEN);
+				pNatIfaces[i + 1].v4_up = false;
+				pNatIfaces[i + 1].v6_up = false;
 			}
 			ipa_nat_iface_entries--;
 			IPACMDBG_H("Update nat-ifaces number: %d\n", ipa_nat_iface_entries);
@@ -534,23 +555,33 @@
 	return 0;
 }
 
-int IPACM_Config::CheckNatIfaces(const char *dev_name)
+int IPACM_Config::CheckNatIfaces(const char *dev_name, ipa_ip_type ip_type)
 {
 	int i = 0;
-	IPACMDBG_H("Check iface %s from NAT-ifaces, currently it has %d nat ifaces\n",
-					 dev_name, ipa_nat_iface_entries);
+	IPACMDBG_H("Check iface %s for ip-type %d from NAT-ifaces, currently it has %d nat ifaces\n",
+					 dev_name, ip_type, ipa_nat_iface_entries);
 
 	for (i = 0; i < ipa_nat_iface_entries; i++)
 	{
 		if (strcmp(dev_name, pNatIfaces[i].iface_name) == 0)
 		{
-			IPACMDBG_H("Find Nat IfaceName: %s ,previous nat-ifaces number: %d\n",
-							 pNatIfaces[i].iface_name, ipa_nat_iface_entries);
+			IPACMDBG_H("Find Nat IfaceName: %s ,previous nat-ifaces number: %d, v4_up %d, v6_up %d \n",
+							 pNatIfaces[i].iface_name, ipa_nat_iface_entries, pNatIfaces[i].v4_up, pNatIfaces[i].v6_up);
+			if (ip_type == IPA_IP_v4 && pNatIfaces[i].v4_up == true)
+			{
+				IPACMDBG_H(" v4_up=%d\n", pNatIfaces[i].v4_up);
+				return 0;
+			}
+			if (ip_type == IPA_IP_v6 && pNatIfaces[i].v6_up == true)
+			{
+				IPACMDBG_H(" v6_up=%d\n", pNatIfaces[i].v6_up);
 			return 0;
 		}
+			return -1;
+		}
 	}
-	IPACMDBG_H("Can't find Nat IfaceName: %s with total nat-ifaces number: %d\n",
-					    dev_name, ipa_nat_iface_entries);
+	IPACMDBG_H("Can't find Nat IfaceName: %s for ip_type %d up with total nat-ifaces number: %d\n",
+					    dev_name, ip_type, ipa_nat_iface_entries);
 	return -1;
 }
 
diff --git a/ipacm/src/IPACM_Iface.cpp b/ipacm/src/IPACM_Iface.cpp
index 36e2141..e24f7d9 100644
--- a/ipacm/src/IPACM_Iface.cpp
+++ b/ipacm/src/IPACM_Iface.cpp
@@ -622,13 +622,6 @@
 		}
 	}
 
-	/* Add Natting iface to IPACM_Config if there is  Rx/Tx property */
-	if (rx_prop != NULL || tx_prop != NULL)
-	{
-		IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
-        IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
-	}
-
 	close(fd);
 	return res;
 }
@@ -937,6 +930,12 @@
 		}
 	}
 
+	/* Add Natting iface to IPACM_Config if there is  Rx/Tx property */
+	if (rx_prop != NULL || tx_prop != NULL)
+	{
+		IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING for ip-family %d \n", dev_name, iptype);
+		IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, iptype);
+	}
 
 fail:
 	free(m_pFilteringTable);
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 3c9cc72..a1d2ab6 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -261,7 +261,7 @@
 			if (rx_prop != NULL || tx_prop != NULL)
 			{
 				IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
-				IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
+				IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, IPA_IP_MAX);
 			}
 		}
 		break;
diff --git a/ipacm/src/IPACM_OffloadManager.cpp b/ipacm/src/IPACM_OffloadManager.cpp
index 777edb6..a42f919 100644
--- a/ipacm/src/IPACM_OffloadManager.cpp
+++ b/ipacm/src/IPACM_OffloadManager.cpp
@@ -196,6 +196,7 @@
 	int index;
 	ipacm_cmd_q_data evt;
 	ipacm_event_ipahal_stream *evt_data;
+	bool cache_need = false;
 
 	IPACMDBG_H("addDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
 
@@ -223,8 +224,13 @@
 		IPACMDBG_H("add iface(%s) to list\n", downstream_name);
 	}
 
-	/* check if downstream netdev driver finished its configuration on IPA-HW */
-	if (IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name))
+	/* check if upstream netdev driver finished its configuration on IPA-HW for ipv4 and ipv6 */
+	if (prefix.fam == V4 && IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name, IPA_IP_v4))
+		cache_need = true;
+	if (prefix.fam == V6 && IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name, IPA_IP_v6))
+		cache_need = true;
+
+	if (cache_need)
 	{
 		IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", downstream_name);
 		/* copy to the cache */
@@ -343,6 +349,7 @@
 {
 	int index;
 	RET result = SUCCESS;
+	bool cache_need = false;
 
 	/* if interface name is NULL, default route is removed */
 	if(upstream_name != NULL)
@@ -380,8 +387,13 @@
 			return FAIL_INPUT_CHECK;
 		}
 
-		/* check if downstream netdev driver finished its configuration on IPA-HW */
-		if (IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name))
+		/* check if upstream netdev driver finished its configuration on IPA-HW for ipv4 and ipv6 */
+		if (gw_addr_v4.fam == V4 && IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name, IPA_IP_v4))
+			cache_need = true;
+		if (gw_addr_v6.fam == V6 && IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name, IPA_IP_v6))
+			cache_need = true;
+
+		if (cache_need)
 		{
 			IPACMDBG_H("setUpstream name(%s) currently not support in ipa \n", upstream_name);
 			/* copy to the cache */
@@ -635,9 +647,15 @@
 	IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
 					evt_data_route->ipv6_addr_gw[0], evt_data_route->ipv6_addr_gw[1], evt_data_route->ipv6_addr_gw[2], evt_data_route->ipv6_addr_gw[3]);
 #endif
-	IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", evt_data_route->if_index,
+	if (event == WAN_UPSTREAM_ROUTE_ADD) {
+		IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", evt_data_route->if_index,
 			evt_data_route->if_index_tether, evt_data_route->iptype);
-
+	}
+	else if (event == WAN_UPSTREAM_ROUTE_DEL) {
+		IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL: fid(%d) tether_fid(%d) ip-type(%d)\n",
+				evt_data_route->if_index,
+				evt_data_route->if_index_tether, evt_data_route->iptype);
+	}
 	memset(&evt, 0, sizeof(evt));
 	evt.evt_data = (void*)evt_data_route;
 	evt.event = event;
@@ -700,7 +718,7 @@
 	stats.reset_stats = true;
 
 	if (ioctl(fd, WAN_IOC_RESET_TETHER_STATS, &stats) < 0) {
-        IPACMERR("IOCTL WAN_IOC_RESET_TETHER_STATS call failed: %s", strerror(errno));
+		IPACMERR("IOCTL WAN_IOC_RESET_TETHER_STATS call failed: %s", strerror(errno));
 		close(fd);
 		return FAIL_HARDWARE;
 	}
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index ffdbdae..87ecb6d 100644
--- a/ipacm/src/IPACM_Wan.cpp
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -509,12 +509,12 @@
 	}
 
 #ifdef FEATURE_IPACM_HAL
-	/* check if having pending add_downstream cache*/
+	/* check if having pending set_upstream 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);
+		IPACMDBG_H(" check iface %s if having set_upstream cache events\n", dev_name);
 		OffloadMng->search_framwork_cache(dev_name);
 	}
 #endif
@@ -3206,6 +3206,13 @@
 	}
 	install_wan_filtering_rule(false);
 
+	/* Add Natting iface to IPACM_Config if there is  Rx/Tx property */
+	if (rx_prop != NULL || tx_prop != NULL)
+	{
+		IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
+		IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, iptype);
+	}
+
 fail:
 	return res;
 }
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index ec93233..0669b80 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -870,7 +870,7 @@
 		if (rx_prop != NULL || tx_prop != NULL)
 		{
 			IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
-			IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
+			IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, IPA_IP_MAX);
 		}
 
 		if (m_is_guest_ap == true && (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == FULL))