IPACM: add support for cradle in msmzirc

Add IPACM support for cradle LAN/WAN ROUTER/BRIDGE modes in msmzirc.

Change-Id: I166cac09614f5a3a1da340c04bcdf97c8002ebaa
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index 45ea6c0..72c348c 100644
--- a/ipacm/inc/IPACM_Defs.h
+++ b/ipacm/inc/IPACM_Defs.h
@@ -101,7 +101,7 @@
 #define IPA_LAN_TO_LAN_WLAN_HDR_NAME_V4 "Lan2Lan_Wlan_v4"
 #define IPA_LAN_TO_LAN_WLAN_HDR_NAME_V6 "Lan2Lan_Wlan_v6"
 #define IPA_LAN_TO_LAN_MAX_WLAN_CLIENT 32
-#define IPA_LAN_TO_LAN_MAX_USB_CLIENT 1
+#define IPA_LAN_TO_LAN_MAX_USB_CLIENT 15
 #define TCP_FIN_SHIFT 16
 #define TCP_SYN_SHIFT 17
 #define TCP_RST_SHIFT 18
@@ -179,6 +179,7 @@
 	IPA_ETH_BRIDGE_HDR_PROC_CTX_UNSET_EVENT,  /* 49 ipacm_event_data_fid */
 	IPA_WLAN_SWITCH_TO_SCC,                   /* 50 No Data */
 	IPA_WLAN_SWITCH_TO_MCC,                   /* 51 No Data */
+	IPA_CRADLE_WAN_MODE_SWITCH,				  /* 52 ipacm_event_cradle_wan_mode */
 	IPACM_EVENT_MAX
 } ipa_cm_event_id;
 
@@ -200,6 +201,12 @@
 	UNKNOWN_IF
 } ipacm_iface_type;
 
+typedef enum
+{
+	ROUTER = 0,
+	BRIDGE
+} ipacm_iface_mode;
+
 typedef struct
 {
 	struct nf_conntrack *ct;
@@ -210,6 +217,7 @@
 {
 	char iface_name[IPA_IFACE_NAME_LEN];
 	ipacm_iface_type if_cat;
+	ipacm_iface_mode if_mode;
 	int netlink_interface_index;
 } ipa_ifi_dev_name_t;
 
@@ -233,6 +241,11 @@
 
 typedef struct
 {
+	ipacm_iface_mode cradle_wan_mode;
+} ipacm_event_cradle_wan_mode;
+
+typedef struct
+{
 	enum ipa_ip_type iptype;
 	uint32_t ipv4_addr;
 	uint32_t ipv6_addr[4];
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
index 505f426..bcfd898 100644
--- a/ipacm/inc/IPACM_Lan.h
+++ b/ipacm/inc/IPACM_Lan.h
@@ -185,6 +185,7 @@
 
 	int del_lan2lan_hdr(ipa_ip_type iptype, uint32_t hdr_hdl);
 
+	int handle_cradle_wan_mode_switch(bool is_wan_bridge_mode);
 
 
 	static ipa_hdr_l2_type usb_hdr_type;
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
index 07036f0..96bb0e6 100644
--- a/ipacm/inc/IPACM_Wan.h
+++ b/ipacm/inc/IPACM_Wan.h
@@ -116,6 +116,7 @@
 	static uint32_t backhaul_ipv6_prefix[2];
 
 	static bool embms_is_on;
+	static bool cradle_backhaul_is_wan_bridge;
 
 private:
 
diff --git a/ipacm/inc/IPACM_Xml.h b/ipacm/inc/IPACM_Xml.h
index 90e0289..924e16d 100644
--- a/ipacm/inc/IPACM_Xml.h
+++ b/ipacm/inc/IPACM_Xml.h
@@ -84,6 +84,7 @@
 #define IFACE_TAG                            "Iface"
 #define NAME_TAG                             "Name"
 #define CATEGORY_TAG                         "Category"
+#define MODE_TAG                             "Mode"
 #define IPACMPRIVATESUBNETCFG_TAG            "IPACMPrivateSubnet"
 #define SUBNET_TAG                           "Subnet"
 #define SUBNETADDRESS_TAG                    "SubnetAddress"
@@ -96,6 +97,8 @@
 #define ODUIF_TAG                            "ODU"
 #define EMBMSIF_TAG                          "EMBMS"
 #define ETHIF_TAG                            "ETH"
+#define IFACE_ROUTER_MODE_TAG                "ROUTER"
+#define IFACE_BRIDGE_MODE_TAG                "BRIDGE"
 #define IPACMALG_TAG                         "IPACMALG"
 #define ALG_TAG                              "ALG"
 #define Protocol_TAG                         "Protocol"
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
index 1a11012..5626367 100644
--- a/ipacm/src/IPACM_Config.cpp
+++ b/ipacm/src/IPACM_Config.cpp
@@ -145,7 +145,9 @@
 	{
 		strncpy(iface_table[i].iface_name, cfg->iface_config.iface_entries[i].iface_name, sizeof(iface_table[i].iface_name));
 		iface_table[i].if_cat = cfg->iface_config.iface_entries[i].if_cat;
-		IPACMDBG_H("IPACM_Config::iface_table[%d] = %s, cat=%d\n", i, iface_table[i].iface_name, iface_table[i].if_cat);
+		iface_table[i].if_mode = cfg->iface_config.iface_entries[i].if_mode;
+		IPACMDBG_H("IPACM_Config::iface_table[%d] = %s, cat=%d, mode=%d\n", i, iface_table[i].iface_name,
+				iface_table[i].if_cat, iface_table[i].if_mode);
 		/* copy bridge interface name to ipacmcfg */
 		if( iface_table[i].if_cat == VIRTUAL_IF)
 		{
diff --git a/ipacm/src/IPACM_IfaceManager.cpp b/ipacm/src/IPACM_IfaceManager.cpp
index 573d7c6..80f7210 100644
--- a/ipacm/src/IPACM_IfaceManager.cpp
+++ b/ipacm/src/IPACM_IfaceManager.cpp
@@ -225,6 +225,7 @@
 				IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_HDR_PROC_CTX_SET_EVENT, lan);
 				IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_HDR_PROC_CTX_UNSET_EVENT, lan);
 #endif
+				IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, lan);
 				IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
 				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);
@@ -246,6 +247,7 @@
 				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, ETH);
 				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, ETH);
 				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);
 				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);
@@ -269,6 +271,7 @@
 					IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, odu);
 					IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, odu);
 					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);
 					IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
 					IPACMDBG("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
@@ -319,6 +322,7 @@
 				IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_HDR_PROC_CTX_SET_EVENT, wl);
 				IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_HDR_PROC_CTX_UNSET_EVENT, wl);
 #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
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index bf69bed..2b757a6 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -732,6 +732,27 @@
 	}
 	break;
 
+	case IPA_CRADLE_WAN_MODE_SWITCH:
+	{
+		IPACMDBG_H("Received IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+		ipacm_event_cradle_wan_mode* wan_mode = (ipacm_event_cradle_wan_mode*)param;
+		if(wan_mode == NULL)
+		{
+			IPACMERR("Event data is empty.\n");
+			return;
+		}
+
+		if(wan_mode->cradle_wan_mode == BRIDGE)
+		{
+			handle_cradle_wan_mode_switch(true);
+		}
+		else
+		{
+			handle_cradle_wan_mode_switch(false);
+		}
+	}
+	break;
+
 	default:
 		break;
 	}
@@ -1148,7 +1169,14 @@
 		flt_rule_entry.at_rear = true;
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
-		flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+		if(IPACM_Wan::cradle_backhaul_is_wan_bridge == true)
+		{
+			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+		}
+		else
+		{
+			flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+		}
 		flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
 
 		memcpy(&flt_rule_entry.rule.attrib,
@@ -5426,5 +5454,85 @@
 	return IPACM_SUCCESS;
 }
 
+int IPACM_Lan::handle_cradle_wan_mode_switch(bool is_wan_bridge_mode)
+{
+	struct ipa_flt_rule_mdfy flt_rule_entry;
+	int len = 0;
+	ipa_ioc_mdfy_flt_rule *m_pFilteringTable;
+
+	IPACMDBG_H("Handle wan mode swtich: is wan bridge mode?%d\n", is_wan_bridge_mode);
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (1 * sizeof(struct ipa_flt_rule_mdfy));
+	m_pFilteringTable = (struct ipa_ioc_mdfy_flt_rule *)calloc(1, len);
+	if (m_pFilteringTable == NULL)
+	{
+		PERROR("Error Locate ipa_ioc_mdfy_flt_rule memory...\n");
+		return IPACM_FAILURE;
+	}
+
+	m_pFilteringTable->commit = 1;
+	m_pFilteringTable->ip = IPA_IP_v4;
+	m_pFilteringTable->num_rules = (uint8_t)1;
+
+	IPACMDBG_H("Retrieving routing hanle for table: %s\n",
+					 IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+	if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+	{
+		IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
+						 &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+		free(m_pFilteringTable);
+		return IPACM_FAILURE;
+	}
+	IPACMDBG_H("Routing handle for table: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl);
+
+
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_mdfy)); // Zero All Fields
+	flt_rule_entry.status = -1;
+	flt_rule_entry.rule_hdl = lan_wan_fl_rule_hdl[0];
+
+	flt_rule_entry.rule.retain_hdr = 0;
+	flt_rule_entry.rule.to_uc = 0;
+	flt_rule_entry.rule.eq_attrib_type = 0;
+	if(is_wan_bridge_mode)
+	{
+		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+	}
+	else
+	{
+		flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+	}
+	flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+
+	memcpy(&flt_rule_entry.rule.attrib,
+				 &rx_prop->rx[0].attrib,
+				 sizeof(flt_rule_entry.rule.attrib));
+
+	flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x0;
+	flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x0;
+
+	memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+	if (false == m_filtering.ModifyFilteringRule(m_pFilteringTable))
+	{
+		IPACMERR("Error Modifying RuleTable(0) to Filtering, aborting...\n");
+		free(m_pFilteringTable);
+		return IPACM_FAILURE;
+	}
+	else
+	{
+		IPACMDBG_H("flt rule hdl = %d, status = %d\n",
+						 m_pFilteringTable->rules[0].rule_hdl,
+						 m_pFilteringTable->rules[0].status);
+	}
+	free(m_pFilteringTable);
+	return IPACM_SUCCESS;
+}
+
 
 
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index 92b4a5e..ddb7915 100644
--- a/ipacm/src/IPACM_Wan.cpp
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -66,6 +66,7 @@
 int IPACM_Wan::num_ipv6_modem_pdn = 0;
 
 bool IPACM_Wan::embms_is_on = false;
+bool IPACM_Wan::cradle_backhaul_is_wan_bridge = false;
 
 uint32_t IPACM_Wan::backhaul_ipv6_prefix[2];
 
@@ -501,7 +502,66 @@
 
 	case IPA_CFG_CHANGE_EVENT:
 		{
-			if ( (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat != ipa_if_cate) &&
+			if ( (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == ipa_if_cate) &&
+					(m_is_sta_mode ==ECM_WAN))
+			{
+				IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT and category did not change(wan_mode:%d)\n", m_is_sta_mode);
+				IPACMDBG_H("Now the cradle wan mode is %d.\n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode);
+				if(is_default_gateway == true)
+				{
+					if(cradle_backhaul_is_wan_bridge == false && IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == BRIDGE)
+					{
+						IPACMDBG_H("Cradle wan mode switch to bridge mode.\n");
+						cradle_backhaul_is_wan_bridge = true;
+					}
+					else if(cradle_backhaul_is_wan_bridge == true && IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+					{
+						IPACMDBG_H("Cradle wan mode switch to router mode.\n");
+						cradle_backhaul_is_wan_bridge = false;
+					}
+					else
+					{
+						IPACMDBG_H("No cradle mode switch, return.\n");
+						return;
+					}
+					/* post wan mode change event to LAN/WLAN */
+					if(IPACM_Wan::wan_up == true)
+					{
+						IPACMDBG_H("This interface is default GW.\n");
+						ipacm_cmd_q_data evt_data;
+						memset(&evt_data, 0, sizeof(evt_data));
+
+						ipacm_event_cradle_wan_mode *data_wan_mode = NULL;
+						data_wan_mode = (ipacm_event_cradle_wan_mode *)malloc(sizeof(ipacm_event_cradle_wan_mode));
+						if(data_wan_mode == NULL)
+						{
+							IPACMERR("unable to allocate memory.\n");
+							return;
+						}
+						data_wan_mode->cradle_wan_mode = IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode;
+						evt_data.event = IPA_CRADLE_WAN_MODE_SWITCH;
+						evt_data.evt_data = data_wan_mode;
+						IPACMDBG_H("Posting IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+						IPACM_EvtDispatcher::PostEvt(&evt_data);
+					}
+					/* update the firewall flt rule actions */
+					if(active_v4)
+					{
+						del_dft_firewall_rules(IPA_IP_v4);
+						config_dft_firewall_rules(IPA_IP_v4);
+					}
+					if(active_v6)
+					{
+						del_dft_firewall_rules(IPA_IP_v6);
+						config_dft_firewall_rules(IPA_IP_v6);
+					}
+				}
+				else
+				{
+					IPACMDBG_H("This interface is not default GW, ignore.\n");
+				}
+			}
+			else if ( (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat != ipa_if_cate) &&
 					(m_is_sta_mode ==ECM_WAN))
 			{
 				IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT and category changed(wan_mode:%d)\n", m_is_sta_mode);
@@ -1027,6 +1087,14 @@
 	if (m_is_sta_mode !=Q6_WAN)
 	{
 		IPACM_Wan::backhaul_is_sta_mode	= true;
+		if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == BRIDGE)
+		{
+			IPACM_Wan::cradle_backhaul_is_wan_bridge = true;
+		}
+		else
+		{
+			IPACM_Wan::cradle_backhaul_is_wan_bridge = false;
+		}
 		if((iptype==IPA_IP_v4) && (header_set_v4 != true))
 		{
 			header_partial_default_wan_v4 = true;
@@ -1566,13 +1634,13 @@
 	        }
 	}
 
-    /* see if default routes are setup before constructing full header */
-    if(header_partial_default_wan_v4 == true)
+	/* see if default routes are setup before constructing full header */
+	if(header_partial_default_wan_v4 == true)
 	{
 	   handle_route_add_evt(IPA_IP_v4);
 	}
 
-    if(header_partial_default_wan_v6 == true)
+	if(header_partial_default_wan_v6 == true)
 	{
 	   handle_route_add_evt(IPA_IP_v6);
 	}
@@ -1697,25 +1765,39 @@
 			flt_rule_entry.status = -1;
 
 			/* firewall disable, all traffic are allowed */
-                        if(firewall_config.firewall_enable == true)
+			if(firewall_config.firewall_enable == true)
 			{
-			    flt_rule_entry.at_rear = true;
+				flt_rule_entry.at_rear = true;
 
-			     /* default action for v4 is go DST_NAT unless user set to exception*/
-                             if(firewall_config.rule_action_accept == true)
-			    {
-			        flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
-			    }
-			    else
-			    {
-			        flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
-                            }
-		        }
+				/* default action for v4 is go DST_NAT unless user set to exception*/
+				if(firewall_config.rule_action_accept == true)
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+				}
+				else
+				{
+					if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+					}
+					else
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+					}
+				}
+			}
 			else
 			{
-			  flt_rule_entry.at_rear = true;
-			flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
-                        }
+				flt_rule_entry.at_rear = true;
+				if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+				}
+				else
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+				}
+            }
 
 			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
 			memcpy(&flt_rule_entry.rule.attrib,
@@ -1776,14 +1858,21 @@
 					flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
 
 					/* Accept v4 matched rules*/
-                                        if(firewall_config.rule_action_accept == true)
-			                {
-			                     flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
-			                }
-			                else
-			                {
-			                     flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
-                                        }
+                    if(firewall_config.rule_action_accept == true)
+			        {
+						if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+						{
+							flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+						}
+						else
+						{
+							flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+						}
+			        }
+			        else
+			        {
+			            flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+                    }
 
 					memcpy(&flt_rule_entry.rule.attrib,
 								 &firewall_config.extd_firewall_entries[i].attrib,
@@ -1877,7 +1966,7 @@
 			flt_rule_entry.status = -1;
 
 			/* firewall disable, all traffic are allowed */
-                        if(firewall_config.firewall_enable == true)
+            if(firewall_config.firewall_enable == true)
 			{
 			     flt_rule_entry.at_rear = true;
 
@@ -1888,14 +1977,28 @@
 			     }
 			     else
 			     {
-			       flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
-                             }
-		        }
+					if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+					}
+					else
+					{
+						flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+					}
+				}
+		    }
 			else
 			{
 			    flt_rule_entry.at_rear = true;
-			flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
-                        }
+				if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+				}
+				else
+				{
+					flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+				}
+            }
 
 			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
 			memcpy(&flt_rule_entry.rule.attrib,
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 4731641..0d822f6 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -757,6 +757,27 @@
 		}
 		break;
 
+	case IPA_CRADLE_WAN_MODE_SWITCH:
+	{
+		IPACMDBG_H("Received IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+		ipacm_event_cradle_wan_mode* wan_mode = (ipacm_event_cradle_wan_mode*)param;
+		if(wan_mode == NULL)
+		{
+			IPACMERR("Event data is empty.\n");
+			return;
+		}
+
+		if(wan_mode->cradle_wan_mode == BRIDGE)
+		{
+			handle_cradle_wan_mode_switch(true);
+		}
+		else
+		{
+			handle_cradle_wan_mode_switch(false);
+		}
+	}
+	break;
+
 	default:
 		break;
 	}
diff --git a/ipacm/src/IPACM_Xml.cpp b/ipacm/src/IPACM_Xml.cpp
index 6ef4cc0..09fd2e3 100644
--- a/ipacm/src/IPACM_Xml.cpp
+++ b/ipacm/src/IPACM_Xml.cpp
@@ -292,6 +292,26 @@
 						}
 					}
 				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name, MODE_TAG) == 0)
+				{
+					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 (0 == strncasecmp(content_buf, IFACE_ROUTER_MODE_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode = ROUTER;
+							IPACMDBG_H("Iface mode %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode);
+						}
+						else  if (0 == strncasecmp(content_buf, IFACE_BRIDGE_MODE_TAG, str_size))
+						{
+							config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode = BRIDGE;
+							IPACMDBG_H("Iface mode %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode);
+						}
+					}
+				}
 				else if (IPACM_util_icmp_string((char*)xml_node->name,
 																				SUBNETADDRESS_TAG) == 0)
 				{
diff --git a/ipacm/src/IPACM_cfg.xml b/ipacm/src/IPACM_cfg.xml
index 95a7796..8f7e886 100644
--- a/ipacm/src/IPACM_cfg.xml
+++ b/ipacm/src/IPACM_cfg.xml
@@ -12,6 +12,7 @@
 			<Iface>
 			   <Name>ecm0</Name>
 			   <Category>LAN</Category>
+			   <Mode>ROUTER</Mode>
 			</Iface>
 			<Iface>
 			   <Name>rmnet_data0</Name>
@@ -144,4 +145,4 @@
  	        <MaxNatEntries>500</MaxNatEntries>
 		</IPACMNAT>
 		</IPACM>
-</system>
\ No newline at end of file
+</system>