Merge "IPACM: add wlan2 and wlan3 in xml file"
diff --git a/ipacm/inc/IPACM_Config.h b/ipacm/inc/IPACM_Config.h
index 8d054a0..5bcb4eb 100644
--- a/ipacm/inc/IPACM_Config.h
+++ b/ipacm/inc/IPACM_Config.h
@@ -115,6 +115,8 @@
 
 	bool ipacm_odu_embms_enable;
 
+	bool ipacm_ip_passthrough_mode;
+
 	int ipa_nat_iface_entries;
 
 	/* Store the total number of wlan guest ap configured */
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
index 0076a01..6c54f5e 100644
--- a/ipacm/inc/IPACM_Lan.h
+++ b/ipacm/inc/IPACM_Lan.h
@@ -222,6 +222,8 @@
 
 	uint32_t if_ipv4_subnet;
 
+	uint32_t ipv6_prefix[2];
+
 private:
 
 	/* get hdr proc ctx type given source and destination l2 hdr type */
diff --git a/ipacm/inc/IPACM_Routing.h b/ipacm/inc/IPACM_Routing.h
index 4f5488f..b5ffabc 100644
--- a/ipacm/inc/IPACM_Routing.h
+++ b/ipacm/inc/IPACM_Routing.h
@@ -61,7 +61,6 @@
 	bool Reset(enum ipa_ip_type ip);
 
 	bool GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable);
-	bool PutRoutingTable(uint32_t routingTableHandle);
 
 	bool DeviceNodeIsOpened();
 	bool DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip);
@@ -71,6 +70,8 @@
 private:
 	static const char *DEVICE_NAME;
 	int m_fd; /* File descriptor of the IPA device node /dev/ipa */
+
+	bool PutRoutingTable(uint32_t routingTableHandle);
 };
 
 #endif //IPACM_ROUTING_H
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
index b4bf50e..e42358f 100644
--- a/ipacm/inc/IPACM_Wan.h
+++ b/ipacm/inc/IPACM_Wan.h
@@ -97,6 +97,7 @@
 	static uint8_t xlat_mux_id;
 	/* IPACM interface name */
 	static char wan_up_dev_name[IF_NAME_LEN];
+	static uint32_t curr_wan_ip;
 	IPACM_Wan(int, ipacm_wan_iface_type, uint8_t *);
 	virtual ~IPACM_Wan();
 
@@ -140,6 +141,11 @@
 #endif
 	}
 
+	static uint32_t getWANIP()
+	{
+		return curr_wan_ip;
+	}
+
 	static bool getXlat_Mux_Id()
 	{
 		return xlat_mux_id;
diff --git a/ipacm/inc/IPACM_Xml.h b/ipacm/inc/IPACM_Xml.h
index f645ae1..64c00ed 100644
--- a/ipacm/inc/IPACM_Xml.h
+++ b/ipacm/inc/IPACM_Xml.h
@@ -178,6 +178,9 @@
 #define IPACMNat_TAG                         "IPACMNAT"
 #define NAT_MaxEntries_TAG                   "MaxNatEntries"
 
+#define IP_PassthroughFlag_TAG               "IPPassthroughFlag"
+#define IP_PassthroughMode_TAG               "IPPassthroughMode"
+
 /*---------------------------------------------------------------------------
       IP protocol numbers - use in dss_socket() to identify protocols.
       Also contains the extension header types for IPv6.
@@ -276,6 +279,7 @@
 	bool router_mode_enable;
 	bool odu_embms_enable;
 	int num_wlan_guest_ap;
+	bool ip_passthrough_mode;
 } IPACM_conf_t;  
 
 /* This function read IPACM XML configuration*/
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
index cb1d826..d8c4227 100644
--- a/ipacm/src/IPACM_Config.cpp
+++ b/ipacm/src/IPACM_Config.cpp
@@ -112,6 +112,7 @@
 {
 	iface_table = NULL;
 	alg_table = NULL;
+	pNatIfaces = NULL;
 	memset(&ipa_client_rm_map_tbl, 0, sizeof(ipa_client_rm_map_tbl));
 	memset(&ipa_rm_tbl, 0, sizeof(ipa_rm_tbl));
 	ipa_rm_a2_check=0;
@@ -222,7 +223,7 @@
 		/* copy bridge interface name to ipacmcfg */
 		if( iface_table[i].if_cat == VIRTUAL_IF)
 		{
-			memcpy(ipa_virtual_iface_name, iface_table[i].iface_name, sizeof(ipa_virtual_iface_name));
+			strlcpy(ipa_virtual_iface_name, iface_table[i].iface_name, sizeof(ipa_virtual_iface_name));
 			IPACMDBG_H("ipa_virtual_iface_name(%s) \n", ipa_virtual_iface_name);
 		}
 	}
@@ -286,6 +287,10 @@
 	IPACMDBG_H("ipacm_odu_enable %d\n", ipacm_odu_enable);
 	IPACMDBG_H("ipacm_odu_mode %d\n", ipacm_odu_router_mode);
 	IPACMDBG_H("ipacm_odu_embms_enable %d\n", ipacm_odu_embms_enable);
+
+	ipacm_ip_passthrough_mode = cfg->ip_passthrough_mode;
+	IPACMDBG_H("ipacm_ip_passthrough_mode %d. \n", ipacm_ip_passthrough_mode);
+
 	ipa_num_wlan_guest_ap = cfg->num_wlan_guest_ap;
 	IPACMDBG_H("ipa_num_wlan_guest_ap %d\n",ipa_num_wlan_guest_ap);
 
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index 33023cb..38ab7da 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -33,6 +33,8 @@
 #include "IPACM_ConntrackListener.h"
 #include "IPACM_ConntrackClient.h"
 #include "IPACM_EvtDispatcher.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Wan.h"
 
 IPACM_ConntrackListener::IPACM_ConntrackListener()
 {
@@ -210,30 +212,11 @@
 					pNatIfaces[i].iface_name,
 					sizeof(pNatIfaces[i].iface_name)) == 0)
 		{
-			/* copy the ipv4 address to filter out downlink connections
-				 ignore downlink after listening connection event from
-				 conntrack as it is not destinated to private ip address */
-			IPACMDBG("Interface (%s) is nat\n", ifr.ifr_name);
-			for (j = 0; j < MAX_IFACE_ADDRESS; j++)
-			{
-				/* check if duplicate NAT ip */
-				if (nat_iface_ipv4_addr[j] == data->ipv4_addr)
-				{
-					*NatIface = true;
-					return IPACM_SUCCESS;
-				}
-
-				if (nat_iface_ipv4_addr[j] == 0)
-				{
-					nat_iface_ipv4_addr[j] = data->ipv4_addr;
-					IPACMDBG_H("Nating connections of Interface (%s), entry (%d) ",
+			IPACMDBG_H("Nat iface (%s), entry (%d), dont cache",
 						pNatIfaces[i].iface_name, j);
-					iptodot("with ipv4 address: ", nat_iface_ipv4_addr[j]);
-
-					*NatIface = true;
-					return IPACM_SUCCESS;
-				}
-			}
+			iptodot("with ipv4 address: ", nat_iface_ipv4_addr[j]);
+			*NatIface = true;
+			return IPACM_SUCCESS;
 		}
 	}
 
@@ -247,6 +230,12 @@
 	bool NatIface = false;
 	int cnt, ret;
 
+	if (isStaMode)
+	{
+		IPACMDBG("In STA mode, don't add dummy rules for non nat ifaces\n");
+		return;
+	}
+
 	/* Handle only non nat ifaces, NAT iface should be handle
 	   separately to avoid race conditions between route/nat
 	   rules add/delete operations */
@@ -261,6 +250,9 @@
 				if (nonnat_iface_ipv4_addr[cnt] == 0)
 				{
 					nonnat_iface_ipv4_addr[cnt] = data->ipv4_addr;
+					IPACMDBG("Add ip addr to non nat list (%d) ", cnt);
+					iptodot("with ipv4 address", nonnat_iface_ipv4_addr[cnt]);
+
 					/* Add dummy nat rule for non nat ifaces */
 					nat_inst->FlushTempEntries(data->ipv4_addr, true, true);
 					return;
@@ -700,6 +692,18 @@
 	int cnt;
 
 	*isTempEntry = false;
+
+	/* Special handling for Passthrough IP. */
+	if (IPACM_Iface::ipacmcfg->ipacm_ip_passthrough_mode)
+	{
+		if (rule->private_ip == IPACM_Wan::getWANIP())
+		{
+			IPACMDBG("In Passthrough mode and entry matched with Wan IP (0x%x)\n",
+				rule->private_ip);
+			return true;
+		}
+	}
+
 	/* check whether nat iface or not */
 	for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
 	{
@@ -716,27 +720,32 @@
 		}
 	}
 
-	/* check whether non nat iface or not, on Nat iface
-	   add dummy rule by copying public ip to private ip */
-	for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+	if (!isStaMode)
 	{
-		if (nonnat_iface_ipv4_addr[cnt] != 0)
+		/* check whether non nat iface or not, on Non Nat iface
+		   add dummy rule by copying public ip to private ip */
+		for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
 		{
-			if (rule->private_ip == nonnat_iface_ipv4_addr[cnt] ||
-				rule->target_ip == nonnat_iface_ipv4_addr[cnt])
+			if (nonnat_iface_ipv4_addr[cnt] != 0)
 			{
-				IPACMDBG("matched non_nat_iface_ipv4_addr entry(%d)\n", cnt);
-				iptodot("AddIface(): Non Nat entry match with ip addr",
-						nat_iface_ipv4_addr[cnt]);
+				if (rule->private_ip == nonnat_iface_ipv4_addr[cnt] ||
+					rule->target_ip == nonnat_iface_ipv4_addr[cnt])
+				{
+					IPACMDBG("matched non_nat_iface_ipv4_addr entry(%d)\n", cnt);
+					iptodot("AddIface(): Non Nat entry match with ip addr",
+							nonnat_iface_ipv4_addr[cnt]);
 
-				rule->private_ip = rule->public_ip;
-				rule->private_port = rule->public_port;
-				return true;
+					rule->private_ip = rule->public_ip;
+					rule->private_port = rule->public_port;
+					return true;
+				}
 			}
 		}
+		IPACMDBG_H("Not mtaching with non-nat ifaces\n");
 	}
+	else
+		IPACMDBG("In STA mode, don't compare against non nat ifaces\n");
 
-	IPACMDBG_H("Not mtaching with non-nat ifaces\n");
 	if(pConfig == NULL)
 	{
 		pConfig = IPACM_Config::GetInstance();
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
index 93627bb..f0bdd99 100644
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -242,7 +242,7 @@
 			 cache[cnt].protocol == rule->protocol)
 		{
 			log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
-			rule->target_port,"Duplicate Rule");
+			rule->target_port,"Duplicate Rule\n");
 			return true;
 		}
 	}
@@ -257,7 +257,7 @@
 	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
 
 	log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
-	rule->target_port,"for deletion");
+	rule->target_port,"for deletion\n");
 
 
 	for(; cnt < max_entries; cnt++)
@@ -302,7 +302,7 @@
 
 	CHK_TBL_HDL();
 	log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
-	rule->target_port,"for addition");
+	rule->target_port,"for addition\n");
 	if(isAlgPort(rule->protocol, rule->private_port) ||
 		 isAlgPort(rule->protocol, rule->target_port))
 	{
diff --git a/ipacm/src/IPACM_IfaceManager.cpp b/ipacm/src/IPACM_IfaceManager.cpp
index d6ad9a5..ef5e0a0 100644
--- a/ipacm/src/IPACM_IfaceManager.cpp
+++ b/ipacm/src/IPACM_IfaceManager.cpp
@@ -83,6 +83,11 @@
 		case IPA_BRIDGE_LINK_UP_EVENT:
 			IPACMDBG_H(" Save the bridge0 mac info in IPACM_cfg \n");
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_BRIDGE_LINK_UP_EVENT: not supported iface id: %d\n", data_all->if_index);
+				break;
+			}
 			/* check if iface is bridge interface*/
 			if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
 			{
@@ -98,6 +103,11 @@
 		case IPA_LINK_UP_EVENT:
 			IPACMDBG_H("Recieved IPA_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+				break;
+			}
 			/* LTE-backhaul */
 			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == EMBMS_IF)
 			{
@@ -115,6 +125,11 @@
 		case IPA_USB_LINK_UP_EVENT:
 			IPACMDBG_H("Recieved IPA_USB_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_USB_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+				break;
+			}
 			/* check if it's WAN_IF */
 			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
 			{
@@ -134,6 +149,11 @@
 
 		case IPA_WLAN_AP_LINK_UP_EVENT:
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_WLAN_AP_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+				break;
+			}
 			/* change iface category from unknown to WLAN_IF */
 			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
 			{
@@ -151,6 +171,11 @@
 
 		case IPA_WLAN_STA_LINK_UP_EVENT:
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(StaData->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_WLAN_STA_LINK_UP_EVENT: not supported iface id: %d\n", StaData->if_index);
+				break;
+			}
 			/* change iface category from unknown to WAN_IF */
 			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
 			{
@@ -175,6 +200,11 @@
 		/* Add new instance open for eMBMS iface and wan iface */
 		case IPA_WAN_EMBMS_LINK_UP_EVENT:
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_WAN_EMBMS_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+				break;
+			}
 			/* change iface category from unknown to EMBMS_IF */
 			if ((IPACM_Iface::ipacmcfg->ipacm_odu_enable == true) && (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true))
 			{
@@ -250,6 +280,7 @@
 #endif
 				IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, lan);
 				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
+				/* IPA_LAN_DELETE_SELF should be always last */
 				IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, lan);
 				IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", lan->dev_name, lan->ipa_if_num);
 				registr(ipa_interface_index, lan);
@@ -272,6 +303,7 @@
 				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, ETH);
 				IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, ETH);
 				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, ETH);
+				/* IPA_LAN_DELETE_SELF should be always last */
 				IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, ETH);
 				IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", ETH->dev_name, ETH->ipa_if_num);
 				registr(ipa_interface_index, ETH);
@@ -297,6 +329,7 @@
 					IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, odu);
 					IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, odu);
 					IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, odu);
+					/* IPA_LAN_DELETE_SELF should be always last */
 					IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
 					IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
 					registr(ipa_interface_index, odu);
@@ -312,6 +345,7 @@
 					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, odu);
 					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, odu);
 					IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, odu);
+					/* IPA_LAN_DELETE_SELF should be always last */
 					IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
 					IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
 					registr(ipa_interface_index, odu);
@@ -352,17 +386,18 @@
 #endif
 				IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, wl);
 				IPACM_EvtDispatcher::registr(IPA_WLAN_LINK_DOWN_EVENT, wl);
-				IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, wl);
 #ifndef FEATURE_IPA_ANDROID
 				IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, wl);
 				IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, wl);
 #else
 				IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, wl);
 #endif
+				/* IPA_LAN_DELETE_SELF should be always last */
+				IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, wl);
 				IPACMDBG_H("ipa_WLAN (%s):ipa_index (%d) instance open/registr ok\n", wl->dev_name, wl->ipa_if_num);
 				registr(ipa_interface_index, wl);
 				/* solve the new_addr comes earlier issue */
-	                        IPACM_Iface::iface_addr_query(if_index);
+	            IPACM_Iface::iface_addr_query(if_index);
 			}
 			break;
 
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index d4e983a..6b211d9 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -120,6 +120,7 @@
 	memset(ipv6_icmp_flt_rule_hdl, 0, NUM_IPV6_ICMP_FLT_RULE * sizeof(uint32_t));
 	modem_ul_v4_set = false;
 	modem_ul_v6_set = false;
+	memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
 
 	/* ODU routing table initilization */
 	if(ipa_if_cate == ODU_IF)
@@ -379,6 +380,7 @@
 						{
 							if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
 							{
+								memcpy(ipv6_prefix, IPACM_Wan::backhaul_ipv6_prefix, sizeof(ipv6_prefix));
 								install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
 								if(IPACM_Wan::backhaul_is_sta_mode == false)
 								{
@@ -481,6 +483,7 @@
 		{
 			if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
 			{
+					memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix));
 					install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix);
 					if(data_wan_tether->is_sta == false)
 					{
@@ -576,16 +579,17 @@
 		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
 		if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
 		{
+			memcpy(ipv6_prefix, data_wan->ipv6_prefix, sizeof(ipv6_prefix));
 			install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
-		if(data_wan->is_sta == false)
-		{
+			if(data_wan->is_sta == false)
+			{
 				ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
 				handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
 			}
-		else
-		{
-			handle_wan_up(IPA_IP_v6);
-		}
+			else
+			{
+				handle_wan_up(IPA_IP_v6);
+			}
 		}
 		break;
 
@@ -779,7 +783,7 @@
 {
 	uint32_t tx_index;
 	uint32_t rt_hdl;
-	int num_v6, clnt_indx;
+	int num_v6 =0, clnt_indx;
 
 	clnt_indx = get_eth_client_index(data->mac_addr);
 	if (clnt_indx == IPACM_INVALID_INDEX)
@@ -967,7 +971,7 @@
 		rt_rule_entry->at_rear = false;
 		rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;  //go to A5
 		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
-   		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name));
 		rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
 		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
 #ifdef FEATURE_IPA_V3
@@ -1024,7 +1028,7 @@
 		rt_rule->commit = 1;
 		rt_rule->num_rules = NUM_RULES;
 		rt_rule->ip = data->iptype;
-		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
 
 		rt_rule_entry = &rt_rule->rules[0];
 		rt_rule_entry->at_rear = false;
@@ -1060,7 +1064,7 @@
 		dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
 
 		/* setup same rule for v6_wan table*/
-		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name);
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
 		if (false == m_routing.AddRoutingRule(rt_rule))
 		{
 			IPACMERR("Routing rule addition failed!\n");
@@ -1135,13 +1139,6 @@
 		m_pFilteringTable->ip = IPA_IP_v4;
 		m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
 
-		if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
-		{
-			IPACMERR("LAN m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
-			free(m_pFilteringTable);
-			return IPACM_FAILURE;
-		}
-
 		/* Make LAN-traffic always go A5, use default IPA-RT table */
 		if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4))
 		{
@@ -1685,6 +1682,8 @@
 {
 	int clnt_indx;
 	int v6_num;
+	uint32_t ipv6_link_local_prefix = 0xFE800000;
+	uint32_t ipv6_link_local_prefix_mask = 0xFFC00000;
 
 	IPACMDBG_H("number of eth clients: %d\n", num_eth_client);
 	IPACMDBG_H("event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -1731,10 +1730,10 @@
 					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
-	{
+		else
+		{
 		    IPACMDBG_H("Invalid client IPv4 address \n");
 		    return IPACM_FAILURE;
 		}
@@ -1744,21 +1743,28 @@
 		if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
 				(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0)) /* check if all 0 not valid ipv6 address */
 		{
-		   IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
-                   if(get_client_memptr(eth_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
-		   {
+			IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+			if( (data->ipv6_addr[0] & ipv6_link_local_prefix_mask) != (ipv6_link_local_prefix & ipv6_link_local_prefix_mask) &&
+				memcmp(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix)) != 0)
+			{
+				IPACMDBG_H("This IPv6 address is not global IPv6 address with correct prefix, ignore.\n");
+				return IPACM_FAILURE;
+			}
+
+            if(get_client_memptr(eth_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
+			{
 
 		       for(v6_num=0;v6_num < get_client_memptr(eth_client, clnt_indx)->ipv6_set;v6_num++)
-	               {
-			      if( data->ipv6_addr[0] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][0] &&
+				{
+					if( data->ipv6_addr[0] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][0] &&
 			           data->ipv6_addr[1] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][1] &&
 			  	        data->ipv6_addr[2]== get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][2] &&
 			  	         data->ipv6_addr[3] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][3])
-			      {
-					IPACMDBG_H("Already see this ipv6 addr at position: %d for client:%d\n", v6_num, clnt_indx);
-			  	    return IPACM_FAILURE; /* not setup the RT rules*/
-			      }
-		       }
+					{
+						IPACMDBG_H("Already see this ipv6 addr at position: %d for client:%d\n", v6_num, clnt_indx);
+						return IPACM_FAILURE; /* not setup the RT rules*/
+					}
+				}
 
 		       /* not see this ipv6 before for wifi client*/
 			   get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
@@ -1769,8 +1775,8 @@
 		    }
 		    else
 		    {
-		         IPACMDBG_H("Already got 3 ipv6 addr for client:%d\n", clnt_indx);
-			 return IPACM_FAILURE; /* not setup the RT rules*/
+		        IPACMDBG_H("Already got %d ipv6 addr for client:%d\n", IPV6_NUM_ADDR, clnt_indx);
+				return IPACM_FAILURE; /* not setup the RT rules*/
 		    }
 		}
 	}
@@ -2055,7 +2061,7 @@
 
 								memset(pHeaderDescriptor->hdr[0].name, 0,
 											 sizeof(pHeaderDescriptor->hdr[0].name));
-								strcpy(pHeaderDescriptor->hdr[0].name, IPA_ODU_HDR_NAME_v4);
+								strlcpy(pHeaderDescriptor->hdr[0].name, IPA_ODU_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name));
 								pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
 								pHeaderDescriptor->hdr[0].hdr_hdl = -1;
 								pHeaderDescriptor->hdr[0].is_partial = 0;
@@ -2135,7 +2141,7 @@
 				memset(pHeaderDescriptor->hdr[0].name, 0,
 					 sizeof(pHeaderDescriptor->hdr[0].name));
 
-				strcpy(pHeaderDescriptor->hdr[0].name, IPA_ODU_HDR_NAME_v6);
+				strlcpy(pHeaderDescriptor->hdr[0].name, IPA_ODU_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name));
 				pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
 				pHeaderDescriptor->hdr[0].hdr_hdl = -1;
 				pHeaderDescriptor->hdr[0].is_partial = 0;
@@ -2202,13 +2208,13 @@
 
 		if (IPA_IP_v4 == tx_prop->tx[tx_index].ip)
 		{
-			strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v4.name);
+			strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v4.name, sizeof(rt_rule->rt_tbl_name));
 			rt_rule_entry->rule.hdr_hdl = ODU_hdr_hdl_v4;
 			rt_rule->ip = IPA_IP_v4;
 		}
 		else
 		{
-			strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v6.name);
+			strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v6.name, sizeof(rt_rule->rt_tbl_name));
 			rt_rule_entry->rule.hdr_hdl = ODU_hdr_hdl_v6;
 			rt_rule->ip = IPA_IP_v6;
 		}
@@ -2931,6 +2937,8 @@
 
 	delete_ipv6_prefix_flt_rule();
 
+	memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
+
 	if(is_sta_mode == false)
 	{
 		if (num_wan_ul_fl_rule_v6 > MAX_WAN_UL_FILTER_RULES)
diff --git a/ipacm/src/IPACM_LanToLan.cpp b/ipacm/src/IPACM_LanToLan.cpp
index be33acd..6817177 100644
--- a/ipacm/src/IPACM_LanToLan.cpp
+++ b/ipacm/src/IPACM_LanToLan.cpp
@@ -593,7 +593,6 @@
 	m_p_iface->eth_bridge_add_flt_rule(client->mac_addr, rt_tbl.hdl,
 		iptype, &flt_rule_hdl);
 	IPACMDBG_H("Installed flt rule for IP type %d: handle %d\n", iptype, flt_rule_hdl);
-	IPACM_Iface::m_routing.PutRoutingTable(rt_tbl.hdl);
 
 	for(it_flt = peer->flt_rule.begin(); it_flt != peer->flt_rule.end(); it_flt++)
 	{
diff --git a/ipacm/src/IPACM_Neighbor.cpp b/ipacm/src/IPACM_Neighbor.cpp
index 6a49502..b4587d3 100644
--- a/ipacm/src/IPACM_Neighbor.cpp
+++ b/ipacm/src/IPACM_Neighbor.cpp
@@ -71,6 +71,11 @@
 		{
 			ipacm_event_data_wlan_ex *data = (ipacm_event_data_wlan_ex *)param;
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("IPA_WLAN_CLIENT_ADD_EVENT_EX: not supported iface id: %d\n", data->if_index);
+				break;
+			}
 			uint8_t client_mac_addr[6];
 
 			IPACMDBG_H("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
@@ -132,9 +137,14 @@
 							IPACM_EvtDispatcher::PostEvt(&evt_data);
 							/* ask for replaced iface name*/
 							ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
-							IPACMDBG_H("Posted event %d, with %s for ipv4 client re-connect\n",
-											evt_data.event,
-											IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+							/* check for failure return */
+							if (IPACM_FAILURE == ipa_interface_index) {
+								IPACMERR("not supported iface id: %d\n", data_all->if_index);
+							} else {
+								IPACMDBG_H("Posted event %d, with %s for ipv4 client re-connect\n",
+									evt_data.event,
+									IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+							}
 						}
 					}
 					break;
@@ -156,7 +166,11 @@
 
 			ipacm_event_data_all *data = (ipacm_event_data_all *)param;
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
-
+			/* check for failure return */
+			if (IPACM_FAILURE == ipa_interface_index) {
+				IPACMERR("not supported iface id: %d\n", data->if_index);
+				break;
+			}
 			if (data->iptype == IPA_IP_v4)
 			{
 				if (data->ipv4_addr != 0) /* not 0.0.0.0 */
@@ -224,9 +238,15 @@
 
 								/* ask for replaced iface name*/
 								ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
-								IPACMDBG_H("Posted event %d, with %s for ipv4\n",
-												evt_data.event,
-												IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+								/* check for failure return */
+								if (IPACM_FAILURE == ipa_interface_index) {
+									IPACMERR("not supported iface id: %d\n", data_all->if_index);
+								} else {
+									IPACMDBG_H("Posted event %d,\
+										with %s for ipv4\n",
+										evt_data.event,
+										IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+								}
 								break;
 							}
 						}
@@ -385,9 +405,15 @@
 								IPACM_EvtDispatcher::PostEvt(&evt_data);
 								/* ask for replaced iface name*/
 								ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
-								IPACMDBG_H("Posted event %d, with %s for ipv6\n",
-												evt_data.event,
-												IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+								/* check for failure return */
+								if (IPACM_FAILURE == ipa_interface_index) {
+									IPACMERR("not supported iface id: %d\n", data_all->if_index);
+								} else {
+									IPACMDBG_H("Posted event %d,\
+										with %s for ipv6\n",
+										evt_data.event,
+										IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+								}
 								break;
 							};
 						}
@@ -470,9 +496,15 @@
 									IPACM_EvtDispatcher::PostEvt(&evt_data);
 									/* ask for replaced iface name*/
 									ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
-									IPACMDBG_H("Posted event %d, with %s for ipv4 client re-connect\n",
-													evt_data.event,
-													IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+									/* check for failure return */
+									if (IPACM_FAILURE == ipa_interface_index) {
+										IPACMERR("not supported iface id: %d\n", data_all->if_index);
+									} else {
+										IPACMDBG_H("Posted event %d,\
+											with %s for ipv4 client re-connect\n",
+											evt_data.event,
+											IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+									}
 								}
 							}
 							/* delete cache neighbor entry */
diff --git a/ipacm/src/IPACM_Routing.cpp b/ipacm/src/IPACM_Routing.cpp
index 7ae6131..2a2555a 100644
--- a/ipacm/src/IPACM_Routing.cpp
+++ b/ipacm/src/IPACM_Routing.cpp
@@ -176,8 +176,10 @@
 		IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
 		return false;
 	}
-
 	IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
+	/* put routing table right after successfully get routing table */
+	PutRoutingTable(routingTable->hdl);
+
 	return true;
 }
 
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index 5aae426..3bc62b2 100644
--- a/ipacm/src/IPACM_Wan.cpp
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -55,6 +55,7 @@
 bool IPACM_Wan::wan_up_v6 = false;
 uint8_t IPACM_Wan::xlat_mux_id = 0;
 
+uint32_t IPACM_Wan::curr_wan_ip = 0;
 int IPACM_Wan::num_v4_flt_rule = 0;
 int IPACM_Wan::num_v6_flt_rule = 0;
 
@@ -231,7 +232,7 @@
 	    rt_rule->commit = 1;
 	    rt_rule->num_rules = NUM_RULES;
 	    rt_rule->ip = data->iptype;
-	    	strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
 
 	    rt_rule_entry = &rt_rule->rules[0];
 		if(m_is_sta_mode == Q6_WAN)
@@ -285,7 +286,7 @@
 	    	dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
 
             /* setup same rule for v6_wan table*/
-	    	strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name);
+			strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
 	    if (false == m_routing.AddRoutingRule(rt_rule))
 	    {
 	    	IPACMERR("Routing rule addition failed!\n");
@@ -447,7 +448,7 @@
 		rt_rule_entry->at_rear = false;
 		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
 		/* still need setup v4 default routing rule to A5*/
-		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name));
 		rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
 		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
 #ifdef FEATURE_IPA_V3
@@ -491,6 +492,10 @@
 
 		wan_v4_addr = data->ipv4_addr;
 		wan_v4_addr_set = true;
+
+		if (m_is_sta_mode == Q6_WAN)
+			curr_wan_ip = data->ipv4_addr;
+
 		IPACMDBG_H("Receved wan ipv4-addr:0x%x\n",wan_v4_addr);
 	}
 
@@ -1336,12 +1341,12 @@
 			/* use the STA-header handler */
 			if (iptype == IPA_IP_v4)
 			{
-	    		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+				strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name, sizeof(rt_rule->rt_tbl_name));
 				rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v4;
 			}
 			else
 			{
-	    		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+				strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
 				rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v6;
 			}
 
@@ -1412,7 +1417,7 @@
 
 	if (iptype == IPA_IP_v6)
 	{
-		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name);
+		strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
 		memset(rt_rule_entry, 0, sizeof(struct ipa_rt_rule_add));
 		rt_rule_entry->at_rear = true;
 		if(m_is_sta_mode == Q6_WAN)
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 375a718..00754a1 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -157,7 +157,7 @@
 				IPACMDBG_H("Received IPA_WLAN_LINK_DOWN_EVENT\n");
 				handle_down_evt();
 				/* reset the AP-iface category to unknown */
-				ipa_if_cate = UNKNOWN_IF;
+				IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat = UNKNOWN_IF;
 				IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
 				IPACM_Wlan::total_num_wifi_clients = (IPACM_Wlan::total_num_wifi_clients) - \
                                                                      (num_wifi_client);
@@ -284,6 +284,7 @@
 					{
 						if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
 						{
+							memcpy(ipv6_prefix, IPACM_Wan::backhaul_ipv6_prefix, sizeof(ipv6_prefix));
 							install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
 
 							if(IPACM_Wan::backhaul_is_sta_mode == false)
@@ -356,6 +357,7 @@
 		{
 			if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
 			{
+				memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix));
 				install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix);
 
 				if(data_wan_tether->is_sta == false)
@@ -463,6 +465,7 @@
 		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
 		if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
 		{
+			memcpy(ipv6_prefix, data_wan->ipv6_prefix, sizeof(ipv6_prefix));
 			install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
 
 			if(data_wan->is_sta == false)
@@ -1038,6 +1041,8 @@
 {
 	int clnt_indx;
 	int v6_num;
+	uint32_t ipv6_link_local_prefix = 0xFE800000;
+	uint32_t ipv6_link_local_prefix_mask = 0xFFC00000;
 
 	IPACMDBG_H("number of wifi clients: %d\n", num_wifi_client);
 	IPACMDBG_H(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -1097,22 +1102,29 @@
 		if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
 				(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0)) /* check if all 0 not valid ipv6 address */
 		{
-		   IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
-                   if(get_client_memptr(wlan_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
-		   {
+			IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+			if( (data->ipv6_addr[0] & ipv6_link_local_prefix_mask) != (ipv6_link_local_prefix & ipv6_link_local_prefix_mask) &&
+				memcmp(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix)) != 0)
+			{
+				IPACMDBG_H("This IPv6 address is not global IPv6 address with correct prefix, ignore.\n");
+				return IPACM_FAILURE;
+			}
+
+			if(get_client_memptr(wlan_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
+			{
 
 		       for(v6_num=0;v6_num < get_client_memptr(wlan_client, clnt_indx)->ipv6_set;v6_num++)
-	               {
-			      if( data->ipv6_addr[0] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][0] &&
+				{
+					if( data->ipv6_addr[0] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][0] &&
 			           data->ipv6_addr[1] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][1] &&
 			  	        data->ipv6_addr[2]== get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][2] &&
 			  	         data->ipv6_addr[3] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][3])
-			      {
+					{
 			  	    IPACMDBG_H("Already see this ipv6 addr for client:%d\n", clnt_indx);
 			  	    return IPACM_FAILURE; /* not setup the RT rules*/
 			  		break;
-			      }
-		       }
+					}
+				}
 
 		       /* not see this ipv6 before for wifi client*/
 			   get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
@@ -1123,8 +1135,8 @@
 		    }
 		    else
 		    {
-		         IPACMDBG_H("Already got 3 ipv6 addr for client:%d\n", clnt_indx);
-			 return IPACM_FAILURE; /* not setup the RT rules*/
+				IPACMDBG_H("Already got %d ipv6 addr for client:%d\n", IPV6_NUM_ADDR, clnt_indx);
+				return IPACM_FAILURE; /* not setup the RT rules*/
 		    }
 		}
 	}
diff --git a/ipacm/src/IPACM_Xml.cpp b/ipacm/src/IPACM_Xml.cpp
index faae5b2..073dc98 100644
--- a/ipacm/src/IPACM_Xml.cpp
+++ b/ipacm/src/IPACM_Xml.cpp
@@ -174,7 +174,8 @@
 						IPACM_util_icmp_string((char*)xml_node->name, SUBNET_TAG) == 0 ||
 						IPACM_util_icmp_string((char*)xml_node->name, IPACMALG_TAG) == 0 ||
 						IPACM_util_icmp_string((char*)xml_node->name, ALG_TAG) == 0 ||
-						IPACM_util_icmp_string((char*)xml_node->name, IPACMNat_TAG) == 0)
+						IPACM_util_icmp_string((char*)xml_node->name, IPACMNat_TAG) == 0 ||
+						IPACM_util_icmp_string((char*)xml_node->name, IP_PassthroughFlag_TAG) == 0)
 				{
 					if (0 == IPACM_util_icmp_string((char*)xml_node->name, IFACE_TAG))
 					{
@@ -196,6 +197,27 @@
 					/* go to child */
 					ret_val = ipacm_cfg_xml_parse_tree(xml_node->children, config);
 				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, IP_PassthroughMode_TAG) == 0)
+				{
+					IPACMDBG_H("inside IP Passthrough\n");
+					content = IPACM_read_content_element(xml_node);
+					if (content)
+					{
+						str_size = strlen(content);
+						memset(content_buf, 0, sizeof(content_buf));
+						memcpy(content_buf, (void *)content, str_size);
+						if (atoi(content_buf))
+						{
+							config->ip_passthrough_mode = true;
+							IPACMDBG_H("Passthrough enable %d buf(%d)\n", config->ip_passthrough_mode, atoi(content_buf));
+						}
+						else
+						{
+							config->ip_passthrough_mode = false;
+							IPACMDBG_H("Passthrough enable %d buf(%d)\n", config->ip_passthrough_mode, atoi(content_buf));
+						}
+					}
+				}
 				else if (IPACM_util_icmp_string((char*)xml_node->name, ODUMODE_TAG) == 0)
 				{
 					IPACMDBG_H("inside ODU-XML\n");
diff --git a/ipacm/src/IPACM_cfg.xml b/ipacm/src/IPACM_cfg.xml
index 6758e2a..fc6314d 100644
--- a/ipacm/src/IPACM_cfg.xml
+++ b/ipacm/src/IPACM_cfg.xml
@@ -77,6 +77,9 @@
 			   <Category>VIRTUAL</Category>
 		    </Iface>
 		</IPACMIface>
+		<IPPassthroughFlag>
+			<IPPassthroughMode>0</IPPassthroughMode>
+		</IPPassthroughFlag>
 		<IPACMPrivateSubnet>
 			<Subnet>
   			   <SubnetAddress>192.168.225.0</SubnetAddress>