Merge "IPACM: fix the cpe bootup crash issue"
diff --git a/ipacm/inc/IPACM_Conntrack_NATApp.h b/ipacm/inc/IPACM_Conntrack_NATApp.h
index 7c97225..1fb12bf 100644
--- a/ipacm/inc/IPACM_Conntrack_NATApp.h
+++ b/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -52,6 +52,7 @@
 	uint32_t target_ip;
 	uint16_t target_port;
 
+	uint16_t public_ip;
 	uint16_t public_port;
 
 	u_int8_t  protocol;
@@ -74,6 +75,7 @@
 	nat_table_entry *cache;
 	nat_table_entry temp[MAX_TEMP_ENTRIES];
 	uint32_t pub_ip_addr;
+	uint32_t pub_ip_addr_pre;
 	uint32_t nat_table_hdl;
 
 	int curCnt, max_entries;
@@ -118,6 +120,7 @@
 	void UpdateTcpUdpTo(uint32_t, int proto);
 
 	void AddTempEntry(const nat_table_entry *);
+	void CacheEntry(const nat_table_entry *);
 	void DeleteTempEntry(const nat_table_entry *);
 	void FlushTempEntries(uint32_t, bool);
 };
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
index d8fe726..9de5911 100644
--- a/ipacm/src/IPACM_ConntrackClient.cpp
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -113,19 +113,6 @@
 		goto IGNORE;
 	}
 
-	if(!CtList->isWanUp())
-	{
-#ifdef IPACM_DEBUG
-		IPACMDBG("Wan is not up, ignoring below connections\n");
-		char buf[1024];
-		nfct_snprintf(buf, sizeof(buf), ct,
-									type, NFCT_O_PLAIN, NFCT_OF_TIME);
-		IPACMDBG("%s\n", buf);
-		IPACMDBG("\n");
-		ParseCTMessage(ct);
-#endif
-		goto IGNORE;
-	}
 #endif
 
 	ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index e00f921..9e66a00 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -213,6 +213,7 @@
 				if(nat_iface_ipv4_addr[j] == 0)
 				{
 					nat_iface_ipv4_addr[j] = data->ipv4_addr;
+					nat_inst->ResetPwrSaveIf(data->ipv4_addr);
 					nat_inst->FlushTempEntries(data->ipv4_addr, true);
 					break;
 				}
@@ -702,11 +703,13 @@
 		 {
 			 IPACMDBG("orig src ip:0x%x equal to wan ip\n",orig_src_ip);
 			 status = IPS_SRC_NAT;
+			 rule.public_ip = wan_ipaddr;
 		 }
 		 else if(orig_dst_ip == wan_ipaddr)
 		 {
 			 IPACMDBG("orig Dst IP:0x%x equal to wan ip\n",orig_dst_ip);
 			 status = IPS_DST_NAT;
+	 	 	 rule.public_ip = wan_ipaddr;
 		 }
 		 else
 		 {
@@ -933,7 +936,12 @@
 			if(TCP_CONNTRACK_ESTABLISHED == tcp_state)
 			{
 				 IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED(%d)\n", tcp_state);
-				 if(isTempEntry)
+				 if(!CtList->isWanUp())
+				 {
+				 	 IPACMDBG("Wan is not up, cache connections\n");
+					 nat_inst->CacheEntry(&rule);
+				 }
+				 else if(isTempEntry)
 				 {
 					 nat_inst->AddTempEntry(&rule);
 				 }
@@ -973,7 +981,12 @@
 			if(NFCT_T_NEW == type)
 			{
 				 IPACMDBG("New UDP connection at time %ld\n", time(NULL));
-				 if(isTempEntry)
+				 if(!CtList->isWanUp())
+				 {
+				 	 IPACMDBG("Wan is not up, cache connections\n");
+					 nat_inst->CacheEntry(&rule);
+				 }
+				 else if(isTempEntry)
 				 {
 					 nat_inst->AddTempEntry(&rule);
 				 }
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
index c4a7e52..0915fda 100644
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -129,8 +129,19 @@
 int NatApp::AddTable(uint32_t pub_ip)
 {
 	int ret;
+	int cnt = 0;
+	ipa_nat_ipv4_rule nat_rule;
 	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
 
+	/* Not reset the cache wait it timeout by destroy event */
+#if 0
+	if (pub_ip != pub_ip_addr_pre)
+	{
+		IPACMDBG("Reset the cache because NAT-ipv4 different\n");
+		memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+		curCnt = 0;
+	}
+#endif
 	ret = ipa_nat_add_ipv4_tbl(pub_ip, max_entries, &nat_table_hdl);
 	if(ret)
 	{
@@ -138,17 +149,56 @@
 		return ret;
 	}
 
+	/* Add back the cashed NAT-entry */
+	if (pub_ip == pub_ip_addr_pre)
+	{
+		IPACMDBG("Restore the cache to ipa NAT-table\n");
+		for(cnt = 0; cnt < max_entries; cnt++)
+		{
+			if(cache[cnt].private_ip !=0)
+			{
+				memset(&nat_rule, 0 , sizeof(nat_rule));
+				nat_rule.private_ip = cache[cnt].private_ip;
+				nat_rule.target_ip = cache[cnt].target_ip;
+				nat_rule.target_port = cache[cnt].target_port;
+				nat_rule.private_port = cache[cnt].private_port;
+				nat_rule.public_port = cache[cnt].public_port;
+				nat_rule.protocol = cache[cnt].protocol;
+
+				if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+				{
+					IPACMERR("unable to add the rule delete from cache\n");
+					memset(&cache[cnt], 0, sizeof(cache[cnt]));
+					curCnt--;
+					continue;
+				}
+				cache[cnt].enabled = true;
+
+				IPACMDBG("On wan-iface reset added below rule successfully\n");
+				iptodot("Private IP", nat_rule.private_ip);
+				iptodot("Target IP", nat_rule.target_ip);
+				IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
+				IPACMDBG("Public Port:%d\n", nat_rule.public_port);
+				IPACMDBG("protocol: %d\n", nat_rule.protocol);
+			}
+		}
+	}
+
 	pub_ip_addr = pub_ip;
 	return 0;
 }
 
 void NatApp::Reset()
 {
-	memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+	int cnt = 0;
 
 	nat_table_hdl = 0;
 	pub_ip_addr = 0;
-	curCnt = 0;
+	/* NAT tbl deleted, reset enabled bit */
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		cache[cnt].enabled ==false;
+	}
 }
 
 int NatApp::DeleteTable(uint32_t pub_ip)
@@ -172,6 +222,7 @@
 		return ret;
 	}
 
+	pub_ip_addr_pre = pub_ip_addr;
 	Reset();
 	return 0;
 }
@@ -208,9 +259,7 @@
 	int cnt = 0;
 	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
 
-	CHK_TBL_HDL();
-
-  IPACMDBG("Received below nat entry for deletion\n");
+	IPACMDBG("Received below nat entry for deletion\n");
 	iptodot("Private IP", rule->private_ip);
 	iptodot("Target IP", rule->target_ip);
 	IPACMDBG("Private Port: %d\t Target Port: %d\t", rule->private_port, rule->target_port);
@@ -229,8 +278,7 @@
 			{
 				if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
 				{
-					IPACMERR("%s() %d\n", __FUNCTION__, __LINE__);
-					return -1;
+					IPACMERR("%s() %d deletion failed\n", __FUNCTION__, __LINE__);
 				}
 
 				IPACMDBG("Deleted Nat entry(%d) Successfully\n", cnt);
@@ -525,7 +573,6 @@
 		}
 	}
 
-	CHK_TBL_HDL();
 
 	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
 	{
@@ -579,6 +626,8 @@
 
 	for(cnt = 0; cnt < max_entries; cnt++)
 	{
+		IPACMDBG("cache (%d): enable %d, ip 0x%x\n", cnt, cache[cnt].enabled, cache[cnt].private_ip);
+
 		if(cache[cnt].private_ip == client_lan_ip &&
 			 cache[cnt].enabled == false)
 		{
@@ -704,11 +753,14 @@
 		{
 			if(isAdd)
 			{
-				ret = AddEntry(&temp[cnt]);
-				if(ret)
+				if(temp[cnt].public_ip == pub_ip_addr)
 				{
-					IPACMERR("unable to add temp entry: %d\n", ret);
-					continue;
+					ret = AddEntry(&temp[cnt]);
+					if(ret)
+					{
+						IPACMERR("unable to add temp entry: %d\n", ret);
+						continue;
+					}
 				}
 			}
 			memset(&temp[cnt], 0, sizeof(nat_table_entry));
@@ -729,7 +781,6 @@
 		return -1;
 	}
 
-	CHK_TBL_HDL();
 
   for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
   {
@@ -741,27 +792,28 @@
     }
   }
 
-	for(cnt = 0; cnt < max_entries; cnt++)
+  for(cnt = 0; cnt < max_entries; cnt++)
+  {
+	if(cache[cnt].private_ip == ip_addr)
 	{
-		if(cache[cnt].private_ip == ip_addr)
-		{
-
-      if(cache[cnt].enabled == true)
-      {
+		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--;
-		}
+			else
+			{
+				IPACMDBG("won't delete the rule\n");
+				cache[cnt].enabled = false;
+		        }
+	        }
+		IPACMDBG("won't delete the rule for entry %d, enabled %d\n",cnt, cache[cnt].enabled);
 	}
-
+  }
   IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
-	return 0;
+  return 0;
 }
 
 int NatApp::DelEntriesOnSTAClntDiscon(uint32_t ip_addr)
@@ -775,7 +827,6 @@
 		return -1;
 	}
 
-	CHK_TBL_HDL();
 
 	for(cnt = 0; cnt < max_entries; cnt++)
 	{
@@ -798,3 +849,61 @@
 	IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
 	return 0;
 }
+
+void NatApp::CacheEntry(const nat_table_entry *rule)
+{
+	int cnt;
+	if(rule->private_ip == 0 ||
+		 rule->target_ip == 0 ||
+		 rule->private_port == 0  ||
+		 rule->target_port == 0 ||
+		 rule->protocol == 0)
+	{
+		IPACMERR("Invalid Connection, ignoring it\n");
+		return;
+	}
+
+	if(!ChkForDup(rule))
+	{
+		for(; cnt < max_entries; cnt++)
+		{
+			if(cache[cnt].private_ip == 0 &&
+				 cache[cnt].target_ip == 0 &&
+				 cache[cnt].private_port == 0  &&
+				 cache[cnt].target_port == 0 &&
+				 cache[cnt].protocol == 0)
+			{
+				break;
+			}
+		}
+
+		if(max_entries == cnt)
+		{
+			IPACMERR("Error: Unable to add, reached maximum rules\n");
+			return;
+		}
+		else
+		{
+			cache[cnt].enabled = false;
+			cache[cnt].rule_hdl = 0;
+			cache[cnt].private_ip = rule->private_ip;
+			cache[cnt].target_ip = rule->target_ip;
+			cache[cnt].target_port = rule->target_port;
+			cache[cnt].private_port = rule->private_port;
+			cache[cnt].protocol = rule->protocol;
+			cache[cnt].timestamp = 0;
+			cache[cnt].public_port = rule->public_port;
+			cache[cnt].dst_nat = rule->dst_nat;
+			curCnt++;
+		}
+
+	}
+	else
+	{
+		IPACMERR("Duplicate rule. Ignore it\n");
+		return;
+	}
+
+	IPACMDBG("Cached rule(%d) successfully\n", cnt);
+	return;
+}