Merge "IPACM: enable ipacm daemon for user build"
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index 45ea6c0..37f3ff4 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];
@@ -265,6 +278,7 @@
 {
 	enum ipa_ip_type iptype;
 	int if_index;
+	uint32_t  ipv4_addr_gw;
 	uint32_t  ipv4_addr;
 	uint32_t  ipv4_addr_mask;
 	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..5160ac3 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:
 
@@ -133,7 +134,9 @@
 	uint32_t ODU_fl_hdl[IPA_NUM_DEFAULT_WAN_FILTER_RULES];
 	int num_firewall_v4,num_firewall_v6;
 	uint32_t wan_v4_addr;
+	uint32_t wan_v4_addr_gw;
 	bool wan_v4_addr_set;
+	bool wan_v4_addr_gw_set;
 	bool active_v4;
 	bool active_v6;
 	bool header_set_v4;
@@ -203,6 +206,39 @@
 		return IPACM_INVALID_INDEX;
 	}
 
+	inline int get_wan_client_index_ipv4(uint32_t ipv4_addr)
+	{
+		int cnt;
+		int num_wan_client_tmp = num_wan_client;
+
+		IPACMDBG_H("Passed IPv4 %x\n", ipv4_addr);
+
+		for(cnt = 0; cnt < num_wan_client_tmp; cnt++)
+		{
+			if (get_client_memptr(wan_client, cnt)->ipv4_set)
+			{
+				IPACMDBG_H("stored IPv4 %x\n", get_client_memptr(wan_client, cnt)->v4_addr);
+
+				if(ipv4_addr == get_client_memptr(wan_client, cnt)->v4_addr)
+				{
+					IPACMDBG_H("Matched client index: %d\n", cnt);
+					IPACMDBG_H("The MAC is %02x:%02x:%02x:%02x:%02x:%02x\n",
+							get_client_memptr(wan_client, cnt)->mac[0],
+							get_client_memptr(wan_client, cnt)->mac[1],
+							get_client_memptr(wan_client, cnt)->mac[2],
+							get_client_memptr(wan_client, cnt)->mac[3],
+							get_client_memptr(wan_client, cnt)->mac[4],
+							get_client_memptr(wan_client, cnt)->mac[5]);
+					IPACMDBG_H("header set ipv4(%d) ipv6(%d)\n",
+							get_client_memptr(wan_client, cnt)->ipv4_header_set,
+							get_client_memptr(wan_client, cnt)->ipv6_header_set);
+					return cnt;
+				}
+			}
+		}
+		return IPACM_INVALID_INDEX;
+	}
+
 	inline int delete_wan_rtrules(int clt_indx, ipa_ip_type iptype)
 	{
 		uint32_t tx_index;
@@ -278,8 +314,8 @@
 	/* wan default route/filter rule configuration */
 	int handle_route_add_evt(ipa_ip_type iptype);
 
-	/* construct complete ethernet header */
-	int handle_header_add_evt(uint8_t *mac_addr);
+	/* construct complete STA ethernet header */
+	int handle_sta_header_add_evt();
 
 	int config_dft_firewall_rules(ipa_ip_type iptype);
 
diff --git a/ipacm/inc/IPACM_Wlan.h b/ipacm/inc/IPACM_Wlan.h
index 37584e2..fb5555a 100644
--- a/ipacm/inc/IPACM_Wlan.h
+++ b/ipacm/inc/IPACM_Wlan.h
@@ -322,6 +322,11 @@
 	int handle_wlan_client_reset_rt(ipa_ip_type iptype);
 
 	void handle_SCC_MCC_switch(ipa_ip_type);
+
+	void eth_bridge_handle_wlan_SCC_MCC_switch(ipa_ip_type iptype);
+
+	int eth_bridge_modify_wlan_rt_rule(uint8_t* mac, eth_bridge_src_iface src_iface, ipa_ip_type iptyp);
+
 };
 
 
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_Main.cpp b/ipacm/src/IPACM_Main.cpp
index 0aef584..3cc58e1 100644
--- a/ipacm/src/IPACM_Main.cpp
+++ b/ipacm/src/IPACM_Main.cpp
@@ -611,16 +611,22 @@
 
 		case WLAN_SWITCH_TO_SCC:
 			IPACMDBG_H("Received WLAN_SWITCH_TO_SCC\n");
-			IPACM_Iface::ipacmcfg->isMCC_Mode = false;
-			evt_data.event = IPA_WLAN_SWITCH_TO_SCC;
-			break;
-
+			if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+			{
+				IPACM_Iface::ipacmcfg->isMCC_Mode = false;
+				evt_data.event = IPA_WLAN_SWITCH_TO_SCC;
+				break;
+			}
+			continue;
 		case WLAN_SWITCH_TO_MCC:
 			IPACMDBG_H("Received WLAN_SWITCH_TO_MCC\n");
-			IPACM_Iface::ipacmcfg->isMCC_Mode = true;
-			evt_data.event = IPA_WLAN_SWITCH_TO_MCC;
-			break;
-
+			if (IPACM_Iface::ipacmcfg->isMCC_Mode == false)
+			{
+				IPACM_Iface::ipacmcfg->isMCC_Mode == true;
+				evt_data.event = IPA_WLAN_SWITCH_TO_MCC;
+				break;
+			}
+			continue;
 		default:
 			IPACMDBG_H("Unhandled message type: %d\n", event_hdr.msg_type);
 			continue;
diff --git a/ipacm/src/IPACM_Netlink.cpp b/ipacm/src/IPACM_Netlink.cpp
index 9db578c..13b1d6e 100644
--- a/ipacm/src/IPACM_Netlink.cpp
+++ b/ipacm/src/IPACM_Netlink.cpp
@@ -610,7 +610,7 @@
 	int ret_val, mask_value, mask_index, mask_value_v6;
 	struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
 
-	uint32_t if_ipv4_addr =0, if_ipipv4_addr_mask =0, temp =0;
+	uint32_t if_ipv4_addr =0, if_ipipv4_addr_mask =0, temp =0, if_ipv4_addr_gw =0;
 
 	ipacm_cmd_q_data evt_data;
 	ipacm_event_data_all *data_all;
@@ -996,17 +996,20 @@
 
 						IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
 						IPACM_EVENT_COPY_ADDR_v4( if_ipipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+						IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
 
 						evt_data.event = IPA_ROUTE_ADD_EVENT;
 						data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
 						data_addr->iptype = IPA_IP_v4;
 						data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+						data_addr->ipv4_addr_gw = ntohl(if_ipv4_addr_gw);
 						data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
 
-            IPACMDBG_H("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 addr:0x%x and maxk: 0x%x\n",
+            IPACMDBG_H("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 addr:0x%x, mask: 0x%x and gw: 0x%x\n",
 										 data_addr->if_index,
 										 data_addr->ipv4_addr,
-										 data_addr->ipv4_addr_mask);
+										 data_addr->ipv4_addr_mask,
+										 data_addr->ipv4_addr_gw);
 						evt_data.evt_data = data_addr;
 						IPACM_EvtDispatcher::PostEvt(&evt_data);
 						/* finish command queue */
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index 92b4a5e..9d4d99c 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];
 
@@ -90,6 +91,7 @@
 	m_is_sta_mode = is_sta_mode;
 
 	wan_v4_addr_set = false;
+	wan_v4_addr_gw_set = false;
 	active_v4 = false;
 	active_v6 = false;
 	header_set_v4 = false;
@@ -501,7 +503,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);
@@ -611,8 +672,11 @@
 				/* The special below condition is to handle default gateway */
 				if ((data->iptype == IPA_IP_v4) && (active_v4 == false) && (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX))
 				{
-					IPACMDBG_H("adding routing table(upstream), dev (%s) ip-type(%d)\n", dev_name,data->iptype);
+//					wan_v4_addr_gw = data->ipv4_addr_gw; /* android requires CnE change too */
+//					wan_v4_addr_gw_set = true;
+					IPACMDBG_H("adding routing table, dev (%s) ip-type(%d), default gw (%x)\n", dev_name,data->iptype, wan_v4_addr_gw);
 					handle_route_add_evt(data->iptype);
+
 				}
 				else if ((data->iptype == IPA_IP_v6) && (active_v6 == false) && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
 				{
@@ -626,6 +690,7 @@
 				{
 					IPACMDBG_H("Received v4 IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
 					IPACMDBG_H("need clean default v4 route (dst:0.0.0.0) for old iface (%s)\n", dev_name);
+//					wan_v4_addr_gw_set = false; /* android requires CnE change too */
 					if(m_is_sta_mode == Q6_WAN)
 					{
 						del_wan_firewall_rule(IPA_IP_v4);
@@ -667,6 +732,8 @@
 				IPACMDBG_H("Received IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT\n");
 				if ((data->iptype == IPA_IP_v4) && (active_v4 == true))
 				{
+					IPACMDBG_H("get del default v4 route (dst:0.0.0.0)\n");
+//					wan_v4_addr_gw_set = false; /* android requires CnE change too */
 					if(m_is_sta_mode == Q6_WAN)
 					{
 						del_wan_firewall_rule(IPA_IP_v4);
@@ -711,7 +778,11 @@
 				if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == false)
 					&& (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX))
 				{
-					IPACMDBG_H("adding routing table, dev (%s) ip-type(%d)\n", dev_name,data->iptype);
+					wan_v4_addr_gw = data->ipv4_addr_gw;
+					wan_v4_addr_gw_set = true;
+					IPACMDBG_H("adding routing table, dev (%s) ip-type(%d), default gw (%x)\n", dev_name,data->iptype, wan_v4_addr_gw);
+					/* Check & construct STA header */
+					handle_sta_header_add_evt();
 					handle_route_add_evt(data->iptype);
 				}
 				else if ((data->iptype == IPA_IP_v6) &&
@@ -732,6 +803,7 @@
 					IPACMDBG_H("ipv4 addr 0x%x\n", data->ipv4_addr);
 					IPACMDBG_H("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
 					IPACMDBG_H("need clean default v4 route (dst:0.0.0.0) for old iface (%s)\n", dev_name);
+					wan_v4_addr_gw_set = false;
 					if(m_is_sta_mode == Q6_WAN)
 					{
 						del_wan_firewall_rule(IPA_IP_v4);
@@ -774,6 +846,7 @@
 				if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == true))
 				{
 					IPACMDBG_H("get del default v4 route (dst:0.0.0.0)\n");
+					wan_v4_addr_gw_set = false;
 					if(m_is_sta_mode == Q6_WAN)
 					{
 						del_wan_firewall_rule(IPA_IP_v4);
@@ -817,7 +890,6 @@
 
 				if (m_is_sta_mode == WLAN_WAN)
 				{
-					handle_header_add_evt(ext_router_mac_addr);
 					if (data->iptype == IPA_IP_v4 && data->ipv4_addr == wan_v4_addr)
 					{
 						IPACMDBG_H("Ignore IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
@@ -853,18 +925,17 @@
 					return;
 				}
 
-				handle_header_add_evt(data->mac_addr);
-
 				handle_wan_hdr_init(data->mac_addr);
-				IPACMDBG_H("construct wan header and route rules \n");
+				IPACMDBG_H("construct wan-client header and route rules \n");
 				/* Associate with IP and construct RT-rule */
 				if (handle_wan_client_ipaddr(data) == IPACM_FAILURE)
 				{
 					return;
 				}
 				handle_wan_client_route_rule(data->mac_addr, data->iptype);
+				/* Check & construct STA header */
+				handle_sta_header_add_evt();
 				return;
-
 			}
 		}
 		break;
@@ -1027,6 +1098,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;
@@ -1064,7 +1143,7 @@
 			return IPACM_FAILURE;
 		}
 	}
-
+#if 0
     for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
 	{
 		if(tx_prop->tx[cnt].ip==iptype)
@@ -1110,6 +1189,7 @@
 			}
 	    }
     }
+#endif
 
 	rt_rule = (struct ipa_ioc_add_rt_rule *)
 		 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
@@ -1142,29 +1222,16 @@
 				continue;
 			}
 
+			/* use the STA-header handler */
 			if (iptype == IPA_IP_v4)
 			{
 	    		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.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);
-			}
-
-			if (tx_prop->tx[tx_index].hdr_name !=  NULL)
-			{
-				IPACMDBG_H(" TX- header hdl %s \n", tx_prop->tx[tx_index].hdr_name);
-				memset(&sRetHeader, 0, sizeof(sRetHeader));
-				strncpy(sRetHeader.name,
-								tx_prop->tx[tx_index].hdr_name,
-								sizeof(tx_prop->tx[tx_index].hdr_name));
-				if (false == m_header.GetHeaderHandle(&sRetHeader))
-				{
-					IPACMERR("\n ioctl failed\n");
-					free(rt_rule);
-					return IPACM_FAILURE;
-				}
-				rt_rule_entry->rule.hdr_hdl = sRetHeader.hdl;
+				rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v6;
 			}
 
 			if(IPACM_Iface::ipacmcfg->isMCC_Mode == true)
@@ -1353,233 +1420,70 @@
 }
 
 /* construct complete ethernet header */
-int IPACM_Wan::handle_header_add_evt(uint8_t *mac_addr)
+int IPACM_Wan::handle_sta_header_add_evt()
 {
-  #define WAN_IFACE_INDEX_LEN 2
-
-	uint32_t tx_index,cnt;
-	int res = IPACM_SUCCESS, len = 0;
-	char index[WAN_IFACE_INDEX_LEN];
-	struct ipa_ioc_copy_hdr sCopyHeader;
-	struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
-
-	/* start of adding header */
-
-	IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
-					 mac_addr[0], mac_addr[1], mac_addr[2],
-					 mac_addr[3], mac_addr[4], mac_addr[5]);
-
+	int res = IPACM_SUCCESS, index = IPACM_INVALID_INDEX;
 	if((header_set_v4 == true) || (header_set_v6 == true))
 	{
 		IPACMDBG_H("Already add STA full header\n");
 		return IPACM_SUCCESS;
 	}
-	/* add header to IPA */
-	len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
-	pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
-	if (pHeaderDescriptor == NULL)
+
+	/* checking if the ipv4 same as default route */
+	if(wan_v4_addr_gw_set)
 	{
-		IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
-		return IPACM_FAILURE;
-	}
-
-	/* copy partial header for v4 */
-        for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
-	{
-		   if(tx_prop->tx[cnt].ip==IPA_IP_v4)
-		   {
-	               memset(&sCopyHeader, 0, sizeof(sCopyHeader));
-	               memcpy(sCopyHeader.name,
-				 tx_prop->tx[cnt].hdr_name,
-				 sizeof(sCopyHeader.name));
-
-	IPACMDBG_H("header name: %s from tx: %d\n", sCopyHeader.name,cnt);
-	if (m_header.CopyHeader(&sCopyHeader) == false)
-	{
-		IPACMERR("ioctl copy header failed");
-		res = IPACM_FAILURE;
-		goto fail;
-	}
-
-	if(sCopyHeader.is_eth2_ofst_valid == false)
-	{
-		eth2_ofst_v4 = 0;
-	}
-	else
-	{
-		eth2_ofst_v4 = sCopyHeader.eth2_ofst;
-	}
-
-	IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
-	if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
-	{
-		IPACMERR("header oversize\n");
-		res = IPACM_FAILURE;
-		goto fail;
-	}
-	else
-	{
-		memcpy(pHeaderDescriptor->hdr[0].hdr,
-					 sCopyHeader.hdr,
-					 sCopyHeader.hdr_len);
-	}
-
-	/* copy client mac_addr to partial header */
-	memcpy(&pHeaderDescriptor->hdr[0].hdr[eth2_ofst_v4], mac_addr,
-					 IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
-
-	pHeaderDescriptor->commit = true;
-	pHeaderDescriptor->num_hdrs = 1;
-
-	memset(pHeaderDescriptor->hdr[0].name, 0,
-				 sizeof(pHeaderDescriptor->hdr[0].name));
-
-	snprintf(index,sizeof(index), "%d", ipa_if_num);
-	strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
-	if ( strlcat(pHeaderDescriptor->hdr[0].name, IPA_WAN_PARTIAL_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
-	{
-		IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
-		res = IPACM_FAILURE;
-		goto fail;
-	}
-
-	pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
-	pHeaderDescriptor->hdr[0].hdr_hdl = -1;
-	pHeaderDescriptor->hdr[0].is_partial = 0;
-	pHeaderDescriptor->hdr[0].status = -1;
-
-	if (m_header.AddHeader(pHeaderDescriptor) == false ||
-			pHeaderDescriptor->hdr[0].status != 0)
-	{
-		IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
-		res = IPACM_FAILURE;
-		goto fail;
-	}
-	else
-	{
-	        hdr_hdl_sta_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
-		header_set_v4 = true;
-	        IPACMDBG_H("add full header name: %s (%x)\n", pHeaderDescriptor->hdr[0].name, pHeaderDescriptor->hdr[0].hdr_hdl);
-	}
-
-	/* copy ipv4 full header to each TX endpoint property*/
-	for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
-	{
-	   if(tx_prop->tx[tx_index].ip==IPA_IP_v4)
-           {
-		  memcpy(tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].name,
-					 sizeof(tx_prop->tx[tx_index].hdr_name));
-		                 IPACMDBG_H("replace full header name: %s (%x) in tx:%d\n", tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].hdr_hdl,tx_index);
-                           }
-	               }
-		        break;
-		   }
-	}
-
-	/* copy partial header for v6 */
-        for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
-	{
-		   if(tx_prop->tx[cnt].ip == IPA_IP_v6)
-		   {
-	                 IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
-	                 memset(&sCopyHeader, 0, sizeof(sCopyHeader));
-	                 memcpy(sCopyHeader.name,
-				           tx_prop->tx[cnt].hdr_name,
-				                   sizeof(sCopyHeader.name));
-
-			IPACMDBG_H("header name: %s from tx: %d\n", sCopyHeader.name,cnt);
-			if (m_header.CopyHeader(&sCopyHeader) == false)
+		index = get_wan_client_index_ipv4(wan_v4_addr_gw);
+		if (index != IPACM_INVALID_INDEX)
+		{
+			IPACMDBG_H("Matched client index: %d\n", index);
+			IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+					 get_client_memptr(wan_client, index)->mac[0],
+					 get_client_memptr(wan_client, index)->mac[1],
+					 get_client_memptr(wan_client, index)->mac[2],
+					 get_client_memptr(wan_client, index)->mac[3],
+					 get_client_memptr(wan_client, index)->mac[4],
+					 get_client_memptr(wan_client, index)->mac[5]);
+			if(get_client_memptr(wan_client, index)->ipv4_header_set)
 			{
-				IPACMERR("ioctl copy header failed");
-				res = IPACM_FAILURE;
-				goto fail;
-			}
-
-			if(sCopyHeader.is_eth2_ofst_valid == false)
-			{
-				eth2_ofst_v6 = 0;
+				hdr_hdl_sta_v4 = get_client_memptr(wan_client, index)->hdr_hdl_v4;
+				header_set_v4 = true;
+				IPACMDBG_H("add full ipv4 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v4);
 			}
 			else
 			{
-				eth2_ofst_v6 = sCopyHeader.eth2_ofst;
+				IPACMERR(" wan-client got ipv4 however didn't construct complete ipv4 header \n");
+				return IPACM_FAILURE;
 			}
-                     IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
-                     if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
-                     {
-                     	IPACMERR("header oversize\n");
-                     	res = IPACM_FAILURE;
-                     	goto fail;
-                     }
-                     else
-                     {
-                     	memcpy(pHeaderDescriptor->hdr[0].hdr,
-                     				 sCopyHeader.hdr,
-                     				 sCopyHeader.hdr_len);
-                     }
 
-	                 /* copy client mac_addr to partial header */
-	                 memcpy(&pHeaderDescriptor->hdr[0].hdr[eth2_ofst_v6], mac_addr,
-	                 				 IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
-	                 pHeaderDescriptor->commit = true;
-	                 pHeaderDescriptor->num_hdrs = 1;
-
-	                 memset(pHeaderDescriptor->hdr[0].name, 0,
-	                 			 sizeof(pHeaderDescriptor->hdr[0].name));
-
-					 snprintf(index,sizeof(index), "%d", ipa_if_num);
-					 strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
-					 if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WAN_PARTIAL_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
-					 {
-					 	IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
-					 	res = IPACM_FAILURE;
-					 	goto fail;
-					 }
-	                 pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
-	                 pHeaderDescriptor->hdr[0].hdr_hdl = -1;
-	                 pHeaderDescriptor->hdr[0].is_partial = 0;
-	                 pHeaderDescriptor->hdr[0].status = -1;
-
-	                 if (m_header.AddHeader(pHeaderDescriptor) == false ||
-	                 		pHeaderDescriptor->hdr[0].status != 0)
-	                 {
-	                 	IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
-	                 	res = IPACM_FAILURE;
-	                 	goto fail;
-	                 }
-	                 else
-	                 {
-			   header_set_v6 = true;
-	                   hdr_hdl_sta_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
-	                   IPACMDBG_H("add full header name: %s (%x)\n", pHeaderDescriptor->hdr[0].name, pHeaderDescriptor->hdr[0].hdr_hdl);
-	                 }
-	                 /* copy ipv6 full header to each TX endpoint property*/
-	                 for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
-	                 {
-	                    if(tx_prop->tx[tx_index].ip==IPA_IP_v6)
-                        {
-	                 	  memcpy(tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].name,
-	                 				 sizeof(tx_prop->tx[tx_index].hdr_name));
-	                 	  IPACMDBG_H("replace full header name: %s (%x) in tx:%d\n", tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].hdr_hdl,tx_index);
-                        }
-                     }
-	                 break;
-	        }
+			if(get_client_memptr(wan_client, index)->ipv6_header_set)
+			{
+				hdr_hdl_sta_v6 = get_client_memptr(wan_client, index)->hdr_hdl_v6;
+				header_set_v6 = true;
+				IPACMDBG_H("add full ipv6 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v6);
+			}
+			else
+			{
+				IPACMERR(" wan-client got ipv6 however didn't construct complete ipv6 header \n");
+				return IPACM_FAILURE;
+			}
+		}
+		else
+		{
+			IPACMDBG_H(" currently can't find matched wan-client's MAC-addr, waiting for header construction\n");
+			return IPACM_SUCCESS;
+		}
 	}
 
-    /* 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);
 	}
-
-fail:
-	free(pHeaderDescriptor);
-
 	return res;
 }
 
@@ -1697,25 +1601,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 +1694,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 +1802,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 +1813,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,
@@ -2785,7 +2724,7 @@
 
 	if(iptype == IPA_IP_v4)
 	{
-		if(modem_ipv4_pdn_index == 0)	//install ipv4 default modem DL filtering rules only once
+		if(modem_ipv4_pdn_index == 0)	/* install ipv4 default modem DL filtering rules only once */
 		{
 			/* reset the num_v4_flt_rule*/
 			IPACM_Wan::num_v4_flt_rule = 0;
@@ -2794,7 +2733,7 @@
 	}
 	else if(iptype == IPA_IP_v6)
 	{
-		if(modem_ipv6_pdn_index == 0)	//install ipv6 default modem DL filtering rules only once
+		if(modem_ipv6_pdn_index == 0)	/* install ipv6 default modem DL filtering rules only once */
 		{
 			/* reset the num_v6_flt_rule*/
 			IPACM_Wan::num_v6_flt_rule = 0;
@@ -3450,7 +3389,7 @@
 	uint32_t tx_index;
 	ipacm_cmd_q_data evt_data;
 
-	IPACMDBG_H("got handle_route_del_evt with ip-family:%d \n", iptype);
+	IPACMDBG_H("got handle_route_del_evt for STA-mode with ip-family:%d \n", iptype);
 
 	if(tx_prop == NULL)
 	{
@@ -3956,24 +3895,6 @@
 		IPACMDBG_H("finished delete default v6 filtering rules\n ");
 	}
 
-	/* delete the complete header for STA mode*/
-    if((header_set_v4 == true) || (header_set_v6 == true))
-    {
-        if (m_header.DeleteHeaderHdl(hdr_hdl_sta_v4) == false)
-		{
-		    IPACMERR("ErrorDeleting STA header for v4, aborting...\n");
-		  	res = IPACM_FAILURE;
-		  	goto fail;
-		}
-
-		if (m_header.DeleteHeaderHdl(hdr_hdl_sta_v6) == false)
-		{
-		    IPACMERR("ErrorDeleting STA header for v6, aborting...\n");
-			res = IPACM_FAILURE;
-			goto fail;
-		}
-	}
-
 fail:
 	if (tx_prop != NULL)
 	{
@@ -4159,24 +4080,6 @@
 		handle_software_routing_disable();
 	}
 
-	/* delete the complete header for STA mode*/
-	if((header_set_v4 == true) || (header_set_v6 == true))
-	{
-		if (m_header.DeleteHeaderHdl(hdr_hdl_sta_v4) == false)
-		{
-			IPACMERR("ErrorDeleting STA header for v4, aborting...\n");
-			res = IPACM_FAILURE;
-			goto fail;
-		}
-
-		if (m_header.DeleteHeaderHdl(hdr_hdl_sta_v6) == false)
-		{
-			IPACMERR("ErrorDeleting STA header for v6, aborting...\n");
-			res = IPACM_FAILURE;
-			goto fail;
-		}
-	}
-
 fail:
 	if (tx_prop != NULL)
 	{
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 4731641..fd957a4 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -737,10 +737,13 @@
 		{
 			handle_SCC_MCC_switch(IPA_IP_v4);
 			handle_SCC_MCC_switch(IPA_IP_v6);
+			eth_bridge_handle_wlan_SCC_MCC_switch(IPA_IP_v4);
+			eth_bridge_handle_wlan_SCC_MCC_switch(IPA_IP_v6);
 		}
 		else
 		{
 			handle_SCC_MCC_switch(ip_type);
+			eth_bridge_handle_wlan_SCC_MCC_switch(ip_type);
 		}
 		break;
 
@@ -750,13 +753,37 @@
 		{
 			handle_SCC_MCC_switch(IPA_IP_v4);
 			handle_SCC_MCC_switch(IPA_IP_v6);
+			eth_bridge_handle_wlan_SCC_MCC_switch(IPA_IP_v4);
+			eth_bridge_handle_wlan_SCC_MCC_switch(IPA_IP_v6);
 		}
 		else
 		{
 			handle_SCC_MCC_switch(ip_type);
+			eth_bridge_handle_wlan_SCC_MCC_switch(ip_type);
 		}
 		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;
 	}
@@ -4287,8 +4314,18 @@
 				res = IPACM_FAILURE;
 				goto fail;
 			}
+			/* Handle MCC Mode case */
+			if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+			{
+				IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+						tx_prop->tx[i].alt_dst_pipe);
+				rt_rule.rule.dst = tx_prop->tx[i].alt_dst_pipe;
+			}
+			else
+			{
+				rt_rule.rule.dst = tx_prop->tx[i].dst_pipe;
+			}
 
-			rt_rule.rule.dst = tx_prop->tx[i].dst_pipe;
 			memcpy(&rt_rule.rule.attrib, &tx_prop->tx[i].attrib, sizeof(rt_rule.rule.attrib));
 			if(src == SRC_WLAN)	//src is WLAN means packet is from WLAN
 			{
@@ -4825,3 +4862,257 @@
 	}
 	return;
 }
+
+void IPACM_Wlan::eth_bridge_handle_wlan_SCC_MCC_switch(ipa_ip_type iptype)
+{
+
+	for (int i= 0; i < IPACM_Lan::num_wlan_client; i++)
+	{
+		if (IPACM_Lan::eth_bridge_wlan_client[i].ipa_if_num == ipa_if_num)
+		{
+			if (IPACM_Lan::wlan_to_wlan_hdr_proc_ctx.valid == true)
+			{
+				if (eth_bridge_modify_wlan_rt_rule(IPACM_Lan::eth_bridge_wlan_client[i].mac, SRC_WLAN, iptype) == IPACM_FAILURE)
+				{
+					IPACMDBG_H("SCC/MCC switch is failed for iptype: %d src_iface: %d \n", iptype, SRC_WLAN);
+					return;
+				}
+			}
+			if (IPACM_Lan::usb_to_wlan_hdr_proc_ctx.valid == true)
+			{
+				if (eth_bridge_modify_wlan_rt_rule(IPACM_Lan::eth_bridge_wlan_client[i].mac, SRC_USB, iptype) == IPACM_FAILURE)
+				{
+					IPACMDBG_H("SCC/MCC switch is failed for iptype: %d src_iface: %d \n", iptype, SRC_USB);
+					return;
+				}
+			}
+		}
+	}
+
+	IPACMDBG_H("SCC/MCC switch is successful for iptype: %d\n", iptype);
+}
+
+int IPACM_Wlan::eth_bridge_modify_wlan_rt_rule(uint8_t* mac, eth_bridge_src_iface src_iface, ipa_ip_type iptype)
+{
+	struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_mdfy *rt_rule_entry;
+	uint32_t index = 0, num_rt_rule = 0, position;
+
+	if (tx_prop == NULL)
+	{
+		IPACMDBG_H("No tx properties \n");
+		return IPACM_FAILURE;
+	}
+
+	if (mac == NULL)
+	{
+		IPACMERR("Client MAC address is empty.\n");
+		return IPACM_FAILURE;
+	}
+
+	IPACMDBG_H("Receive WLAN client MAC 0x%02x%02x%02x%02x%02x%02x.\n",
+			mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+	if (iptype == IPA_IP_v4)
+	{
+		num_rt_rule = each_client_rt_rule_count_v4;
+	}
+	else
+	{
+		num_rt_rule = each_client_rt_rule_count_v6;
+	}
+
+	if (src_iface == SRC_WLAN)
+	{
+		if (iptype == IPA_IP_v4)
+		{
+			for (index = 0; index < wlan_client_rt_from_wlan_info_count_v4; index++)
+			{
+				if (memcmp(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v4)->mac, mac,
+					sizeof(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v4)->mac)) == 0)
+				{
+					position = index;
+					IPACMDBG_H("The client is found at position %d.\n", position);
+					break;
+				}
+			}
+			if (index == wlan_client_rt_from_wlan_info_count_v4)
+			{
+				IPACMERR("The client is not found.\n");
+				return IPACM_FAILURE;
+			}
+		}
+		else
+		{
+			for (index =0 ; index < wlan_client_rt_from_wlan_info_count_v6; index++)
+			{
+				if (memcmp(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v6)->mac, mac,
+					sizeof(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v6)->mac)) == 0)
+				{
+					position = index;
+					IPACMDBG_H("The client is found at position %d.\n", position);
+					break;
+				}
+			}
+			if (index == wlan_client_rt_from_wlan_info_count_v6)
+			{
+				IPACMERR("The client is not found.\n");
+				return IPACM_FAILURE;
+			}
+		}
+	}
+	else
+	{
+		if (iptype == IPA_IP_v4)
+		{
+			for (index = 0; index < wlan_client_rt_from_usb_info_count_v4; index++)
+			{
+				if (memcmp(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v4)->mac, mac,
+					sizeof(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v4)->mac)) == 0)
+				{
+					position = index;
+					IPACMDBG_H("The client is found at position %d.\n", position);
+					break;
+				}
+			}
+			if (index == wlan_client_rt_from_usb_info_count_v4)
+			{
+				IPACMERR("The client is not found.\n");
+				return IPACM_FAILURE;
+			}
+		}
+		else
+		{
+			for (index = 0; index < wlan_client_rt_from_usb_info_count_v6; index++)
+			{
+				if (memcmp(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v6)->mac, mac,
+					sizeof(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v6)->mac)) == 0)
+				{
+					position = index;
+					IPACMDBG_H("The client is found at position %d.\n", position);
+					break;
+				}
+			}
+			if (index == wlan_client_rt_from_usb_info_count_v6)
+			{
+				IPACMERR("The client is not found.\n");
+				return IPACM_FAILURE;
+			}
+		}
+	}
+
+	rt_rule = (struct ipa_ioc_mdfy_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_mdfy_rt_rule) +
+			(num_rt_rule) * sizeof(struct ipa_rt_rule_mdfy));
+
+	if (rt_rule == NULL)
+	{
+		IPACMERR("Unable to allocate memory for modify rt rule\n");
+		return IPACM_FAILURE;
+	}
+	IPACMDBG("Allocated memory for %d rules successfully\n", num_rt_rule);
+
+	rt_rule->commit = 1;
+	rt_rule->num_rules = 0;
+	rt_rule->ip = iptype;
+
+	for (index = 0; index < tx_prop->num_tx_props; index++)
+	{
+		if (tx_prop->tx[index].ip == iptype)
+		{
+			if (rt_rule->num_rules >= num_rt_rule)
+			{
+				IPACMERR("Number of routing rules exceeds limit.\n");
+				free(rt_rule);
+				return IPACM_FAILURE;
+			}
+
+			rt_rule_entry = &rt_rule->rules[rt_rule->num_rules];
+
+			if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+			{
+				IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+						tx_prop->tx[index].alt_dst_pipe);
+				rt_rule_entry->rule.dst = tx_prop->tx[index].alt_dst_pipe;
+			}
+			else
+			{
+				rt_rule_entry->rule.dst = tx_prop->tx[index].dst_pipe;
+			}
+
+			rt_rule_entry->rule.hdr_hdl = 0;
+
+			if (src_iface == SRC_WLAN)
+			{
+				rt_rule_entry->rule.hdr_proc_ctx_hdl =
+						IPACM_Lan::wlan_to_wlan_hdr_proc_ctx.proc_ctx_hdl;
+			}
+			else
+			{
+				rt_rule_entry->rule.hdr_proc_ctx_hdl =
+						IPACM_Lan::usb_to_wlan_hdr_proc_ctx.proc_ctx_hdl;
+			}
+
+			memcpy(&rt_rule_entry->rule.attrib,
+					&tx_prop->tx[index].attrib,
+					sizeof(rt_rule_entry->rule.attrib));
+
+			if (src_iface == SRC_WLAN)	//src is WLAN means packet is from WLAN
+			{
+				if (IPACM_Lan::wlan_hdr_type == IPA_HDR_L2_ETHERNET_II)
+				{
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+				}
+				else
+				{
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+				}
+			}
+			else	//packet is from USB
+			{
+				if (IPACM_Lan::usb_hdr_type == IPA_HDR_L2_ETHERNET_II)
+				{
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+				}
+				else
+				{
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+				}
+			}
+			memcpy(rt_rule_entry->rule.attrib.dst_mac_addr, mac,
+					sizeof(rt_rule_entry->rule.attrib.dst_mac_addr));
+			memset(rt_rule_entry->rule.attrib.dst_mac_addr_mask, 0xFF,
+					sizeof(rt_rule_entry->rule.attrib.dst_mac_addr_mask));
+
+			rt_rule_entry->rt_rule_hdl =
+					eth_bridge_get_client_rt_info_ptr(position, src_iface, iptype)->rt_rule_hdl[rt_rule->num_rules];
+			IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", index,
+				eth_bridge_get_client_rt_info_ptr(position, src_iface, iptype)->rt_rule_hdl[rt_rule->num_rules], iptype);
+
+			rt_rule->num_rules++;
+		}
+	}
+
+	if (rt_rule->num_rules > 0)
+	{
+		if (false == m_routing.ModifyRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule modify failed!\n");
+			free(rt_rule);
+			return IPACM_FAILURE;
+		}
+		if (false == m_routing.Commit(iptype))
+		{
+			IPACMERR("Routing rule modify commit failed!\n");
+			free(rt_rule);
+			return IPACM_FAILURE;
+		}
+		IPACMDBG("Routing rule modified successfully \n");
+	}
+
+	if (rt_rule)
+	{
+		free(rt_rule);
+	}
+	return IPACM_SUCCESS;
+}
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>