Merge "IPACM: fix the configuration file missing issue"
diff --git a/ipacm/inc/IPACM_Config.h b/ipacm/inc/IPACM_Config.h
index 69c3412..5a79849 100644
--- a/ipacm/inc/IPACM_Config.h
+++ b/ipacm/inc/IPACM_Config.h
@@ -113,24 +113,90 @@
 
 	bool ipacm_odu_enable;
 
+	bool ipacm_odu_embms_enable;
+
 	int ipa_nat_iface_entries;
 
+	/* Max valid rm entry */
+	int ipa_max_valid_rm_entry;
+
 	/* Store SW-enable or not */
 	bool ipa_sw_rt_enable;
 
+	/* Store the flt rule count for each producer client*/
+	int flt_rule_count_v4[IPA_CLIENT_CONS - IPA_CLIENT_PROD];
+	int flt_rule_count_v6[IPA_CLIENT_CONS - IPA_CLIENT_PROD];
+
 	/* IPACM routing table name for v4/v6 */
 	struct ipa_ioc_get_rt_tbl rt_tbl_lan_v4, rt_tbl_wan_v4, rt_tbl_default_v4, rt_tbl_v6, rt_tbl_wan_v6;
 	struct ipa_ioc_get_rt_tbl rt_tbl_wan_dl;
 	struct ipa_ioc_get_rt_tbl rt_tbl_lan2lan_v4, rt_tbl_lan2lan_v6;
-
 	struct ipa_ioc_get_rt_tbl rt_tbl_odu_v4, rt_tbl_odu_v6;
-
 	struct ipa_ioc_get_rt_tbl rt_tbl_eth_bridge_usb_wlan_v4, rt_tbl_eth_bridge_wlan_wlan_v4;
 	struct ipa_ioc_get_rt_tbl rt_tbl_eth_bridge_usb_wlan_v6, rt_tbl_eth_bridge_wlan_wlan_v6;
 
+	bool isMCC_Mode;
+
 	/* To return the instance */
 	static IPACM_Config* GetInstance();
 
+	inline void increaseFltRuleCount(int index, ipa_ip_type iptype, int increment)
+	{
+		if((index >= IPA_CLIENT_CONS - IPA_CLIENT_PROD) || (index < 0))
+		{
+			IPACMERR("Index is out of range: %d.\n", index);
+			return;
+		}
+		if(iptype == IPA_IP_v4)
+		{
+			flt_rule_count_v4[index] += increment;
+			IPACMDBG_H("Now num of v4 flt rules on client %d is %d.\n", index, flt_rule_count_v4[index]);
+		}
+		else
+		{
+			flt_rule_count_v6[index] += increment;
+			IPACMDBG_H("Now num of v6 flt rules on client %d is %d.\n", index, flt_rule_count_v6[index]);
+		}
+		return;
+	}
+
+	inline void decreaseFltRuleCount(int index, ipa_ip_type iptype, int decrement)
+	{
+		if((index >= IPA_CLIENT_CONS - IPA_CLIENT_PROD) || (index < 0))
+		{
+			IPACMERR("Index is out of range: %d.\n", index);
+			return;
+		}
+		if(iptype == IPA_IP_v4)
+		{
+			flt_rule_count_v4[index] -= decrement;
+			IPACMDBG_H("Now num of v4 flt rules on client %d is %d.\n", index, flt_rule_count_v4[index]);
+		}
+		else
+		{
+			flt_rule_count_v6[index] -= decrement;
+			IPACMDBG_H("Now num of v6 flt rules on client %d is %d.\n", index, flt_rule_count_v6[index]);
+		}
+		return;
+	}
+
+	inline int getFltRuleCount(int index, ipa_ip_type iptype)
+	{
+		if((index >= IPA_CLIENT_CONS - IPA_CLIENT_PROD) || (index < 0))
+		{
+			IPACMERR("Index is out of range: %d.\n", index);
+			return -1;
+		}
+		if(iptype == IPA_IP_v4)
+		{
+			return flt_rule_count_v4[index];
+		}
+		else
+		{
+			return flt_rule_count_v6[index];
+		}
+	}
+
 	inline int GetAlgPortCnt()
 	{
 		return ipa_num_alg_ports;
diff --git a/ipacm/inc/IPACM_Conntrack_NATApp.h b/ipacm/inc/IPACM_Conntrack_NATApp.h
index 7c97225..1fb12bf 100644
--- a/ipacm/inc/IPACM_Conntrack_NATApp.h
+++ b/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -52,6 +52,7 @@
 	uint32_t target_ip;
 	uint16_t target_port;
 
+	uint16_t public_ip;
 	uint16_t public_port;
 
 	u_int8_t  protocol;
@@ -74,6 +75,7 @@
 	nat_table_entry *cache;
 	nat_table_entry temp[MAX_TEMP_ENTRIES];
 	uint32_t pub_ip_addr;
+	uint32_t pub_ip_addr_pre;
 	uint32_t nat_table_hdl;
 
 	int curCnt, max_entries;
@@ -118,6 +120,7 @@
 	void UpdateTcpUdpTo(uint32_t, int proto);
 
 	void AddTempEntry(const nat_table_entry *);
+	void CacheEntry(const nat_table_entry *);
 	void DeleteTempEntry(const nat_table_entry *);
 	void FlushTempEntries(uint32_t, bool);
 };
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index 78c6b02..37f3ff4 100644
--- a/ipacm/inc/IPACM_Defs.h
+++ b/ipacm/inc/IPACM_Defs.h
@@ -1,4 +1,4 @@
-/* 
+/*
 Copyright (c) 2013, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -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
@@ -177,6 +177,9 @@
 	IPA_ETH_BRIDGE_WLAN_CLIENT_DEL_EVENT,     /* 47 ipacm_event_data_mac */
 	IPA_ETH_BRIDGE_HDR_PROC_CTX_SET_EVENT,    /* 48 ipacm_event_data_fid */
 	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;
 
@@ -198,6 +201,12 @@
 	UNKNOWN_IF
 } ipacm_iface_type;
 
+typedef enum
+{
+	ROUTER = 0,
+	BRIDGE
+} ipacm_iface_mode;
+
 typedef struct
 {
 	struct nf_conntrack *ct;
@@ -208,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;
 
@@ -231,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];
@@ -263,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_Iface.h b/ipacm/inc/IPACM_Iface.h
index f661974..278ed24 100644
--- a/ipacm/inc/IPACM_Iface.h
+++ b/ipacm/inc/IPACM_Iface.h
@@ -144,11 +144,6 @@
 	/* software routing disable */
 	virtual int handle_software_routing_disable(void);
 
-	/* used to get filtering rule index in table */
-	int flt_rule_count_v4;
-
-	int flt_rule_count_v6;
-
 private:
 
 	static const char *DEVICE_NAME;
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
index 505f426..e520d58 100644
--- a/ipacm/inc/IPACM_Lan.h
+++ b/ipacm/inc/IPACM_Lan.h
@@ -53,7 +53,8 @@
 #define IPA_WAN_DEFAULT_FILTER_RULE_HANDLES  1
 #define IPA_PRIV_SUBNET_FILTER_RULE_HANDLES  3
 #define IPA_NUM_ODU_ROUTE_RULES 2
-#define MAX_WAN_UL_FILTER_RULES 20
+#define MAX_WAN_UL_FILTER_RULES MAX_NUM_EXT_PROPS
+#define NUM_IPV4_ICMP_FLT_RULE 1
 #define NUM_IPV6_PREFIX_FLT_RULE 1
 #define NUM_IPV6_ICMP_FLT_RULE 1
 
@@ -185,7 +186,9 @@
 
 	int del_lan2lan_hdr(ipa_ip_type iptype, uint32_t hdr_hdl);
 
+	int handle_cradle_wan_mode_switch(bool is_wan_bridge_mode);
 
+	int install_ipv4_icmp_flt_rule();
 
 	static ipa_hdr_l2_type usb_hdr_type;
 	static ipa_hdr_l2_type wlan_hdr_type;
@@ -290,6 +293,7 @@
 
 	virtual void install_tcp_ctl_flt_rule(ipa_ip_type iptype);
 
+	uint32_t ipv4_icmp_flt_rule_hdl[NUM_IPV4_ICMP_FLT_RULE];
 	uint32_t tcp_ctl_flt_rule_hdl_v4[NUM_TCP_CTL_FLT_RULE];
 	uint32_t tcp_ctl_flt_rule_hdl_v6[NUM_TCP_CTL_FLT_RULE];
 
@@ -303,6 +307,10 @@
 
 	uint32_t if_ipv4_subnet;
 
+	/* expected modem UL rules starting index */
+	int exp_index_v4;
+	int exp_index_v6;
+
 private:
 
 	/* dynamically allocate lan iface's unicast routing rule structure */
diff --git a/ipacm/inc/IPACM_Log.h b/ipacm/inc/IPACM_Log.h
index f2ed773..131aab8 100644
--- a/ipacm/inc/IPACM_Log.h
+++ b/ipacm/inc/IPACM_Log.h
@@ -65,12 +65,18 @@
 void ipacm_log_send( void * user_data);
 
 static char buffer_send[MAX_BUF_LEN];
+static char dmesg_cmd[MAX_BUF_LEN];
 
 #define PERROR(fmt)   memset(buffer_send, 0, MAX_BUF_LEN);\
 					  snprintf(buffer_send,MAX_BUF_LEN,"%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
 					  ipacm_log_send (buffer_send); \
                       perror(fmt);
 
+#define IPACMDBG_DMESG(fmt, ...) memset(buffer_send, 0, MAX_BUF_LEN);\
+							     snprintf(buffer_send,MAX_BUF_LEN,"%s:%d %s: " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);\
+								 memset(dmesg_cmd, 0, MAX_BUF_LEN);\
+								 snprintf(dmesg_cmd, MAX_BUF_LEN, "echo %s > /dev/kmsg", buffer_send);\
+								 system(dmesg_cmd);
 #define IPACMERR(fmt, ...)	memset(buffer_send, 0, MAX_BUF_LEN);\
 							snprintf(buffer_send,MAX_BUF_LEN,"ERR: %s:%d %s() " fmt, __FILE__,  __LINE__, __FUNCTION__, ##__VA_ARGS__);\
 							ipacm_log_send (buffer_send);\
diff --git a/ipacm/inc/IPACM_Routing.h b/ipacm/inc/IPACM_Routing.h
index ca7a5fd..4f5488f 100644
--- a/ipacm/inc/IPACM_Routing.h
+++ b/ipacm/inc/IPACM_Routing.h
@@ -1,4 +1,4 @@
-/* 
+/*
 Copyright (c) 2013, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -66,6 +66,8 @@
 	bool DeviceNodeIsOpened();
 	bool DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip);
 
+	bool ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *);
+
 private:
 	static const char *DEVICE_NAME;
 	int m_fd; /* File descriptor of the IPA device node /dev/ipa */
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
index 381f792..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,6 +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;
@@ -202,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;
@@ -277,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);
 
@@ -324,6 +361,9 @@
 
 	bool is_global_ipv6_addr(uint32_t* ipv6_addr);
 
+	void handle_wlan_SCC_MCC_switch(bool, ipa_ip_type);
+	void handle_wan_client_SCC_MCC_switch(bool, ipa_ip_type);
+
 	int m_fd_ipa;
 
 };
diff --git a/ipacm/inc/IPACM_Wlan.h b/ipacm/inc/IPACM_Wlan.h
index 6d602a6..fb5555a 100644
--- a/ipacm/inc/IPACM_Wlan.h
+++ b/ipacm/inc/IPACM_Wlan.h
@@ -320,6 +320,13 @@
 
 	/*handle reset wifi-client rt-rules */
 	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..53cabad 100644
--- a/ipacm/inc/IPACM_Xml.h
+++ b/ipacm/inc/IPACM_Xml.h
@@ -77,6 +77,7 @@
 #define system_TAG                           "system"
 #define ODU_TAG                              "ODUCFG"
 #define ODUMODE_TAG                          "Mode"
+#define ODUEMBMS_OFFLOAD_TAG                 "eMBMS_offload"
 #define ODU_ROUTER_TAG                       "router"
 #define ODU_BRIDGE_TAG                       "bridge"
 #define IPACMCFG_TAG                         "IPACM"
@@ -84,6 +85,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 +98,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"
@@ -267,6 +271,7 @@
 	int nat_max_entries;
   bool odu_enable;
   bool router_mode_enable;
+  bool odu_embms_enable;
 } IPACM_conf_t;  
 
 /* This function read IPACM XML configuration*/
diff --git a/ipacm/src/Android.mk b/ipacm/src/Android.mk
index 7a9065b..d9f3145 100644
--- a/ipacm/src/Android.mk
+++ b/ipacm/src/Android.mk
@@ -28,10 +28,10 @@
 LOCAL_CFLAGS += -DFEATURE_IPA_ANDROID
 LOCAL_CFLAGS += -DDEBUG
 
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_CFLAGS += -include bionic/libc/kernel/arch-arm/asm/posix_types.h
-LOCAL_CFLAGS += -include bionic/libc/kernel/arch-arm/asm/byteorder.h
-endif
+filetoadd = bionic/libc/kernel/arch-arm/asm/posix_types.h
+LOCAL_CFLAGS += $(shell if [ -a $(filetoadd) ] ; then echo -include $(filetoadd) ; fi ;)
+filetoadd = bionic/libc/kernel/arch-arm/asm/byteorder.h
+LOCAL_CFLAGS += $(shell if [ -a $(filetoadd) ] ; then echo -include $(filetoadd) ; fi ;)
 
 LOCAL_SRC_FILES := IPACM_Main.cpp \
 		IPACM_EvtDispatcher.cpp \
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
index 3fd3b55..7ed3ade 100644
--- a/ipacm/src/IPACM_Config.cpp
+++ b/ipacm/src/IPACM_Config.cpp
@@ -63,6 +63,8 @@
 	ipa_nat_max_entries = 0;
 	ipa_nat_iface_entries = 0;
 	ipa_sw_rt_enable = false;
+	isMCC_Mode = false;
+	ipa_max_valid_rm_entry = 0;
 
 	memset(&rt_tbl_default_v4, 0, sizeof(rt_tbl_default_v4));
 	memset(&rt_tbl_lan_v4, 0, sizeof(rt_tbl_lan_v4));
@@ -83,6 +85,9 @@
 
 	qmap_id = ~0;
 
+	memset(flt_rule_count_v4, 0, (IPA_CLIENT_CONS - IPA_CLIENT_PROD)*sizeof(int));
+	memset(flt_rule_count_v6, 0, (IPA_CLIENT_CONS - IPA_CLIENT_PROD)*sizeof(int));
+
 	IPACMDBG_H(" create IPACM_Config constructor\n");
 	return;
 }
@@ -143,7 +148,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)
 		{
@@ -207,8 +214,10 @@
 	/* Find ODU is either router mode or bridge mode*/
 	ipacm_odu_enable = cfg->odu_enable;
 	ipacm_odu_router_mode = cfg->router_mode_enable;
+	ipacm_odu_embms_enable = cfg->odu_embms_enable;
 	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);
 
 	/* Allocate more non-nat entries if the monitored iface dun have Tx/Rx properties */
 	if (pNatIfaces != NULL)
@@ -285,6 +294,9 @@
 	ipa_client_rm_map_tbl[IPA_CLIENT_A2_EMBEDDED_CONS]= IPA_RM_RESOURCE_Q6_CONS;
 	ipa_client_rm_map_tbl[IPA_CLIENT_A2_TETHERED_CONS]= IPA_RM_RESOURCE_Q6_CONS;
 	ipa_client_rm_map_tbl[IPA_CLIENT_APPS_WAN_CONS]= IPA_RM_RESOURCE_Q6_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_ODU_PROD]= IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+	ipa_client_rm_map_tbl[IPA_CLIENT_ODU_EMB_CONS]= IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+	ipa_client_rm_map_tbl[IPA_CLIENT_ODU_TETH_CONS]= IPA_RM_RESOURCE_ODU_ADAPT_CONS;
 
 	/* Create the entries which IPACM wants to add dependencies on */
 	ipa_rm_tbl[0].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
@@ -302,9 +314,28 @@
 	ipa_rm_tbl[2].producer_rm2 = IPA_RM_RESOURCE_USB_PROD;
 	ipa_rm_tbl[2].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
 
+	ipa_rm_tbl[3].producer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+	ipa_rm_tbl[3].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
+	ipa_rm_tbl[3].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
+	ipa_rm_tbl[3].consumer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+
+	ipa_rm_tbl[4].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
+	ipa_rm_tbl[4].consumer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+	ipa_rm_tbl[4].producer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+	ipa_rm_tbl[4].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
+
+	ipa_rm_tbl[5].producer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+	ipa_rm_tbl[5].consumer_rm1 = IPA_RM_RESOURCE_USB_CONS;
+	ipa_rm_tbl[5].producer_rm2 = IPA_RM_RESOURCE_USB_PROD;
+	ipa_rm_tbl[5].consumer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+	ipa_max_valid_rm_entry = 6; /* max is IPA_MAX_RM_ENTRY (6)*/
+
 	IPACMDBG_H(" depend MAP-0 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_Q6_CONS);
 	IPACMDBG_H(" depend MAP-1 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_USB_PROD, IPA_RM_RESOURCE_Q6_CONS);
 	IPACMDBG_H(" depend MAP-2 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_USB_CONS);
+	IPACMDBG_H(" depend MAP-3 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_Q6_CONS);
+	IPACMDBG_H(" depend MAP-4 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_ODU_ADAPT_CONS);
+	IPACMDBG_H(" depend MAP-5 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_USB_CONS);
 
 fail:
 	if (cfg != NULL)
@@ -442,7 +473,7 @@
 		IPACMDBG_H("got %d times default RT routing from A2 \n", ipa_rm_a2_check);
 	}
 
-	for(int i=0;i<IPA_MAX_PRIVATE_SUBNET_ENTRIES;i++)
+	for(int i=0;i<ipa_max_valid_rm_entry;i++)
 	{
 		if(rm1 == ipa_rm_tbl[i].producer_rm1)
 		{
@@ -550,7 +581,7 @@
 		IPACMDBG_H("Left %d times default RT routing from A2 \n", ipa_rm_a2_check);
 	}
 
-	for(int i=0;i<IPA_MAX_PRIVATE_SUBNET_ENTRIES;i++)
+	for(int i=0;i<ipa_max_valid_rm_entry;i++)
 	{
 
 		if(rm1 == ipa_rm_tbl[i].producer_rm1)
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
index d8fe726..9de5911 100644
--- a/ipacm/src/IPACM_ConntrackClient.cpp
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -113,19 +113,6 @@
 		goto IGNORE;
 	}
 
-	if(!CtList->isWanUp())
-	{
-#ifdef IPACM_DEBUG
-		IPACMDBG("Wan is not up, ignoring below connections\n");
-		char buf[1024];
-		nfct_snprintf(buf, sizeof(buf), ct,
-									type, NFCT_O_PLAIN, NFCT_OF_TIME);
-		IPACMDBG("%s\n", buf);
-		IPACMDBG("\n");
-		ParseCTMessage(ct);
-#endif
-		goto IGNORE;
-	}
 #endif
 
 	ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
index 3a2041a..9e66a00 100644
--- a/ipacm/src/IPACM_ConntrackListener.cpp
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -213,6 +213,7 @@
 				if(nat_iface_ipv4_addr[j] == 0)
 				{
 					nat_iface_ipv4_addr[j] = data->ipv4_addr;
+					nat_inst->ResetPwrSaveIf(data->ipv4_addr);
 					nat_inst->FlushTempEntries(data->ipv4_addr, true);
 					break;
 				}
@@ -316,86 +317,101 @@
 
 int IPACM_ConntrackListener::CreateConnTrackThreads(void)
 {
-	 int ret;
-	 pthread_t tcp_thread = 0, udp_thread = 0;
+	int ret;
+	pthread_t tcp_thread = 0, udp_thread = 0;
 
-	 if(isCTReg == false)
-	 {
-
-			if(!tcp_thread)
+	if(isCTReg == false)
+	{
+		if(!tcp_thread)
+		{
+			ret = pthread_create(&tcp_thread, NULL, IPACM_ConntrackClient::TCPRegisterWithConnTrack, NULL);
+			if(0 != ret)
 			{
-				 ret = pthread_create(&tcp_thread, NULL, IPACM_ConntrackClient::TCPRegisterWithConnTrack, NULL);
-				 if(0 != ret)
-				 {
-						IPACMERR("unable to create TCP conntrack event listner thread\n");
-						PERROR("unable to create TCP conntrack\n");
-						return -1;
-				 }
-
-				 IPACMDBG("created TCP conntrack event listner thread\n");
+				IPACMERR("unable to create TCP conntrack event listner thread\n");
+				PERROR("unable to create TCP conntrack\n");
+				return -1;
 			}
 
-			if(!udp_thread)
+			IPACMDBG("created TCP conntrack event listner thread\n");
+			if(pthread_setname_np(tcp_thread, "tcp ct listener") != 0)
 			{
-				 ret = pthread_create(&udp_thread, NULL, IPACM_ConntrackClient::UDPRegisterWithConnTrack, NULL);
-				 if(0 != ret)
-				 {
-						IPACMERR("unable to create UDP conntrack event listner thread\n");
-						PERROR("unable to create UDP conntrack\n");
-						goto error;
-				 }
+				IPACMERR("unable to set thread name\n");
+			}
+		}
 
-				 IPACMDBG("created UDP conntrack event listner thread\n");
+		if(!udp_thread)
+		{
+			ret = pthread_create(&udp_thread, NULL, IPACM_ConntrackClient::UDPRegisterWithConnTrack, NULL);
+			if(0 != ret)
+			{
+				IPACMERR("unable to create UDP conntrack event listner thread\n");
+				PERROR("unable to create UDP conntrack\n");
+				goto error;
 			}
 
-			isCTReg = true;
-	 }
+			IPACMDBG("created UDP conntrack event listner thread\n");
+			if(pthread_setname_np(udp_thread, "udp ct listener") != 0)
+			{
+				IPACMERR("unable to set thread name\n");
+			}
+		}
 
-	 return 0;
+		isCTReg = true;
+	}
+
+	return 0;
 
 error:
-	 return -1;
+	return -1;
 }
 int IPACM_ConntrackListener::CreateNatThreads(void)
 {
-	 int ret;
-	 pthread_t udpcto_thread = 0, to_monitor_thread = 0;
+	int ret;
+	pthread_t udpcto_thread = 0, to_monitor_thread = 0;
 
-	 if(isNatThreadStart == false)
-	 {
+	if(isNatThreadStart == false)
+	{
 
-			if(!udpcto_thread)
+		if(!udpcto_thread)
+		{
+			ret = pthread_create(&udpcto_thread, NULL, IPACM_ConntrackClient::UDPConnTimeoutUpdate, NULL);
+			if(0 != ret)
 			{
-				 ret = pthread_create(&udpcto_thread, NULL, IPACM_ConntrackClient::UDPConnTimeoutUpdate, NULL);
-				 if(0 != ret)
-				 {
-						IPACMERR("unable to create udp conn timeout thread\n");
-						PERROR("unable to create udp conn timeout\n");
-						goto error;
-				 }
-
-				 IPACMDBG("created upd conn timeout thread\n");
+				IPACMERR("unable to create udp conn timeout thread\n");
+				PERROR("unable to create udp conn timeout\n");
+				goto error;
 			}
 
-			if(!to_monitor_thread)
+			IPACMDBG("created upd conn timeout thread\n");
+			if(pthread_setname_np(udpcto_thread, "udp conn timeout") != 0)
 			{
-				ret = pthread_create(&to_monitor_thread, NULL, IPACM_ConntrackClient::TCPUDP_Timeout_monitor, NULL);
-				 if(0 != ret)
-				 {
-						IPACMERR("unable to create tcp/udp timeout monitor thread\n");
-						PERROR("unable to create tcp/udp timeout monitor\n");
-						goto error;
-				 }
+				IPACMERR("unable to set thread name\n");
+			}
+		}
 
-				 IPACMDBG("created tcp/udp timeout monitor thread\n");
+		if(!to_monitor_thread)
+		{
+			ret = pthread_create(&to_monitor_thread, NULL, IPACM_ConntrackClient::TCPUDP_Timeout_monitor, NULL);
+			if(0 != ret)
+			{
+				IPACMERR("unable to create tcp/udp timeout monitor thread\n");
+				PERROR("unable to create tcp/udp timeout monitor\n");
+				goto error;
 			}
 
-			isNatThreadStart = true;
-	 }
-	 return 0;
+			IPACMDBG("created tcp/udp timeout monitor thread\n");
+			if(pthread_setname_np(to_monitor_thread, "tcp udp timeout mtr") != 0)
+			{
+				IPACMERR("unable to set thread name\n");
+			}
+		}
+
+		isNatThreadStart = true;
+	}
+	return 0;
 
 error:
-	 return -1;
+	return -1;
 }
 
 void IPACM_ConntrackListener::TriggerWANDown(uint32_t wan_addr)
@@ -687,11 +703,13 @@
 		 {
 			 IPACMDBG("orig src ip:0x%x equal to wan ip\n",orig_src_ip);
 			 status = IPS_SRC_NAT;
+			 rule.public_ip = wan_ipaddr;
 		 }
 		 else if(orig_dst_ip == wan_ipaddr)
 		 {
 			 IPACMDBG("orig Dst IP:0x%x equal to wan ip\n",orig_dst_ip);
 			 status = IPS_DST_NAT;
+	 	 	 rule.public_ip = wan_ipaddr;
 		 }
 		 else
 		 {
@@ -918,7 +936,12 @@
 			if(TCP_CONNTRACK_ESTABLISHED == tcp_state)
 			{
 				 IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED(%d)\n", tcp_state);
-				 if(isTempEntry)
+				 if(!CtList->isWanUp())
+				 {
+				 	 IPACMDBG("Wan is not up, cache connections\n");
+					 nat_inst->CacheEntry(&rule);
+				 }
+				 else if(isTempEntry)
 				 {
 					 nat_inst->AddTempEntry(&rule);
 				 }
@@ -958,7 +981,12 @@
 			if(NFCT_T_NEW == type)
 			{
 				 IPACMDBG("New UDP connection at time %ld\n", time(NULL));
-				 if(isTempEntry)
+				 if(!CtList->isWanUp())
+				 {
+				 	 IPACMDBG("Wan is not up, cache connections\n");
+					 nat_inst->CacheEntry(&rule);
+				 }
+				 else if(isTempEntry)
 				 {
 					 nat_inst->AddTempEntry(&rule);
 				 }
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
index 3d388f9..0915fda 100644
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -77,24 +77,27 @@
 	memset(cache, 0, size);
 
 	nALGPort = pConfig->GetAlgPortCnt();
-	pALGPorts = (ipacm_alg *)malloc(sizeof(ipacm_alg) * nALGPort);
-	if(pALGPorts == NULL)
+	if(nALGPort > 0)
 	{
-		IPACMERR("Unable to allocate memory for alg prots\n");
-		goto fail;
-	}
-	memset(pALGPorts, 0, sizeof(ipacm_alg) * nALGPort);
+		pALGPorts = (ipacm_alg *)malloc(sizeof(ipacm_alg) * nALGPort);
+		if(pALGPorts == NULL)
+		{
+			IPACMERR("Unable to allocate memory for alg prots\n");
+			goto fail;
+		}
+		memset(pALGPorts, 0, sizeof(ipacm_alg) * nALGPort);
 
-	if(pConfig->GetAlgPorts(nALGPort, pALGPorts) != 0)
-	{
-		IPACMERR("Unable to retrieve ALG prots\n");
-		goto fail;
-	}
+		if(pConfig->GetAlgPorts(nALGPort, pALGPorts) != 0)
+		{
+			IPACMERR("Unable to retrieve ALG prots\n");
+			goto fail;
+		}
 
-	IPACMDBG("Printing %d alg ports information\n", nALGPort);
-	for(int cnt=0; cnt<nALGPort; cnt++)
-	{
-		IPACMDBG("%d: Proto[%d], port[%d]\n", cnt, pALGPorts[cnt].protocol, pALGPorts[cnt].port);
+		IPACMDBG("Printing %d alg ports information\n", nALGPort);
+		for(int cnt=0; cnt<nALGPort; cnt++)
+		{
+			IPACMDBG("%d: Proto[%d], port[%d]\n", cnt, pALGPorts[cnt].protocol, pALGPorts[cnt].port);
+		}
 	}
 
 	return 0;
@@ -126,8 +129,19 @@
 int NatApp::AddTable(uint32_t pub_ip)
 {
 	int ret;
+	int cnt = 0;
+	ipa_nat_ipv4_rule nat_rule;
 	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
 
+	/* Not reset the cache wait it timeout by destroy event */
+#if 0
+	if (pub_ip != pub_ip_addr_pre)
+	{
+		IPACMDBG("Reset the cache because NAT-ipv4 different\n");
+		memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+		curCnt = 0;
+	}
+#endif
 	ret = ipa_nat_add_ipv4_tbl(pub_ip, max_entries, &nat_table_hdl);
 	if(ret)
 	{
@@ -135,17 +149,56 @@
 		return ret;
 	}
 
+	/* Add back the cashed NAT-entry */
+	if (pub_ip == pub_ip_addr_pre)
+	{
+		IPACMDBG("Restore the cache to ipa NAT-table\n");
+		for(cnt = 0; cnt < max_entries; cnt++)
+		{
+			if(cache[cnt].private_ip !=0)
+			{
+				memset(&nat_rule, 0 , sizeof(nat_rule));
+				nat_rule.private_ip = cache[cnt].private_ip;
+				nat_rule.target_ip = cache[cnt].target_ip;
+				nat_rule.target_port = cache[cnt].target_port;
+				nat_rule.private_port = cache[cnt].private_port;
+				nat_rule.public_port = cache[cnt].public_port;
+				nat_rule.protocol = cache[cnt].protocol;
+
+				if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+				{
+					IPACMERR("unable to add the rule delete from cache\n");
+					memset(&cache[cnt], 0, sizeof(cache[cnt]));
+					curCnt--;
+					continue;
+				}
+				cache[cnt].enabled = true;
+
+				IPACMDBG("On wan-iface reset added below rule successfully\n");
+				iptodot("Private IP", nat_rule.private_ip);
+				iptodot("Target IP", nat_rule.target_ip);
+				IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
+				IPACMDBG("Public Port:%d\n", nat_rule.public_port);
+				IPACMDBG("protocol: %d\n", nat_rule.protocol);
+			}
+		}
+	}
+
 	pub_ip_addr = pub_ip;
 	return 0;
 }
 
 void NatApp::Reset()
 {
-	memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+	int cnt = 0;
 
 	nat_table_hdl = 0;
 	pub_ip_addr = 0;
-	curCnt = 0;
+	/* NAT tbl deleted, reset enabled bit */
+	for(cnt = 0; cnt < max_entries; cnt++)
+	{
+		cache[cnt].enabled ==false;
+	}
 }
 
 int NatApp::DeleteTable(uint32_t pub_ip)
@@ -169,6 +222,7 @@
 		return ret;
 	}
 
+	pub_ip_addr_pre = pub_ip_addr;
 	Reset();
 	return 0;
 }
@@ -205,9 +259,7 @@
 	int cnt = 0;
 	IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
 
-	CHK_TBL_HDL();
-
-  IPACMDBG("Received below nat entry for deletion\n");
+	IPACMDBG("Received below nat entry for deletion\n");
 	iptodot("Private IP", rule->private_ip);
 	iptodot("Target IP", rule->target_ip);
 	IPACMDBG("Private Port: %d\t Target Port: %d\t", rule->private_port, rule->target_port);
@@ -226,8 +278,7 @@
 			{
 				if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
 				{
-					IPACMERR("%s() %d\n", __FUNCTION__, __LINE__);
-					return -1;
+					IPACMERR("%s() %d deletion failed\n", __FUNCTION__, __LINE__);
 				}
 
 				IPACMDBG("Deleted Nat entry(%d) Successfully\n", cnt);
@@ -522,7 +573,6 @@
 		}
 	}
 
-	CHK_TBL_HDL();
 
 	for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
 	{
@@ -576,6 +626,8 @@
 
 	for(cnt = 0; cnt < max_entries; cnt++)
 	{
+		IPACMDBG("cache (%d): enable %d, ip 0x%x\n", cnt, cache[cnt].enabled, cache[cnt].private_ip);
+
 		if(cache[cnt].private_ip == client_lan_ip &&
 			 cache[cnt].enabled == false)
 		{
@@ -701,11 +753,14 @@
 		{
 			if(isAdd)
 			{
-				ret = AddEntry(&temp[cnt]);
-				if(ret)
+				if(temp[cnt].public_ip == pub_ip_addr)
 				{
-					IPACMERR("unable to add temp entry: %d\n", ret);
-					continue;
+					ret = AddEntry(&temp[cnt]);
+					if(ret)
+					{
+						IPACMERR("unable to add temp entry: %d\n", ret);
+						continue;
+					}
 				}
 			}
 			memset(&temp[cnt], 0, sizeof(nat_table_entry));
@@ -726,7 +781,6 @@
 		return -1;
 	}
 
-	CHK_TBL_HDL();
 
   for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
   {
@@ -738,27 +792,28 @@
     }
   }
 
-	for(cnt = 0; cnt < max_entries; cnt++)
+  for(cnt = 0; cnt < max_entries; cnt++)
+  {
+	if(cache[cnt].private_ip == ip_addr)
 	{
-		if(cache[cnt].private_ip == ip_addr)
-		{
-
-      if(cache[cnt].enabled == true)
-      {
+		if(cache[cnt].enabled == true)
+      		{
 			if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
 			{
 				IPACMERR("unable to delete the rule\n");
 				continue;
 			}
-      }
-
-			memset(&cache[cnt], 0, sizeof(cache[cnt]));
-      curCnt--;
-		}
+			else
+			{
+				IPACMDBG("won't delete the rule\n");
+				cache[cnt].enabled = false;
+		        }
+	        }
+		IPACMDBG("won't delete the rule for entry %d, enabled %d\n",cnt, cache[cnt].enabled);
 	}
-
+  }
   IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
-	return 0;
+  return 0;
 }
 
 int NatApp::DelEntriesOnSTAClntDiscon(uint32_t ip_addr)
@@ -772,7 +827,6 @@
 		return -1;
 	}
 
-	CHK_TBL_HDL();
 
 	for(cnt = 0; cnt < max_entries; cnt++)
 	{
@@ -795,3 +849,61 @@
 	IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
 	return 0;
 }
+
+void NatApp::CacheEntry(const nat_table_entry *rule)
+{
+	int cnt;
+	if(rule->private_ip == 0 ||
+		 rule->target_ip == 0 ||
+		 rule->private_port == 0  ||
+		 rule->target_port == 0 ||
+		 rule->protocol == 0)
+	{
+		IPACMERR("Invalid Connection, ignoring it\n");
+		return;
+	}
+
+	if(!ChkForDup(rule))
+	{
+		for(; cnt < max_entries; cnt++)
+		{
+			if(cache[cnt].private_ip == 0 &&
+				 cache[cnt].target_ip == 0 &&
+				 cache[cnt].private_port == 0  &&
+				 cache[cnt].target_port == 0 &&
+				 cache[cnt].protocol == 0)
+			{
+				break;
+			}
+		}
+
+		if(max_entries == cnt)
+		{
+			IPACMERR("Error: Unable to add, reached maximum rules\n");
+			return;
+		}
+		else
+		{
+			cache[cnt].enabled = false;
+			cache[cnt].rule_hdl = 0;
+			cache[cnt].private_ip = rule->private_ip;
+			cache[cnt].target_ip = rule->target_ip;
+			cache[cnt].target_port = rule->target_port;
+			cache[cnt].private_port = rule->private_port;
+			cache[cnt].protocol = rule->protocol;
+			cache[cnt].timestamp = 0;
+			cache[cnt].public_port = rule->public_port;
+			cache[cnt].dst_nat = rule->dst_nat;
+			curCnt++;
+		}
+
+	}
+	else
+	{
+		IPACMERR("Duplicate rule. Ignore it\n");
+		return;
+	}
+
+	IPACMDBG("Cached rule(%d) successfully\n", cnt);
+	return;
+}
diff --git a/ipacm/src/IPACM_Iface.cpp b/ipacm/src/IPACM_Iface.cpp
index 2494e99..0606ab4 100644
--- a/ipacm/src/IPACM_Iface.cpp
+++ b/ipacm/src/IPACM_Iface.cpp
@@ -82,8 +82,6 @@
 	memset(software_routing_fl_rule_hdl, 0, sizeof(software_routing_fl_rule_hdl));
 	memset(ipv6_addr, 0, sizeof(ipv6_addr));
 
-	flt_rule_count_v4 = 0;
-	flt_rule_count_v6 = 0;
 	query_iface_property();
 	IPACMDBG_H(" create iface-index(%d) constructor\n", ipa_if_num);
 	return;
@@ -159,6 +157,7 @@
 			goto fail;
 		}
 
+		IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
 		/* copy filter hdls */
 		software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
@@ -179,6 +178,7 @@
 			goto fail;
 		}
 
+		IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
 		/* copy filter hdls */
 		software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
@@ -209,6 +209,7 @@
 			goto fail;
 		}
 
+		IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, ip_type, 1);
 		IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
 		/* copy filter hdls */
 		if (ip_type == IPA_IP_v4)
@@ -258,6 +259,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 
 		/* ipv6 case */
 		if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[1],
@@ -267,6 +269,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 		softwarerouting_act = false;
 #if 0
 	}
@@ -297,6 +300,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, ip, 1);
 		softwarerouting_act = false;
 	}
 #endif
@@ -553,8 +557,11 @@
 		{
 			for (cnt = 0; cnt < tx_prop->num_tx_props; cnt++)
 			{
-				IPACMDBG_H("Tx(%d):attrib-mask:0x%x, ip-type: %d, dst_pipe: %d, header: %s\n",
-								 cnt, tx_prop->tx[cnt].attrib.attrib_mask, tx_prop->tx[cnt].ip, tx_prop->tx[cnt].dst_pipe, tx_prop->tx[cnt].hdr_name);
+				IPACMDBG_H("Tx(%d):attrib-mask:0x%x, ip-type: %d, dst_pipe: %d, alt_dst_pipe: %d, header: %s\n",
+						cnt, tx_prop->tx[cnt].attrib.attrib_mask,
+						tx_prop->tx[cnt].ip, tx_prop->tx[cnt].dst_pipe,
+						tx_prop->tx[cnt].alt_dst_pipe,
+						tx_prop->tx[cnt].hdr_name);
 			}
 		}
 
@@ -751,7 +758,7 @@
 		}
 		else
 		{
-			flt_rule_count_v4 += IPV4_DEFAULT_FILTERTING_RULES;
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
 			/* copy filter hdls */
 			for (int i = 0; i < IPV4_DEFAULT_FILTERTING_RULES; i++)
 			{
@@ -839,7 +846,7 @@
 		}
 		else
 		{
-			flt_rule_count_v6 += IPV6_DEFAULT_FILTERTING_RULES;
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
 			/* copy filter hdls */
 			for (int i = 0;
 					 i < IPV6_DEFAULT_FILTERTING_RULES;
diff --git a/ipacm/src/IPACM_IfaceManager.cpp b/ipacm/src/IPACM_IfaceManager.cpp
index 335b64e..4e6c438 100644
--- a/ipacm/src/IPACM_IfaceManager.cpp
+++ b/ipacm/src/IPACM_IfaceManager.cpp
@@ -157,21 +157,21 @@
 		case IPA_WAN_EMBMS_LINK_UP_EVENT:
 			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
 			/* change iface category from unknown to EMBMS_IF */
-			if (IPACM_Iface::ipacmcfg->ipacm_odu_enable == true)
+			if ((IPACM_Iface::ipacmcfg->ipacm_odu_enable == true) && (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true))
 			{
 				IPACMDBG(" ODU-mode enable or not (%d) \n",IPACM_Iface::ipacmcfg->ipacm_odu_enable);
-			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
-			{
-				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat=EMBMS_IF;
-				IPACMDBG("WAN eMBMS (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
-				ifmgr_data.if_index = StaData->if_index;
-				ifmgr_data.if_type = Q6_WAN;
-				create_iface_instance(&ifmgr_data);
-			}
-			else
-			{
-				IPACMDBG("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
-			}
+				if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
+				{
+					IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat=EMBMS_IF;
+					IPACMDBG("WAN eMBMS (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+					ifmgr_data.if_index = StaData->if_index;
+					ifmgr_data.if_type = Q6_WAN;
+					create_iface_instance(&ifmgr_data);
+				}
+				else
+				{
+					IPACMDBG("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+				}
 			}
 			break;
 
@@ -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);
@@ -236,22 +237,23 @@
 
 		case ETH_IF:
 			{
-					IPACMDBG_H("Creating ETH interface in router mode\n");
-					IPACM_Lan *ETH = new IPACM_Lan(ipa_interface_index);
-					IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, ETH);
-					IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, ETH);
-					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, ETH);
-					IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, ETH);
-					IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, ETH);
-					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_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);
-					registr(ipa_interface_index, ETH);
-					/* solve the new_addr comes earlier issue */
-					IPACM_Iface::iface_addr_query(if_index);
+				IPACMDBG_H("Creating ETH interface in router mode\n");
+				IPACM_Lan *ETH = new IPACM_Lan(ipa_interface_index);
+				IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, ETH);
+				IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, ETH);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, ETH);
+				IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, ETH);
+				IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, ETH);
+				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);
+				registr(ipa_interface_index, ETH);
+				/* solve the new_addr comes earlier issue */
+				IPACM_Iface::iface_addr_query(if_index);
 			}
 			break;
 
@@ -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,8 +322,13 @@
 				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
+				IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, wl);
+				IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, wl);
+#endif
 				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 */
@@ -357,15 +365,20 @@
 					if(is_sta_mode == WLAN_WAN)
 					{
 						IPACM_EvtDispatcher::registr(IPA_WLAN_LINK_DOWN_EVENT, w); // for STA mode
+#ifndef FEATURE_IPA_ANDROI
+						IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, w);
+						IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, w);
+#endif
 					}
 					else
 					{
 						IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, w);
 					}
+
 					IPACMDBG_H("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", w->dev_name, w->ipa_if_num);
 					registr(ipa_interface_index, w);
 					/* 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 e09ea10..624f548 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -78,6 +78,9 @@
 	ipv6_set = 0;
 	ipv4_header_set = false;
 	ipv6_header_set = false;
+	odu_route_rule_v4_hdl = NULL;
+	odu_route_rule_v6_hdl = NULL;
+	eth_client = NULL;
 	int m_fd_odu, ret = IPACM_SUCCESS;
 
 	Nat_App = NatApp::GetInstance();
@@ -157,6 +160,7 @@
 	memset(wlan_client_flt_rule_hdl_v6, 0, IPA_LAN_TO_LAN_MAX_WLAN_CLIENT * sizeof(lan2lan_flt_rule_hdl));
 
 	is_active = true;
+	memset(ipv4_icmp_flt_rule_hdl, 0, NUM_IPV4_ICMP_FLT_RULE * sizeof(uint32_t));
 	memset(tcp_ctl_flt_rule_hdl_v4, 0, NUM_TCP_CTL_FLT_RULE*sizeof(uint32_t));
 	memset(tcp_ctl_flt_rule_hdl_v6, 0, NUM_TCP_CTL_FLT_RULE*sizeof(uint32_t));
 	is_mode_switch = false;
@@ -165,6 +169,22 @@
 	memset(ipv6_prefix_flt_rule_hdl, 0, NUM_IPV6_PREFIX_FLT_RULE * sizeof(uint32_t));
 	memset(ipv6_icmp_flt_rule_hdl, 0, NUM_IPV6_ICMP_FLT_RULE * sizeof(uint32_t));
 
+#ifdef FEATURE_ETH_BRIDGE_LE
+	exp_index_v4 = IPV4_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + NUM_IPV4_ICMP_FLT_RULE + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+	exp_index_v6 = IPV6_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + NUM_IPV6_ICMP_FLT_RULE + NUM_IPV6_PREFIX_FLT_RULE;
+#else
+#ifdef CT_OPT
+	exp_index_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + NUM_TCP_CTL_FLT_RULE + NUM_IPV4_ICMP_FLT_RULE +IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+	exp_index_v6 = IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + NUM_IPV6_ICMP_FLT_RULE + NUM_IPV6_PREFIX_FLT_RULE;
+#else
+	exp_index_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + NUM_IPV4_ICMP_FLT_RULE + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+	exp_index_v6 = IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + NUM_IPV6_ICMP_FLT_RULE + NUM_IPV6_PREFIX_FLT_RULE;
+#endif
+#ifdef FEATURE_IPA_ANDROID
+	exp_index_v4 = exp_index_v4 - IPACM_Iface::ipacmcfg->ipa_num_private_subnet + IPA_MAX_PRIVATE_SUBNET_ENTRIES;
+#endif
+#endif
+
 	/* ODU routing table initilization */
 	if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == ODU_IF)
 	{
@@ -339,6 +359,21 @@
 				//IPACMDBG_H("Posting event:%d\n", evt_data.event);
 				IPACM_EvtDispatcher::PostEvt(&evt_data);
 			}
+#ifndef FEATURE_IPA_ANDROID
+			if(rx_prop != NULL)
+			{
+				if(IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4) != 0)
+				{
+					IPACMDBG_DMESG("### WARNING ### num ipv4 flt rules on client %d is not expected: %d expected value: 0",
+						rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4));
+				}
+				if(IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6) != 0)
+				{
+					IPACMDBG_DMESG("### WARNING ### num ipv6 flt rules on client %d is not expected: %d expected value: 0",
+						rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6));
+				}
+			}
+#endif
 			delete this;
 		}
 		break;
@@ -386,6 +421,11 @@
 						|| ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
 					{
 						IPACMDBG_H("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
+						/* ADD ipv4 icmp rule */
+						if (data->iptype == IPA_IP_v4)
+						{
+							install_ipv4_icmp_flt_rule();
+						}
 						/* ADD ipv6 icmp rule */
 						if ((num_dft_rt_v6 == 0) && (data->iptype == IPA_IP_v6))
 						{
@@ -570,9 +610,17 @@
 				/* first construc ODU full header */
 				if ((ipv4_header_set == false) && (ipv6_header_set == false))
 				{
+					/* construct ODU RT tbl */
 					handle_odu_hdr_init(data->mac_addr);
-					handle_odu_route_add(); /* construct ODU RT tbl*/
-					IPACMDBG("construct ODU header and route rules \n");
+					if (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true)
+					{
+						handle_odu_route_add();
+						IPACMDBG("construct ODU header and route rules, embms_flag (%d) \n", IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable);
+					}
+					else
+					{
+						IPACMDBG("construct ODU header only, embms_flag (%d) \n", IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable);
+					}
 				}
 				/* if ODU in bridge mode, directly return */
 				if(IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == false)
@@ -729,6 +777,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;
 	}
@@ -748,20 +817,6 @@
 		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
 		return IPACM_FAILURE;
 	}
-#ifdef FEATURE_ETH_BRIDGE_LE
-	flt_rule_count_v4 = IPV4_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
-#else
-#ifdef CT_OPT
-	flt_rule_count_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR
-					+ NUM_TCP_CTL_FLT_RULE + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
-#else
-	flt_rule_count_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR
-					+ IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
-#endif
-#ifdef FEATURE_IPA_ANDROID
-	flt_rule_count_v4 = flt_rule_count_v4 - IPACM_Iface::ipacmcfg->ipa_num_private_subnet + IPA_MAX_PRIVATE_SUBNET_ENTRIES;
-#endif
-#endif
 
 	if(is_sta_mode == false)
 	{
@@ -778,6 +833,7 @@
 			close(fd);
 			return IPACM_FAILURE;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_wan_ul_fl_rule_v4);
 
 		memset(wan_ul_fl_rule_hdl_v4, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
 		num_wan_ul_fl_rule_v4 = 0;
@@ -808,6 +864,7 @@
 			close(fd);
 			return IPACM_FAILURE;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 	}
 
 	close(fd);
@@ -861,20 +918,20 @@
    		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
 		rt_rule_entry->rule.attrib.u.v4.dst_addr      = data->ipv4_addr;
 		rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
-	    if (false == m_routing.AddRoutingRule(rt_rule))
-	    {
-	    	IPACMERR("Routing rule addition failed!\n");
-	    	res = IPACM_FAILURE;
-	    	goto fail;
-	    }
-	    else if (rt_rule_entry->status)
-	    {
-	    	IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
-	    	res = rt_rule_entry->status;
-	    	goto fail;
-	    }
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		else if (rt_rule_entry->status)
+		{
+			IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+			res = rt_rule_entry->status;
+			goto fail;
+		}
 		dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
-        IPACMDBG_H("ipv4 iface rt-rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
+		IPACMDBG_H("ipv4 iface rt-rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
 		/* initial multicast/broadcast/fragment filter rule */
 #ifdef FEATURE_ETH_BRIDGE_LE
 		init_fl_rule(data->iptype);
@@ -1080,8 +1137,7 @@
 			free(m_pFilteringTable);
 			return IPACM_FAILURE;
 		}
-
-		flt_rule_count_v4 += IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+		IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
 
 		/* copy filter rule hdls */
 		for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
@@ -1145,7 +1201,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,
@@ -1165,6 +1228,7 @@
 		}
 		else
 		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 			IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
 							 m_pFilteringTable->rules[0].flt_rule_hdl,
 							 m_pFilteringTable->rules[0].status);
@@ -1232,6 +1296,7 @@
 		}
 		else
 		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 			IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 		}
 
@@ -1688,8 +1753,8 @@
 	{
 
         /* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
-	IPACMDBG_H("dev %s add producer dependency\n", dev_name);
-	IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+		IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
         IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
 
 		rt_rule = (struct ipa_ioc_add_rt_rule *)
@@ -2294,7 +2359,11 @@
 	if (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == ODU_IF)
 	{
 		/* delete ODU default RT rules */
-		handle_odu_route_del();
+		if (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true)
+		{
+			IPACMDBG_H(" eMBMS enable, delete eMBMS DL RT rule\n");
+			handle_odu_route_del();
+		}
 
 		/* delete full header */
 		if (ipv4_header_set)
@@ -2351,12 +2420,21 @@
 	/* delete default filter rules */
 	if (ip_type != IPA_IP_v6 && rx_prop != NULL)
 	{
+		if(m_filtering.DeleteFilteringHdls(ipv4_icmp_flt_rule_hdl, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE) == false)
+		{
+			IPACMERR("Error Deleting ICMPv4 Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE);
+
 		if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES) == false)
 		{
 			IPACMERR("Error Deleting Filtering Rule, aborting...\n");
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
 #ifdef FEATURE_ETH_BRIDGE_LE
 		for(i=0; i<IPA_LAN_TO_LAN_MAX_WLAN_CLIENT; i++)
 		{
@@ -2368,13 +2446,8 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_LAN_TO_LAN_MAX_WLAN_CLIENT);
 #endif
-		if(m_filtering.DeleteFilteringHdls(ipv6_icmp_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE) == false)
-		{
-			IPACMERR("Error Deleting ICMPv6 Filtering Rule, aborting...\n");
-			res = IPACM_FAILURE;
-			goto fail;
-		}
 #ifndef FEATURE_ETH_BRIDGE_LE
 #ifdef CT_OPT
 		if (m_filtering.DeleteFilteringHdls(tcp_ctl_flt_rule_hdl_v4, IPA_IP_v4, NUM_TCP_CTL_FLT_RULE) == false)
@@ -2383,6 +2456,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, NUM_TCP_CTL_FLT_RULE);
 #endif
 		for(i=0; i<MAX_OFFLOAD_PAIR; i++)
 		{
@@ -2392,6 +2466,7 @@
 				res = IPACM_FAILURE;
 				goto fail;
 			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 		}
 		IPACMDBG_H("Deleted lan2lan IPv4 flt rules.\n");
 #endif
@@ -2411,6 +2486,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES);
 #else
 		if (m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
 		{
@@ -2418,20 +2494,28 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
 #endif
 	}
     IPACMDBG_H("Finished delete default iface ipv4 filtering rules \n ");
 
 	if (ip_type != IPA_IP_v4 && rx_prop != NULL)
 	{
-		if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
-																				IPA_IP_v6,
-																				(IPV6_DEFAULT_FILTERTING_RULES + IPV6_DEFAULT_LAN_FILTERTING_RULES)) == false)
+		if(m_filtering.DeleteFilteringHdls(ipv6_icmp_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE) == false)
+		{
+			IPACMERR("Error Deleting ICMPv6 Filtering Rule, aborting...\n");
+			res = IPACM_FAILURE;
+			goto fail;
+		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE);
+
+		if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES) == false)
 		{
 			IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
 #ifdef FEATURE_ETH_BRIDGE_LE
 		for(i=0; i<IPA_LAN_TO_LAN_MAX_WLAN_CLIENT; i++)
 		{
@@ -2443,6 +2527,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPA_LAN_TO_LAN_MAX_WLAN_CLIENT);
 #endif
 #ifndef FEATURE_ETH_BRIDGE_LE
 #ifdef CT_OPT
@@ -2452,6 +2537,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_TCP_CTL_FLT_RULE);
 #endif
 		for(i=0; i<MAX_OFFLOAD_PAIR; i++)
 		{
@@ -2461,6 +2547,7 @@
 				res = IPACM_FAILURE;
 				goto fail;
 			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 		}
 		IPACMDBG_H("Deleted lan2lan IPv6 flt rules.\n");
 #endif
@@ -2637,7 +2724,7 @@
 	ipa_ioc_add_flt_rule *pFilteringTable;
 	ipa_fltr_installed_notif_req_msg_v01 flt_index;
 	int fd;
-	int i;
+	int i, index;
 
 	IPACMDBG_H("Set extended property rules in LAN\n");
 
@@ -2657,6 +2744,13 @@
 	if (0 == fd)
 	{
 		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+	if (prop->num_ext_props > MAX_WAN_UL_FILTER_RULES)
+	{
+		IPACMERR("number of modem UL rules > MAX_WAN_UL_FILTER_RULES, aborting...\n");
+		close(fd);
+		return IPACM_FAILURE;
 	}
 
 	memset(&flt_index, 0, sizeof(flt_index));
@@ -2707,6 +2801,21 @@
 		goto fail;
 	}
 
+	index = IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, iptype);
+
+#ifndef FEATURE_IPA_ANDROID
+	if(iptype == IPA_IP_v4 && index != exp_index_v4)
+	{
+		IPACMDBG_DMESG("### WARNING ### num flt rules for IPv4 on client %d is not expected: %d expected value: %d",
+			rx_prop->rx[0].src_pipe, index, exp_index_v4);
+	}
+	if(iptype == IPA_IP_v6 && index != exp_index_v6)
+	{
+		IPACMDBG_DMESG("### WARNING ### num flt rules for IPv6 on client %d is not expected: %d expected value: %d",
+			rx_prop->rx[0].src_pipe, index, exp_index_v6);
+	}
+#endif
+
 	for(cnt=0; cnt<prop->num_ext_props; cnt++)
 	{
 		memcpy(&flt_rule_entry.rule.eq_attrib,
@@ -2715,18 +2824,10 @@
 		flt_rule_entry.rule.rt_tbl_idx = prop->prop[cnt].rt_tbl_idx;
 		memcpy(&pFilteringTable->rules[cnt], &flt_rule_entry, sizeof(flt_rule_entry));
 
-		if(iptype == IPA_IP_v4)
-		{
-			IPACMDBG_H("Filtering rule %d has index %d\n", cnt, flt_rule_count_v4);
-			flt_index.filter_index_list[cnt].filter_index = flt_rule_count_v4;
-			flt_rule_count_v4++;
-		}
-		if(iptype == IPA_IP_v6)
-		{
-			IPACMDBG_H("Filtering rule %d has index %d\n", cnt, flt_rule_count_v6);
-			flt_index.filter_index_list[cnt].filter_index = flt_rule_count_v6;
-			flt_rule_count_v6++;
-		}
+		IPACMDBG_H("Modem UL filtering rule %d has index %d\n", cnt, index);
+		flt_index.filter_index_list[cnt].filter_index = index;
+		index++;
+
 		flt_index.filter_index_list[cnt].filter_handle = prop->prop[cnt].filter_hdl;
 	}
 
@@ -2752,6 +2853,7 @@
 				wan_ul_fl_rule_hdl_v4[num_wan_ul_fl_rule_v4] = pFilteringTable->rules[i].flt_rule_hdl;
 				num_wan_ul_fl_rule_v4++;
 			}
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, pFilteringTable->num_rules);
 		}
 		else if(iptype == IPA_IP_v6)
 		{
@@ -2760,6 +2862,7 @@
 				wan_ul_fl_rule_hdl_v6[num_wan_ul_fl_rule_v6] = pFilteringTable->rules[i].flt_rule_hdl;
 				num_wan_ul_fl_rule_v6++;
 			}
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, pFilteringTable->num_rules);
 		}
 		else
 		{
@@ -2785,21 +2888,13 @@
 		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
 		return IPACM_FAILURE;
 	}
-#ifdef FEATURE_ETH_BRIDGE_LE
-	flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + NUM_IPV6_ICMP_FLT_RULE;
-#else
-#ifdef CT_OPT
-	flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + NUM_IPV6_ICMP_FLT_RULE;
-#else
-	flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + NUM_IPV6_ICMP_FLT_RULE;
-#endif
-#endif
 
 	if(m_filtering.DeleteFilteringHdls(ipv6_prefix_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE) == false)
 	{
 		close(fd);
 		return IPACM_FAILURE;
 	}
+	IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE);
 
 	if(is_sta_mode == false)
 	{
@@ -2817,6 +2912,7 @@
 			close(fd);
 			return IPACM_FAILURE;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_wan_ul_fl_rule_v6);
 
 		memset(wan_ul_fl_rule_hdl_v6, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
 		num_wan_ul_fl_rule_v6 = 0;
@@ -2848,6 +2944,7 @@
 			close(fd);
 			return IPACM_FAILURE;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 	}
 
 	close(fd);
@@ -2858,6 +2955,12 @@
 /*handle lan2lan client active*/
 int IPACM_Lan::handle_lan2lan_client_active(ipacm_event_data_all *data, ipa_cm_event_id event)
 {
+	if((tx_prop == NULL) || (rx_prop == NULL))
+	{
+		IPACMDBG_H("No tx/rx properties registered for iface %s, not posting lan2lan event(%d)\n", dev_name, event);
+		return IPACM_SUCCESS;
+	}
+
 	if(data == NULL)
 	{
 		IPACMERR("Event data is empty.\n");
@@ -3167,7 +3270,7 @@
 		}
 		else
 		{
-			flt_rule_count_v4 += MAX_OFFLOAD_PAIR;
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, MAX_OFFLOAD_PAIR);
 			/* copy filter rule hdls */
 			for (int i = 0; i < MAX_OFFLOAD_PAIR; i++)
 			{
@@ -3218,7 +3321,7 @@
 		}
 		else
 		{
-			flt_rule_count_v6 += MAX_OFFLOAD_PAIR;
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, MAX_OFFLOAD_PAIR);
 			/* copy filter rule hdls */
 			for (int i = 0; i < MAX_OFFLOAD_PAIR; i++)
 			{
@@ -3978,6 +4081,63 @@
 	return IPACM_SUCCESS;
 }
 
+int IPACM_Lan::install_ipv4_icmp_flt_rule()
+{
+	int len;
+	struct ipa_ioc_add_flt_rule* flt_rule;
+	struct ipa_flt_rule_add flt_rule_entry;
+
+	if(rx_prop != NULL)
+	{
+		len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+		flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+		if (!flt_rule)
+		{
+			IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+			return IPACM_FAILURE;
+		}
+
+		flt_rule->commit = 1;
+		flt_rule->ep = rx_prop->rx[0].src_pipe;
+		flt_rule->global = false;
+		flt_rule->ip = IPA_IP_v4;
+		flt_rule->num_rules = 1;
+
+		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+		flt_rule_entry.rule.retain_hdr = 1;
+		flt_rule_entry.rule.to_uc = 0;
+		flt_rule_entry.rule.eq_attrib_type = 0;
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.flt_rule_hdl = -1;
+		flt_rule_entry.status = -1;
+		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+
+		memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
+		flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_PROTOCOL;
+		flt_rule_entry.rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP;
+		memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+		if (m_filtering.AddFilteringRule(flt_rule) == false)
+		{
+			IPACMERR("Error Adding Filtering rule, aborting...\n");
+			free(flt_rule);
+			return IPACM_FAILURE;
+		}
+		else
+		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+			ipv4_icmp_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
+			IPACMDBG_H("IPv4 icmp filter rule HDL:0x%x\n", ipv4_icmp_flt_rule_hdl[0]);
+                        free(flt_rule);
+		}
+	}
+	return IPACM_SUCCESS;
+}
+
 void IPACM_Lan::install_tcp_ctl_flt_rule(ipa_ip_type iptype)
 {
 	if (rx_prop == NULL)
@@ -4019,11 +4179,14 @@
 
 	flt_rule.rule.eq_attrib.rule_eq_bitmap = 0;
 
-	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
-	flt_rule.rule.eq_attrib.metadata_meq32_present = 1;
-	flt_rule.rule.eq_attrib.metadata_meq32.offset = 0;
-	flt_rule.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
-	flt_rule.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
+	if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA)
+	{
+		flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
+		flt_rule.rule.eq_attrib.metadata_meq32_present = 1;
+		flt_rule.rule.eq_attrib.metadata_meq32.offset = 0;
+		flt_rule.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
+		flt_rule.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
+	}
 
 	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
 	flt_rule.rule.eq_attrib.protocol_eq_present = 1;
@@ -4059,17 +4222,17 @@
 		{
 			for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
 			{
-				flt_rule_count_v4++;
 				tcp_ctl_flt_rule_hdl_v4[i] = pFilteringTable->rules[i].flt_rule_hdl;
 			}
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, NUM_TCP_CTL_FLT_RULE);
 		}
 		else
 		{
 			for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
 			{
-				flt_rule_count_v6++;
 				tcp_ctl_flt_rule_hdl_v6[i] = pFilteringTable->rules[i].flt_rule_hdl;
 			}
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, NUM_TCP_CTL_FLT_RULE);
 		}
 	}
 
@@ -4143,7 +4306,7 @@
 		}
 		else
 		{
-			flt_rule_count_v4 += IPA_MAX_PRIVATE_SUBNET_ENTRIES;
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES);
 			/* copy filter rule hdls */
 			for (int i = 0; i < IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
 			{
@@ -4309,9 +4472,9 @@
 		}
 		else
 		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 			ipv6_prefix_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
 			IPACMDBG_H("IPv6 prefix filter rule HDL:0x%x\n", ipv6_prefix_flt_rule_hdl[0]);
-			flt_rule_count_v6++;
 			free(flt_rule);
 		}
 	}
@@ -4347,7 +4510,7 @@
 		flt_rule_entry.rule.retain_hdr = 1;
 		flt_rule_entry.rule.to_uc = 0;
 		flt_rule_entry.rule.eq_attrib_type = 0;
-		flt_rule_entry.at_rear = true;
+		flt_rule_entry.at_rear = false;
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
@@ -4366,9 +4529,9 @@
 		}
 		else
 		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 			ipv6_icmp_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
 			IPACMDBG_H("IPv6 icmp filter rule HDL:0x%x\n", ipv6_icmp_flt_rule_hdl[0]);
-			flt_rule_count_v6++;
 			free(flt_rule);
 		}
 	}
@@ -4468,7 +4631,7 @@
 		}
 		else
 		{
-			flt_rule_count_v4 += IPA_LAN_TO_LAN_MAX_WLAN_CLIENT;
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, IPA_LAN_TO_LAN_MAX_WLAN_CLIENT);
 			/* copy filter rule hdls */
 			for (int i = 0; i < IPA_LAN_TO_LAN_MAX_WLAN_CLIENT; i++)
 			{
@@ -4520,7 +4683,7 @@
 		}
 		else
 		{
-			flt_rule_count_v6 += IPA_LAN_TO_LAN_MAX_WLAN_CLIENT;
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, IPA_LAN_TO_LAN_MAX_WLAN_CLIENT);
 			/* copy filter rule hdls */
 			for (int i = 0; i < IPA_LAN_TO_LAN_MAX_WLAN_CLIENT; i++)
 			{
@@ -5413,5 +5576,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 39a31f5..3cc58e1 100644
--- a/ipacm/src/IPACM_Main.cpp
+++ b/ipacm/src/IPACM_Main.cpp
@@ -39,7 +39,7 @@
 */
 /******************************************************************************
 
-																																																																																																IP_MAIN.C
+                      IPCM_MAIN.C
 
 ******************************************************************************/
 
@@ -270,6 +270,9 @@
 	ipacm_event_data_iptype *data_iptype = NULL;
 	ipacm_event_data_wlan_ex *data_ex;
 
+	ipacm_cmd_q_data new_neigh_evt;
+	ipacm_event_data_all* new_neigh_data;
+
 	fd = open(IPA_DRIVER, O_RDWR);
 	if (fd == 0)
 	{
@@ -282,6 +285,8 @@
 		IPACMDBG_H("Waiting for nofications from IPA driver \n");
 		memset(buffer, 0, sizeof(buffer));
 		memset(&evt_data, 0, sizeof(evt_data));
+		memset(&new_neigh_evt, 0, sizeof(ipacm_cmd_q_data));
+		new_neigh_data = NULL;
 		data = NULL;
 		data_fid = NULL;
 
@@ -404,6 +409,7 @@
 
 		case WLAN_CLIENT_CONNECT_EX:
 			IPACMDBG_H("Received WLAN_CLIENT_CONNECT_EX\n");
+
 			memcpy(&event_ex_o, buffer + sizeof(struct ipa_msg_meta),sizeof(struct ipa_wlan_msg_ex));
 			if(event_ex_o.num_of_attribs > IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS)
 			{
@@ -430,10 +436,25 @@
 			memcpy(data_ex->attribs,
 						event_ex->attribs,
 						event_ex->num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val));
+
+			ipa_get_if_index(event_ex->name, &(data_ex->if_index));
+			evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT_EX;
+			evt_data.evt_data = data_ex;
+
+			/* Construct new_neighbor msg with netdev device internally */
+			new_neigh_data = (ipacm_event_data_all*)malloc(sizeof(ipacm_event_data_all));
+			if(new_neigh_data == NULL)
+			{
+				IPACMERR("Failed to allocate memory.\n");
+				return NULL;
+			}
+			memset(new_neigh_data, 0, sizeof(ipacm_event_data_all));
+			new_neigh_data->iptype = IPA_IP_v6;
 			for(cnt = 0; cnt < event_ex->num_of_attribs; cnt++)
 			{
 				if(event_ex->attribs[cnt].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
 				{
+					memcpy(new_neigh_data->mac_addr, event_ex->attribs[cnt].u.mac_addr, sizeof(new_neigh_data->mac_addr));
 					IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
 								 event_ex->attribs[cnt].u.mac_addr[0], event_ex->attribs[cnt].u.mac_addr[1], event_ex->attribs[cnt].u.mac_addr[2],
 								 event_ex->attribs[cnt].u.mac_addr[3], event_ex->attribs[cnt].u.mac_addr[4], event_ex->attribs[cnt].u.mac_addr[5]);
@@ -447,10 +468,9 @@
 					IPACMDBG_H("Wlan message has unexpected type!\n");
 				}
 			}
-
-			ipa_get_if_index(event_ex->name, &(data_ex->if_index));
-		    evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT_EX;
-			evt_data.evt_data = data_ex;
+			new_neigh_data->if_index = data_ex->if_index;
+			new_neigh_evt.evt_data = (void*)new_neigh_data;
+			new_neigh_evt.event = IPA_NEW_NEIGH_EVENT;
 			free(event_ex);
 			break;
 
@@ -589,6 +609,24 @@
 			evt_data.evt_data = data_fid;
 			break;
 
+		case WLAN_SWITCH_TO_SCC:
+			IPACMDBG_H("Received WLAN_SWITCH_TO_SCC\n");
+			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");
+			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;
@@ -598,6 +636,12 @@
 		/* finish command queue */
 		IPACMDBG_H("Posting event:%d\n", evt_data.event);
 		IPACM_EvtDispatcher::PostEvt(&evt_data);
+		/* push new_neighbor with netdev device internally */
+		if(new_neigh_data != NULL)
+		{
+			IPACMDBG_H("Internally post event IPA_NEW_NEIGH_EVENT\n");
+			IPACM_EvtDispatcher::PostEvt(&new_neigh_evt);
+		}
 	}
 
 	(void)close(fd);
@@ -675,6 +719,10 @@
 			return ret;
 		}
 		IPACMDBG_H("created command queue thread\n");
+		if(pthread_setname_np(cmd_queue_thread, "cmd queue process") != 0)
+		{
+			IPACMERR("unable to set thread name\n");
+		}
 	}
 
 	if (IPACM_SUCCESS == netlink_thread)
@@ -686,6 +734,10 @@
 			return ret;
 		}
 		IPACMDBG_H("created netlink thread\n");
+		if(pthread_setname_np(netlink_thread, "netlink socket") != 0)
+		{
+			IPACMERR("unable to set thread name\n");
+		}
 	}
 
 
@@ -698,6 +750,10 @@
 			return ret;
 		}
 		IPACMDBG_H("created firewall monitor thread\n");
+		if(pthread_setname_np(monitor_thread, "firewall cfg process") != 0)
+		{
+			IPACMERR("unable to set thread name\n");
+		}
 	}
 
 	if (IPACM_SUCCESS == ipa_driver_thread)
@@ -709,6 +765,10 @@
 			return ret;
 		}
 		IPACMDBG_H("created ipa_driver_wlan thread\n");
+		if(pthread_setname_np(ipa_driver_thread, "ipa driver ntfy") != 0)
+		{
+			IPACMERR("unable to set thread name\n");
+		}
 	}
 
 	pthread_join(cmd_queue_thread, NULL);
diff --git a/ipacm/src/IPACM_Neighbor.cpp b/ipacm/src/IPACM_Neighbor.cpp
index d122b92..91facbd 100644
--- a/ipacm/src/IPACM_Neighbor.cpp
+++ b/ipacm/src/IPACM_Neighbor.cpp
@@ -328,15 +328,14 @@
 								/* use previous ipv4 first */
 								if(data->if_index != neighbor_client[i].iface_index)
 								{
-									IPACMERR("update new kernel iface index \n");
+									IPACMDBG_H("update new kernel iface index \n");
 									neighbor_client[i].iface_index = data->if_index;
 								}
 
 								/* check if client associated with previous network interface */
 								if(ipa_interface_index != neighbor_client[i].ipa_if_num)
 								{
-									IPACMERR("client associate to different AP \n");
-									return;
+									IPACMDBG_H("client associate to different AP \n");
 								}
 
 								if (neighbor_client[i].v4_addr != 0) /* not 0.0.0.0 */
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_Routing.cpp b/ipacm/src/IPACM_Routing.cpp
index d6cafa0..7ae6131 100644
--- a/ipacm/src/IPACM_Routing.cpp
+++ b/ipacm/src/IPACM_Routing.cpp
@@ -1,4 +1,4 @@
-/* 
+/*
 Copyright (c) 2013, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,8 @@
 
 bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
 {
-	int retval = 0;
+	int retval = 0, cnt=0;
+	bool isInvalid = false;
 
 	if (!DeviceNodeIsOpened())
 	{
@@ -81,6 +82,20 @@
 		return false;
 	}
 
+	for(cnt=0; cnt<ruleTable->num_rules; cnt++)
+	{
+		if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX)
+		{
+			IPACMERR("Invalid dst pipe, Rule:%d  dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
+			isInvalid = true;
+		}
+	}
+
+	if(isInvalid)
+	{
+		return false;
+	}
+
 	retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
 	if (retval)
 	{
@@ -88,6 +103,11 @@
 		return false;
 	}
 
+	for(cnt=0; cnt<ruleTable->num_rules; cnt++)
+	{
+		IPACMDBG("Rule:%d  dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
+	}
+
 	IPACMDBG_H("Added routing rule %p\n", ruleTable);
 	return true;
 }
@@ -224,3 +244,31 @@
 	return res;
 }
 
+bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules)
+{
+	int retval = 0, cnt;
+
+	if (!DeviceNodeIsOpened())
+	{
+		IPACMERR("Device is not opened\n");
+		return false;
+	}
+
+	retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules);
+	if (retval)
+	{
+		IPACMERR("Failed modifying routing rules %p\n", mdfyRules);
+		return false;
+	}
+
+	for(cnt=0; cnt<mdfyRules->num_rules; cnt++)
+	{
+		if(mdfyRules->rules[cnt].status != 0)
+		{
+			IPACMERR("Unable to modify rule: %d\n", cnt);
+		}
+	}
+
+	IPACMDBG_H("Modified routing rules %p\n", mdfyRules);
+	return true;
+}
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index c758e41..785d8e2 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];
 
@@ -75,6 +76,10 @@
 {
 	num_firewall_v4 = 0;
 	num_firewall_v6 = 0;
+	wan_route_rule_v4_hdl = NULL;
+	wan_route_rule_v6_hdl = NULL;
+	wan_route_rule_v6_hdl_a5 = NULL;
+	wan_client = NULL;
 
 	if(iface_query != NULL)
 	{
@@ -85,6 +90,8 @@
 	}
 	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;
@@ -172,11 +179,19 @@
 	struct ipa_rt_rule_add *rt_rule_entry;
 	struct ipa_ioc_add_flt_rule *flt_rule;
 	struct ipa_flt_rule_add flt_rule_entry;
+	struct ipa_ioc_get_hdr hdr;
 
 	const int NUM_RULES = 1;
 	int num_ipv6_addr, len;
 	int res = IPACM_SUCCESS;
 
+	memset(&hdr, 0, sizeof(hdr));
+	if(tx_prop == NULL || rx_prop == NULL)
+	{
+		IPACMDBG_H("Either tx or rx property is NULL, return.\n");
+		return IPACM_SUCCESS;
+	}
+
 	if (data->iptype == IPA_IP_v6)
 	{
 	    for(num_ipv6_addr=0;num_ipv6_addr<num_dft_rt_v6;num_ipv6_addr++)
@@ -207,8 +222,25 @@
 	    	strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
 
 	    rt_rule_entry = &rt_rule->rules[0];
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			strncpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+			if(m_header.GetHeaderHandle(&hdr) == false)
+			{
+				IPACMERR("Failed to get QMAP header.\n");
+				return IPACM_FAILURE;
+			}
+			rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+		}
 	    rt_rule_entry->at_rear = false;
-	    rt_rule_entry->rule.dst = iface_query->excp_pipe;  //go to A5
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+		}
+		else
+		{
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+		}
 	    rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
 	    	rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
 	    	rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
@@ -322,6 +354,7 @@
 				}
 				else
 				{
+					IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 					ipv6_dest_flt_rule_hdl[num_ipv6_dest_flt_rule] = flt_rule->rules[0].flt_rule_hdl;
 					IPACMDBG_H("IPv6 dest filter rule %d HDL:0x%x\n", num_ipv6_dest_flt_rule, ipv6_dest_flt_rule_hdl[num_ipv6_dest_flt_rule]);
 					num_ipv6_dest_flt_rule++;
@@ -338,6 +371,28 @@
     }
 	else
 	{
+		if(wan_v4_addr_set)
+		{
+			/* check iface ipv4 same or not */
+			if(data->ipv4_addr == wan_v4_addr)
+			{
+				IPACMDBG_H("Already setup device (%s) ipv4 and it didn't change(0x%x)\n", dev_name, data->ipv4_addr);
+				return IPACM_SUCCESS;
+			}
+			else
+			{
+				IPACMDBG_H(" device (%s) ipv4 addr is changed\n", dev_name);
+				/* Delete default v4 RT rule */
+				IPACMDBG_H("Delete default v4 routing rules\n");
+				if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+				{
+					IPACMERR("Routing old RT rule deletion failed!\n");
+					res = IPACM_FAILURE;
+					goto fail;
+				}
+			}
+		}
+
 		rt_rule = (struct ipa_ioc_add_rt_rule *)
 			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
 							NUM_RULES * sizeof(struct ipa_rt_rule_add));
@@ -352,8 +407,22 @@
 		rt_rule->num_rules = NUM_RULES;
 		rt_rule->ip = data->iptype;
 		rt_rule_entry = &rt_rule->rules[0];
+		if(m_is_sta_mode == Q6_WAN)
+		{
+			strncpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+			if(m_header.GetHeaderHandle(&hdr) == false)
+			{
+				IPACMERR("Failed to get QMAP header.\n");
+				return IPACM_FAILURE;
+			}
+			rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+		}
+		else
+		{
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+		}
 		rt_rule_entry->at_rear = false;
-		rt_rule_entry->rule.dst = iface_query->excp_pipe;  //go to A5
 		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);
@@ -376,20 +445,26 @@
 		IPACMDBG_H("ipv4 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
 			/* initial multicast/broadcast/fragment filter rule */
 
-		if(m_is_sta_mode == Q6_WAN)
+		/* only do one time */
+		if(!wan_v4_addr_set)
 		{
-			modem_ipv4_pdn_index = num_ipv4_modem_pdn;
-			num_ipv4_modem_pdn++;
-			IPACMDBG_H("Now the number of modem ipv4 pdn is %d.\n", num_ipv4_modem_pdn);
-			init_fl_rule_ex(data->iptype);
-		}
-		else
-		{
-			init_fl_rule(data->iptype);
+			/* initial multicast/broadcast/fragment filter rule */
+			if(m_is_sta_mode == Q6_WAN)
+			{
+				modem_ipv4_pdn_index = num_ipv4_modem_pdn;
+				num_ipv4_modem_pdn++;
+				IPACMDBG_H("Now the number of modem ipv4 pdn is %d.\n", num_ipv4_modem_pdn);
+				init_fl_rule_ex(data->iptype);
+			}
+			else
+			{
+				init_fl_rule(data->iptype);
+			}
 		}
 
 		wan_v4_addr = data->ipv4_addr;
-		IPACMDBG_H("Receved wan address:0x%x\n",wan_v4_addr);
+		wan_v4_addr_set = true;
+		IPACMDBG_H("Receved wan ipv4-addr:0x%x\n",wan_v4_addr);
 	}
 
 	IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
@@ -429,7 +504,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);
@@ -464,30 +598,30 @@
 
 	case IPA_LINK_DOWN_EVENT:
 		{
-			if(m_is_sta_mode == Q6_WAN)
+			ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+			ipa_interface_index = iface_ipa_index_query(data->if_index);
+			if (ipa_interface_index == ipa_if_num)
 			{
-				ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
-				ipa_interface_index = iface_ipa_index_query(data->if_index);
-				if (ipa_interface_index == ipa_if_num)
+				if(m_is_sta_mode == Q6_WAN)
 				{
-					IPACMDBG_H("Received IPA_LINK_DOWN_EVENT\n");
-					handle_down_evt_ex();
-					IPACMDBG_H("IPA_WAN_Q6 (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+						IPACMDBG_H("Received IPA_LINK_DOWN_EVENT\n");
+						handle_down_evt_ex();
+						IPACMDBG_H("IPA_WAN_Q6 (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+						IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+						delete this;
+						return;
+				}
+				else if (m_is_sta_mode == ECM_WAN)
+				{
+					IPACMDBG_H("Received IPA_LINK_DOWN_EVENT(wan_mode:%d)\n", m_is_sta_mode);
+					/* delete previous instance */
+					handle_down_evt();
+					IPACMDBG_H("IPA_WAN_CRADLE (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
 					IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
 					delete this;
 					return;
 				}
 			}
-			else if (m_is_sta_mode == ECM_WAN)
-			{
-				IPACMDBG_H("Received IPA_LINK_DOWN_EVENT(wan_mode:%d)\n", m_is_sta_mode);
-				/* delete previous instance */
-				handle_down_evt();
-				IPACMDBG_H("IPA_WAN_CRADLE (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
-				IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
-				delete this;
-				return;
-			}
 		}
 		break;
 
@@ -509,7 +643,7 @@
 			{
 				IPACMDBG_H("Get IPA_ADDR_ADD_EVENT: IF ip type %d, incoming ip type %d\n", ip_type, data->iptype);
 				/* check v4 not setup before, v6 can have 2 iface ip */
-				if( ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX))
+				if( (data->iptype == IPA_IP_v4)
 				    || ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
 				{
 					IPACMDBG_H("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
@@ -537,12 +671,15 @@
 			{
 				IPACMDBG_H("Received IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT (Android) for ip-type (%d)\n", data->iptype);
 				/* The special below condition is to handle default gateway */
-				if ((data->iptype == IPA_IP_v4) && (active_v4 == false))
+				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))
+				else if ((data->iptype == IPA_IP_v6) && (active_v6 == false) && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
 				{
 					IPACMDBG_H("\n get default v6 route (dst:00.00.00.00) upstream\n");
 				  	handle_route_add_evt(data->iptype);
@@ -554,6 +691,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);
@@ -595,6 +733,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);
@@ -636,13 +776,19 @@
 				IPACMDBG_H("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
 
 				/* The special below condition is to handle default gateway */
-				if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == false))
+				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) &&
-								 (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) && (active_v6 == false))
+								 (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) && (active_v6 == false)
+								 && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
 				{
 					IPACMDBG_H("\n get default v6 route (dst:00.00.00.00)\n");
 					IPACMDBG_H(" IPV6 value: %08x:%08x:%08x:%08x \n",
@@ -658,6 +804,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);
@@ -700,6 +847,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);
@@ -715,7 +863,7 @@
 				else if ((data->iptype == IPA_IP_v6) && (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) && (active_v6 == true))
 				{
 
-				    IPACMDBG_H("get del default v6 route (dst:00.00.00.00)\n");
+					IPACMDBG_H("get del default v6 route (dst:00.00.00.00)\n");
 					if(m_is_sta_mode == Q6_WAN)
 					{
 						del_wan_firewall_rule(IPA_IP_v6);
@@ -743,7 +891,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");
@@ -779,18 +926,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;
@@ -876,6 +1022,44 @@
 		}
 		break;
 
+		case IPA_WLAN_SWITCH_TO_SCC:
+			if(IPACM_Wan::backhaul_is_sta_mode == true)
+			{
+				IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_SCC\n");
+				if(ip_type == IPA_IP_MAX)
+				{
+					handle_wlan_SCC_MCC_switch(true, IPA_IP_v4);
+					handle_wlan_SCC_MCC_switch(true, IPA_IP_v6);
+					handle_wan_client_SCC_MCC_switch(true, IPA_IP_v4);
+					handle_wan_client_SCC_MCC_switch(true, IPA_IP_v6);
+				}
+				else
+				{
+					handle_wlan_SCC_MCC_switch(true, ip_type);
+					handle_wan_client_SCC_MCC_switch(true, ip_type);
+				}
+			}
+			break;
+
+		case IPA_WLAN_SWITCH_TO_MCC:
+			if(IPACM_Wan::backhaul_is_sta_mode == true)
+			{
+				IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_MCC\n");
+				if(ip_type == IPA_IP_MAX)
+				{
+					handle_wlan_SCC_MCC_switch(false, IPA_IP_v4);
+					handle_wlan_SCC_MCC_switch(false, IPA_IP_v6);
+					handle_wan_client_SCC_MCC_switch(false, IPA_IP_v4);
+					handle_wan_client_SCC_MCC_switch(false, IPA_IP_v6);
+				}
+				else
+				{
+					handle_wlan_SCC_MCC_switch(false, ip_type);
+					handle_wan_client_SCC_MCC_switch(false, ip_type);
+				}
+			}
+			break;
+
 	default:
 		break;
 	}
@@ -888,13 +1072,14 @@
 {
 
 	/* add default WAN route */
-	struct ipa_ioc_add_rt_rule *rt_rule;
+	struct ipa_ioc_add_rt_rule *rt_rule = NULL;
 	struct ipa_rt_rule_add *rt_rule_entry;
 	struct ipa_ioc_get_hdr sRetHeader;
 	uint32_t cnt, tx_index = 0;
 	const int NUM = 1;
 	ipacm_cmd_q_data evt_data;
 	struct ipa_ioc_copy_hdr sCopyHeader; /* checking if partial header*/
+	struct ipa_ioc_get_hdr hdr;
 
 	IPACMDBG_H("ip-type:%d\n", iptype);
 
@@ -915,6 +1100,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;
@@ -952,7 +1145,7 @@
 			return IPACM_FAILURE;
 		}
 	}
-
+#if 0
     for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
 	{
 		if(tx_prop->tx[cnt].ip==iptype)
@@ -998,6 +1191,7 @@
 			}
 	    }
     }
+#endif
 
 	rt_rule = (struct ipa_ioc_add_rt_rule *)
 		 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
@@ -1030,32 +1224,28 @@
 				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);
+				rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v6;
 			}
 
-			if (tx_prop->tx[tx_index].hdr_name !=  NULL)
+			if(IPACM_Iface::ipacmcfg->isMCC_Mode == true)
 			{
-				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;
+				IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+						tx_prop->tx[tx_index].alt_dst_pipe);
+				rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
 			}
-
-			rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+			else
+			{
+				rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+			}
 			memcpy(&rt_rule_entry->rule.attrib,
 						 &tx_prop->tx[tx_index].attrib,
 						 sizeof(rt_rule_entry->rule.attrib));
@@ -1108,31 +1298,44 @@
 
 	if (iptype == IPA_IP_v6)
 	{
-    strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name);
-    memset(rt_rule_entry, 0, sizeof(struct ipa_rt_rule_add));
-	rt_rule_entry->at_rear = true;
-    rt_rule_entry->rule.dst = iface_query->excp_pipe;  //go to A5
-    rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
-	rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
-	rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
-	rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
-	rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
-	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
-	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
-	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
-	rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+		strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.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)
+		{
+			memset(&hdr, 0, sizeof(hdr));
+			strncpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+			if(m_header.GetHeaderHandle(&hdr) == false)
+			{
+				IPACMERR("Failed to get QMAP header.\n");
+				return IPACM_FAILURE;
+			}
+			rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+		}
+		else
+		{
+			rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+		}
+		rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+		rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
 
-	if (false == m_routing.AddRoutingRule(rt_rule))
-	{
-		IPACMERR("Routing rule addition failed!\n");
-		free(rt_rule);
-		return IPACM_FAILURE;
-	}
-	wan_route_rule_v6_hdl_a5[0] = rt_rule_entry->rt_rule_hdl;
-	IPACMDBG_H("Set ipv6 wan-route rule hdl for v6_wan_table:0x%x,tx:%d,ip-type: %d \n",
-				wan_route_rule_v6_hdl_a5[0],
-		        0,
-		        iptype);
+		if (false == m_routing.AddRoutingRule(rt_rule))
+		{
+			IPACMERR("Routing rule addition failed!\n");
+			free(rt_rule);
+			return IPACM_FAILURE;
+		}
+		wan_route_rule_v6_hdl_a5[0] = rt_rule_entry->rt_rule_hdl;
+		IPACMDBG_H("Set ipv6 wan-route rule hdl for v6_wan_table:0x%x,tx:%d,ip-type: %d \n",
+				wan_route_rule_v6_hdl_a5[0], 0, iptype);
 	}
 
 	ipacm_event_iface_up *wanup_data;
@@ -1140,13 +1343,14 @@
 	if (wanup_data == NULL)
 	{
 		IPACMERR("Unable to allocate memory\n");
+		free(rt_rule);
 		return IPACM_FAILURE;
 	}
 	memset(wanup_data, 0, sizeof(ipacm_event_iface_up));
 
 	if (iptype == IPA_IP_v4)
 	{
-	    IPACM_Wan::wan_up = true;
+		IPACM_Wan::wan_up = true;
 		active_v4 = true;
 
 		if(m_is_sta_mode == Q6_WAN)
@@ -1216,237 +1420,78 @@
 	IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
 	IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
 
+	if(rt_rule != NULL)
+	{
+		free(rt_rule);
+	}
 	return IPACM_SUCCESS;
 }
 
 /* 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;
 }
 
@@ -1523,8 +1568,7 @@
 		flt_rule_entry.status = -1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
 		memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(struct ipa_rule_attrib));
-		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
-		flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_FRAG_HDR;
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
 
 		memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
 		if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
@@ -1535,6 +1579,7 @@
 		}
 		else
 		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 			ipv6_frag_firewall_flt_rule_hdl = m_pFilteringTable->rules[0].flt_rule_hdl;
 			IPACMDBG_H("Installed IPv6 frag firewall rule, handle %d.\n", ipv6_frag_firewall_flt_rule_hdl);
 		}
@@ -1565,25 +1610,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,
@@ -1603,6 +1662,7 @@
 			}
 			else
 			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 			}
 
@@ -1644,14 +1704,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,
@@ -1680,6 +1747,7 @@
 						}
 						else
 						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 							/* save v4 firewall filter rule handler */
 							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
 											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
@@ -1703,6 +1771,7 @@
 						}
 						else
 						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 							/* save v4 firewall filter rule handler */
 							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
 											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
@@ -1726,6 +1795,7 @@
 						}
 						else
 						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 							/* save v4 firewall filter rule handler */
 							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
 											 m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
@@ -1745,7 +1815,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;
 
@@ -1756,14 +1826,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,
@@ -1785,6 +1869,7 @@
 			}
 			else
 			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 			}
 
@@ -1828,6 +1913,7 @@
 			}
 			else
 			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 			}
 			/* copy filter hdls */
@@ -1892,6 +1978,7 @@
 			}
 			else
 			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 			}
 
@@ -1960,6 +2047,7 @@
 						}
 						else
 						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 							/* save v4 firewall filter rule handler */
 							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
@@ -1978,6 +2066,7 @@
 						}
 						else
 						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 							/* save v6 firewall filter rule handler */
 							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
@@ -1987,7 +2076,6 @@
 					}
 					else
 					{
-
 						memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
 						if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
 						{
@@ -1997,6 +2085,7 @@
 						}
 						else
 						{
+							IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 							/* save v6 firewall filter rule handler */
 							IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 							firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
@@ -2031,6 +2120,7 @@
 			}
 			else
 			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 			}
 			/* copy filter hdls */
@@ -2088,6 +2178,7 @@
 			}
 			else
 			{
+				IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 				IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
 			}
 			/* copy filter hdls*/
@@ -2177,8 +2268,7 @@
 		flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
 		flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
 
-		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
-		flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_FRAG_HDR;
+		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
 
 		change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
 
@@ -2654,17 +2744,21 @@
 
 	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 */
 		{
-		add_dft_filtering_rule(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4);
-	}
+			/* reset the num_v4_flt_rule*/
+			IPACM_Wan::num_v4_flt_rule = 0;
+			add_dft_filtering_rule(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4);
+		}
 	}
 	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 */
 		{
-		add_dft_filtering_rule(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6);
-	}
+			/* reset the num_v6_flt_rule*/
+			IPACM_Wan::num_v6_flt_rule = 0;
+			add_dft_filtering_rule(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6);
+		}
 	}
 	else
 	{
@@ -2724,6 +2818,8 @@
 		memcpy(&flt_rule_entry.rule.attrib,
 					 &rx_prop->rx[0].attrib,
 					 sizeof(flt_rule_entry.rule.attrib));
+		/* remove meta data mask */
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
 		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
 		flt_rule_entry.rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP;
 
@@ -2749,6 +2845,8 @@
 		memcpy(&flt_rule_entry.rule.attrib,
 					 &rx_prop->rx[0].attrib,
 					 sizeof(flt_rule_entry.rule.attrib));
+		/* remove meta data mask */
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
 		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_PORT;
 		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
 		for(i = 0; i < ipacm_config->ipa_num_alg_ports; i++)
@@ -2775,6 +2873,8 @@
 		memcpy(&flt_rule_entry.rule.attrib,
 					 &rx_prop->rx[0].attrib,
 					 sizeof(flt_rule_entry.rule.attrib));
+		/* remove meta data mask */
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
 		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_PORT;
 		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
 		for(i = 0; i < ipacm_config->ipa_num_alg_ports; i++)
@@ -2835,6 +2935,8 @@
 		memcpy(&flt_rule_entry.rule.attrib,
 					 &rx_prop->rx[1].attrib,
 					 sizeof(flt_rule_entry.rule.attrib));
+		/* remove meta data mask */
+		flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
 		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
 		flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
 
@@ -3241,6 +3343,7 @@
 				IPACMERR("Error Deleting Filtering rules, aborting...\n");
 				return IPACM_FAILURE;
 			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_firewall_v4);
 		}
 		else
 		{
@@ -3253,6 +3356,7 @@
 			IPACMERR("Error Deleting Filtering rules, aborting...\n");
 			return IPACM_FAILURE;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
 
 		num_firewall_v4 = 0;
 	}
@@ -3273,6 +3377,7 @@
 				IPACMERR("Error Deleting Filtering rules, aborting...\n");
 				return IPACM_FAILURE;
 			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_firewall_v6);
 		}
 		else
 		{
@@ -3285,16 +3390,19 @@
 			IPACMERR("Error Deleting Filtering rules, aborting...\n");
 			return IPACM_FAILURE;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 		if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[2],
 																				IPA_IP_v6, 1) == false)
 		{
 			IPACMERR("Error Deleting Filtering rules, aborting...\n");
 			return IPACM_FAILURE;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 		if (m_filtering.DeleteFilteringHdls(&ipv6_frag_firewall_flt_rule_hdl, IPA_IP_v6, 1) == false)
 		{
 			IPACMERR("Error deleting IPv6 frag filtering rules.\n");
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
 		num_firewall_v6 = 0;
 	}
 
@@ -3307,7 +3415,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)
 	{
@@ -3785,6 +3893,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
 
 		IPACMDBG_H("finished delete default v4 filtering rules\n ");
 	}
@@ -3800,6 +3909,7 @@
 			res = IPACM_FAILURE;
 			goto fail;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
 
 		if(num_ipv6_dest_flt_rule > 0 && num_ipv6_dest_flt_rule <= MAX_DEFAULT_v6_ROUTE_RULES)
 		{
@@ -3809,28 +3919,11 @@
 				res = IPACM_FAILURE;
 				goto fail;
 			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_ipv6_dest_flt_rule);
 		}
 		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)
 	{
@@ -3871,12 +3964,6 @@
 
 	IPACMDBG_H(" wan handle_down_evt \n");
 
-	/* no iface address up, directly close iface*/
-	if (ip_type == IPACM_IP_NULL)
-	{
-		goto fail;
-	}
-
 	/* free ODU filter rule handlers */
 	if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == EMBMS_IF)
 	{
@@ -3894,6 +3981,12 @@
 		goto fail;
 	}
 
+	/* no iface address up, directly close iface*/
+	if (ip_type == IPACM_IP_NULL)
+	{
+		goto fail;
+	}
+
 	if(ip_type == IPA_IP_v4)
 	{
 		num_ipv4_modem_pdn--;
@@ -4016,24 +4109,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)
 	{
@@ -4148,7 +4223,8 @@
 		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
 		{
 			IPACMERR("Failed to get eq_attrib\n");
-			return IPACM_FAILURE;
+			res = IPACM_FAILURE;
+			goto fail;
 		}
 		memcpy(&flt_rule_entry.rule.eq_attrib,
 			&flt_eq.eq_attrib,
@@ -4180,8 +4256,8 @@
 		if(ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx) < 0)
 		{
 			IPACMERR("Failed to get routing table index from name\n");
-			free(pFilteringTable_v4);
-			return IPACM_FAILURE;
+			res = IPACM_FAILURE;
+			goto fail;
 		}
 		IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
 
@@ -4203,7 +4279,8 @@
 		if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
 		{
 			IPACMERR("Failed to get eq_attrib\n");
-			return IPACM_FAILURE;
+			res = IPACM_FAILURE;
+			goto fail;
 		}
 		memcpy(&flt_rule_entry.rule.eq_attrib,
 			&flt_eq.eq_attrib,
@@ -4228,6 +4305,7 @@
 					IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
 					return IPACM_FAILURE;
 				}
+				memset(pFilteringTable_v4, 0, len);
 				pFilteringTable_v4->commit = 1;
 				pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
 				pFilteringTable_v4->global = false;
@@ -4250,6 +4328,7 @@
 					free(pFilteringTable_v4);
 					return IPACM_FAILURE;
 				}
+				memset(pFilteringTable_v6, 0, len);
 				pFilteringTable_v6->commit = 1;
 				pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
 				pFilteringTable_v6->global = false;
@@ -4270,6 +4349,7 @@
 				IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
 				return IPACM_FAILURE;
 			}
+			memset(pFilteringTable_v4, 0, len);
 			pFilteringTable_v4->commit = 1;
 			pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
 			pFilteringTable_v4->global = false;
@@ -4286,6 +4366,7 @@
 				free(pFilteringTable_v4);
 				return IPACM_FAILURE;
 			}
+			memset(pFilteringTable_v6, 0, len);
 			pFilteringTable_v6->commit = 1;
 			pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
 			pFilteringTable_v6->global = false;
@@ -4746,8 +4827,8 @@
 	}
 
 	IPACMDBG_H("Received mac_addr 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]);
+			mac_addr[0], mac_addr[1], mac_addr[2],
+			mac_addr[3], mac_addr[4], mac_addr[5]);
 
 	wan_index = get_wan_client_index(mac_addr);
 	if (wan_index == IPACM_INVALID_INDEX)
@@ -4758,31 +4839,31 @@
 
 	if (iptype==IPA_IP_v4) {
 		IPACMDBG_H("wan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wan_index, iptype,
-					 get_client_memptr(wan_client, wan_index)->ipv4_set,
-					 get_client_memptr(wan_client, wan_index)->route_rule_set_v4);
+				get_client_memptr(wan_client, wan_index)->ipv4_set,
+				get_client_memptr(wan_client, wan_index)->route_rule_set_v4);
 	} else {
 		IPACMDBG_H("wan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wan_index, iptype,
-					 get_client_memptr(wan_client, wan_index)->ipv6_set,
-					 get_client_memptr(wan_client, wan_index)->route_rule_set_v6);
+				get_client_memptr(wan_client, wan_index)->ipv6_set,
+				get_client_memptr(wan_client, wan_index)->route_rule_set_v6);
 	}
 
 	/* Add default routing rules if not set yet */
 	if ((iptype == IPA_IP_v4
-			 && get_client_memptr(wan_client, wan_index)->route_rule_set_v4 == false
-			 && get_client_memptr(wan_client, wan_index)->ipv4_set == true)
+				&& get_client_memptr(wan_client, wan_index)->route_rule_set_v4 == false
+				&& get_client_memptr(wan_client, wan_index)->ipv4_set == true)
 			|| (iptype == IPA_IP_v6
-		            && get_client_memptr(wan_client, wan_index)->route_rule_set_v6 < get_client_memptr(wan_client, wan_index)->ipv6_set
-					))
+				&& get_client_memptr(wan_client, wan_index)->route_rule_set_v6 < get_client_memptr(wan_client, wan_index)->ipv6_set
+			   ))
 	{
 
-        	/* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+		/* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
 		IPACMDBG_H("dev %s add producer dependency\n", dev_name);
 		IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
 		IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
 
 		rt_rule = (struct ipa_ioc_add_rt_rule *)
-			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
-						NUM * sizeof(struct ipa_rt_rule_add));
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+					NUM * sizeof(struct ipa_rt_rule_add));
 
 		if (rt_rule == NULL)
 		{
@@ -4797,70 +4878,79 @@
 		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
 		{
 			if(iptype != tx_prop->tx[tx_index].ip)
-		    {
+			{
 				IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
 						tx_index, tx_prop->tx[tx_index].ip,iptype);
-		   	        continue;
-		    }
+				continue;
+			}
 
 			rt_rule_entry = &rt_rule->rules[0];
 			rt_rule_entry->at_rear = 0;
 
 			if (iptype == IPA_IP_v4)
 			{
-		        IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wan_index,
-		  		        get_client_memptr(wan_client, wan_index)->v4_addr);
+				IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wan_index,
+						get_client_memptr(wan_client, wan_index)->v4_addr);
 
-                IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
-		  				 wan_index,
-		  				 get_client_memptr(wan_client, wan_index)->hdr_hdl_v4);
+				IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+						wan_index,
+						get_client_memptr(wan_client, wan_index)->hdr_hdl_v4);
 				strncpy(rt_rule->rt_tbl_name,
-								IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name,
-								sizeof(rt_rule->rt_tbl_name));
+						IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name,
+						sizeof(rt_rule->rt_tbl_name));
 
-			    rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
-			    memcpy(&rt_rule_entry->rule.attrib,
-						 &tx_prop->tx[tx_index].attrib,
-						 sizeof(rt_rule_entry->rule.attrib));
-			    rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
-		   	    rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, wan_index)->hdr_hdl_v4;
+				if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+				{
+					IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+							tx_prop->tx[tx_index].alt_dst_pipe);
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+				}
+				else
+				{
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+				}
+				memcpy(&rt_rule_entry->rule.attrib,
+						&tx_prop->tx[tx_index].attrib,
+						sizeof(rt_rule_entry->rule.attrib));
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+				rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, wan_index)->hdr_hdl_v4;
 				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wan_client, wan_index)->v4_addr;
 				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
 
-			    if (false == m_routing.AddRoutingRule(rt_rule))
+				if (false == m_routing.AddRoutingRule(rt_rule))
 				{
 					IPACMERR("Routing rule addition failed!\n");
 					free(rt_rule);
 					return IPACM_FAILURE;
 				}
 
-			    /* copy ipv4 RT hdl */
+				/* copy ipv4 RT hdl */
 				get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4 =
-  	   	        rt_rule->rules[0].rt_rule_hdl;
-		        IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
-				get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4, iptype);
-  	   	    } else {
+					rt_rule->rules[0].rt_rule_hdl;
+				IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+						get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4, iptype);
+			} else {
 
-		        for(v6_num = get_client_memptr(wan_client, wan_index)->route_rule_set_v6;v6_num < get_client_memptr(wan_client, wan_index)->ipv6_set;v6_num++)
-			    {
-                    IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
-		  	    			 wan_index,
-		  	    			 get_client_memptr(wan_client, wan_index)->hdr_hdl_v6);
+				for(v6_num = get_client_memptr(wan_client, wan_index)->route_rule_set_v6;v6_num < get_client_memptr(wan_client, wan_index)->ipv6_set;v6_num++)
+				{
+					IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+							wan_index,
+							get_client_memptr(wan_client, wan_index)->hdr_hdl_v6);
 
-		            /* v6 LAN_RT_TBL */
-			    	strncpy(rt_rule->rt_tbl_name,
-			    					IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
-			    					sizeof(rt_rule->rt_tbl_name));
+					/* v6 LAN_RT_TBL */
+					strncpy(rt_rule->rt_tbl_name,
+							IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+							sizeof(rt_rule->rt_tbl_name));
 
-		            /* Support QCMAP LAN traffic feature, send to A5 */
+					/* Support QCMAP LAN traffic feature, send to A5 */
 					rt_rule_entry->rule.dst = iface_query->excp_pipe;
-			        memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
-		   	        rt_rule_entry->rule.hdr_hdl = 0;
-			        rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][0];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][1];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][2];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][3];
+					memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
+					rt_rule_entry->rule.hdr_hdl = 0;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][3];
 					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
 					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
 					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
@@ -4868,47 +4958,56 @@
 
 					if (false == m_routing.AddRoutingRule(rt_rule))
 					{
-							IPACMERR("Routing rule addition failed!\n");
-							free(rt_rule);
-							return IPACM_FAILURE;
+						IPACMERR("Routing rule addition failed!\n");
+						free(rt_rule);
+						return IPACM_FAILURE;
 					}
 
-		            get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
-		            IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
-		            				 get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[v6_num], iptype);
+					get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+							get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[v6_num], iptype);
 
-			        /*Copy same rule to v6 WAN RT TBL*/
+					/*Copy same rule to v6 WAN RT TBL*/
 					strncpy(rt_rule->rt_tbl_name,
-						IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
-						sizeof(rt_rule->rt_tbl_name));
+							IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
+							sizeof(rt_rule->rt_tbl_name));
 
-                    /* Downlink traffic from Wan iface, directly through IPA */
-					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
-			        memcpy(&rt_rule_entry->rule.attrib,
-						 &tx_prop->tx[tx_index].attrib,
-						 sizeof(rt_rule_entry->rule.attrib));
-		   	        rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, wan_index)->hdr_hdl_v6;
-			        rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][0];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][1];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][2];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][3];
+					/* Downlink traffic from Wan iface, directly through IPA */
+					if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+					{
+						IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+								tx_prop->tx[tx_index].alt_dst_pipe);
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+					}
+					else
+					{
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+					}
+					memcpy(&rt_rule_entry->rule.attrib,
+							&tx_prop->tx[tx_index].attrib,
+							sizeof(rt_rule_entry->rule.attrib));
+					rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, wan_index)->hdr_hdl_v6;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][3];
 					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
 					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
 					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
 					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
 
-		            if (false == m_routing.AddRoutingRule(rt_rule))
-		            {
-							IPACMERR("Routing rule addition failed!\n");
-							free(rt_rule);
-							return IPACM_FAILURE;
-		            }
+					if (false == m_routing.AddRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule addition failed!\n");
+						free(rt_rule);
+						return IPACM_FAILURE;
+					}
 
-		            get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+					get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
 					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
-		            				 get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num], iptype);
-			    }
+							get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num], iptype);
+				}
 			}
 
 		} /* end of for loop */
@@ -4927,3 +5026,292 @@
 
 	return IPACM_SUCCESS;
 }
+
+/* TODO Handle wan client routing rules also */
+void IPACM_Wan::handle_wlan_SCC_MCC_switch(bool isSCCMode, ipa_ip_type iptype)
+{
+	struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_mdfy *rt_rule_entry;
+	uint32_t tx_index = 0;
+
+	IPACMDBG("\n");
+	if (tx_prop == NULL || is_default_gateway == false)
+	{
+		IPACMDBG_H("No tx properties or no default route set yet\n");
+		return;
+	}
+
+	const int NUM = tx_prop->num_tx_props;
+
+	for (tx_index = 0; tx_index < tx_prop->num_tx_props; tx_index++)
+	{
+		if (tx_prop->tx[tx_index].ip != iptype)
+		{
+			IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d Ignore\n",
+					tx_index, tx_prop->tx[tx_index].ip, iptype);
+			continue;
+		}
+
+		if (rt_rule == NULL)
+		{
+			rt_rule = (struct ipa_ioc_mdfy_rt_rule *)
+				calloc(1, sizeof(struct ipa_ioc_mdfy_rt_rule) +
+						NUM * sizeof(struct ipa_rt_rule_mdfy));
+
+			if (rt_rule == NULL)
+			{
+				IPACMERR("Unable to allocate memory for modify rt rule\n");
+				return;
+			}
+			IPACMDBG("Allocated memory for %d rules successfully\n", NUM);
+
+			rt_rule->commit = 1;
+			rt_rule->num_rules = 0;
+			rt_rule->ip = iptype;
+		}
+
+		rt_rule_entry = &rt_rule->rules[rt_rule->num_rules];
+
+		memcpy(&rt_rule_entry->rule.attrib,
+				&tx_prop->tx[tx_index].attrib,
+				sizeof(rt_rule_entry->rule.attrib));
+		rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+		if (iptype == IPA_IP_v4)
+		{
+			rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0;
+			rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
+			rt_rule_entry->rt_rule_hdl = wan_route_rule_v4_hdl[tx_index];
+		}
+		else
+		{
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+			rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+
+			rt_rule_entry->rt_rule_hdl = wan_route_rule_v6_hdl[tx_index];
+		}
+
+		if (isSCCMode)
+		{
+			rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+		}
+		else
+		{
+			IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+					tx_prop->tx[tx_index].alt_dst_pipe);
+			rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+		}
+
+		rt_rule->num_rules++;
+	}
+
+	if (rt_rule != NULL)
+	{
+
+		if (rt_rule->num_rules > 0)
+		{
+			if (false == m_routing.ModifyRoutingRule(rt_rule))
+			{
+				IPACMERR("Routing rule modify failed!\n");
+				free(rt_rule);
+				return;
+			}
+
+			IPACMDBG("Routing rule modified successfully \n");
+		}
+
+		free(rt_rule);
+	}
+
+	return;
+}
+
+void IPACM_Wan::handle_wan_client_SCC_MCC_switch(bool isSCCMode, ipa_ip_type iptype)
+{
+	struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_mdfy *rt_rule_entry;
+
+	uint32_t tx_index = 0, clnt_index =0;
+	int v6_num = 0;
+	const int NUM_RULES = 1;
+
+	int size = sizeof(struct ipa_ioc_mdfy_rt_rule) +
+		NUM_RULES * sizeof(struct ipa_rt_rule_mdfy);
+
+	IPACMDBG("\n");
+
+	if (tx_prop == NULL || is_default_gateway == false)
+	{
+		IPACMDBG_H("No tx properties or no default route set yet\n");
+		return;
+	}
+
+	rt_rule = (struct ipa_ioc_mdfy_rt_rule *)calloc(1, size);
+	if (rt_rule == NULL)
+	{
+		IPACMERR("Unable to allocate memory for modify rt rule\n");
+		return;
+	}
+
+
+	for (clnt_index = 0; clnt_index < num_wan_client; clnt_index++)
+	{
+		if (iptype == IPA_IP_v4)
+		{
+			IPACMDBG_H("wan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n",
+					clnt_index, iptype,
+					get_client_memptr(wan_client, clnt_index)->ipv4_set,
+					get_client_memptr(wan_client, clnt_index)->route_rule_set_v4);
+
+			if( get_client_memptr(wan_client, clnt_index)->route_rule_set_v4 == false ||
+					get_client_memptr(wan_client, clnt_index)->ipv4_set == false)
+			{
+				continue;
+			}
+
+			for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if (iptype != tx_prop->tx[tx_index].ip)
+				{
+					IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d skip\n",
+							tx_index, tx_prop->tx[tx_index].ip, iptype);
+					continue;
+				}
+
+				memset(rt_rule, 0, size);
+				rt_rule->commit = 1;
+				rt_rule->num_rules = NUM_RULES;
+				rt_rule->ip = iptype;
+				rt_rule_entry = &rt_rule->rules[0];
+
+				IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", clnt_index,
+						get_client_memptr(wan_client, clnt_index)->v4_addr);
+
+				IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+						clnt_index,
+						get_client_memptr(wan_client, clnt_index)->hdr_hdl_v4);
+
+				if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+				{
+					IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+							tx_prop->tx[tx_index].alt_dst_pipe);
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+				}
+				else
+				{
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+				}
+
+				memcpy(&rt_rule_entry->rule.attrib,
+						&tx_prop->tx[tx_index].attrib,
+						sizeof(rt_rule_entry->rule.attrib));
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+				rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, clnt_index)->hdr_hdl_v4;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wan_client, clnt_index)->v4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+				/* copy ipv4 RT rule hdl */
+				IPACMDBG_H("rt rule hdl=%x\n",
+						get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4);
+
+				rt_rule_entry->rt_rule_hdl =
+					get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4;
+
+				if (false == m_routing.ModifyRoutingRule(rt_rule))
+				{
+					IPACMERR("Routing rule modify failed!\n");
+					free(rt_rule);
+					return;
+				}
+			}
+		}
+		else
+		{
+			IPACMDBG_H("wan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", clnt_index, iptype,
+					get_client_memptr(wan_client, clnt_index)->ipv6_set,
+					get_client_memptr(wan_client, clnt_index)->route_rule_set_v6);
+
+			if( get_client_memptr(wan_client, clnt_index)->route_rule_set_v6 == 0)
+			{
+				continue;
+			}
+
+			for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if (iptype != tx_prop->tx[tx_index].ip)
+				{
+					IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d skip\n",
+							tx_index, tx_prop->tx[tx_index].ip, iptype);
+					continue;
+				}
+
+				memset(rt_rule, 0, size);
+				rt_rule->commit = 1;
+				rt_rule->num_rules = NUM_RULES;
+				rt_rule->ip = iptype;
+				rt_rule_entry = &rt_rule->rules[0];
+
+				/* Modify only rules in v6 WAN RT TBL*/
+				for (v6_num = 0;
+						v6_num < get_client_memptr(wan_client, clnt_index)->route_rule_set_v6;
+						v6_num++)
+				{
+					IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+							clnt_index,
+							get_client_memptr(wan_client, clnt_index)->hdr_hdl_v6);
+
+					/* Downlink traffic from Wan iface, directly through IPA */
+					if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+					{
+						IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+								tx_prop->tx[tx_index].alt_dst_pipe);
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+					}
+					else
+					{
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+					}
+
+					memcpy(&rt_rule_entry->rule.attrib,
+							&tx_prop->tx[tx_index].attrib,
+							sizeof(rt_rule_entry->rule.attrib));
+
+					rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, clnt_index)->hdr_hdl_v6;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+					IPACMDBG_H("rt rule hdl=%x\n",
+							get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num]);
+
+					rt_rule_entry->rt_rule_hdl =
+						get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num];
+
+					if (false == m_routing.ModifyRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule Modify failed!\n");
+						free(rt_rule);
+						return;
+					}
+				}
+			} /* end of for loop */
+		}
+
+	}
+
+	free(rt_rule);
+	return;
+}
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 9bb05d1..f75b806 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -90,6 +90,7 @@
 
 	num_wifi_client = 0;
 	header_name_count = 0;
+	wlan_client = NULL;
 
 	if(iface_query != NULL)
 	{
@@ -109,6 +110,23 @@
 		return;
 	}
 
+#ifdef FEATURE_ETH_BRIDGE_LE
+	exp_index_v4 = IPV4_DEFAULT_FILTERTING_RULES + 2 * IPACM_Iface::ipacmcfg->ipa_num_private_subnet
+			+ IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_USB_CLIENT + NUM_IPV4_ICMP_FLT_RULE;
+	exp_index_v6 = IPV6_DEFAULT_FILTERTING_RULES + 1 + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_USB_CLIENT + NUM_IPV6_PREFIX_FLT_RULE
+				+ NUM_IPV6_ICMP_FLT_RULE;
+#else
+#ifndef CT_OPT
+	exp_index_v4 = 2*(IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet) + NUM_IPV4_ICMP_FLT_RULE;
+	exp_index_v6 = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR) + NUM_IPV6_PREFIX_FLT_RULE + NUM_IPV6_ICMP_FLT_RULE;
+#else
+	exp_index_v4 = 2*(IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet) + NUM_IPV4_ICMP_FLT_RULE;
+	exp_index_v6 = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR) + NUM_IPV6_PREFIX_FLT_RULE + NUM_IPV6_ICMP_FLT_RULE;
+#endif
+#ifdef FEATURE_IPA_ANDROID
+	exp_index_v4 = exp_index_v4 + 2 * (IPA_MAX_PRIVATE_SUBNET_ENTRIES - IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+#endif
+#endif
 
 	IPACM_Wlan::num_wlan_ap_iface++;
 	IPACMDBG_H("Now the number of wlan AP iface is %d\n", IPACM_Wlan::num_wlan_ap_iface);
@@ -298,6 +316,10 @@
 										 info->ipv4_addr, info->addr_mask);
 						IPACM_EvtDispatcher::PostEvt(&evt_data);
 					}
+					if ((data->iptype == IPA_IP_v4) && (wlan_ap_index == 0))
+					{
+						IPACM_Lan::install_ipv4_icmp_flt_rule();
+					}
 					if ((num_dft_rt_v6 == 0) && (data->iptype == IPA_IP_v6) && (wlan_ap_index == 0))
 					{
 							install_ipv6_icmp_flt_rule();
@@ -617,7 +639,7 @@
 				{
 					/* Add NAT rules after ipv4 RT rules are set */
 					CtList->HandleNeighIpAddrAddEvt(data);
-//					Nat_App->ResetPwrSaveIf(data->ipv4_addr);
+					//Nat_App->ResetPwrSaveIf(data->ipv4_addr);
 				}
 			}
 		}
@@ -641,16 +663,13 @@
 			ipacm_event_data_mac* mac = (ipacm_event_data_mac*)param;
 			if(mac != NULL)
 			{
-				if(wlan_ap_index == 0)
+				if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
 				{
-					if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
-					{
-						eth_bridge_add_usb_client_flt_rule(mac->mac_addr, IPA_IP_v4);
-					}
-					if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
-					{
-						eth_bridge_add_usb_client_flt_rule(mac->mac_addr, IPA_IP_v6);
-					}
+					eth_bridge_add_usb_client_flt_rule(mac->mac_addr, IPA_IP_v4);
+				}
+				if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+				{
+					eth_bridge_add_usb_client_flt_rule(mac->mac_addr, IPA_IP_v6);
 				}
 			}
 			else
@@ -733,6 +752,59 @@
 	}
 	break;
 
+	case IPA_WLAN_SWITCH_TO_SCC:
+		IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_SCC\n");
+		if(ip_type == IPA_IP_MAX)
+		{
+			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_WLAN_SWITCH_TO_MCC:
+		IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_MCC\n");
+		if(ip_type == IPA_IP_MAX)
+		{
+			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;
 	}
@@ -1183,7 +1255,7 @@
 int IPACM_Wlan::handle_uplink_filter_rule(ipacm_ext_prop* prop, ipa_ip_type iptype)
 {
 	ipa_flt_rule_add flt_rule_entry;
-	int len = 0, cnt, ret = IPACM_SUCCESS, offset;
+	int len = 0, cnt, ret = IPACM_SUCCESS, index;
 	ipa_ioc_add_flt_rule *pFilteringTable;
 	ipa_fltr_installed_notif_req_msg_v01 flt_index;
 	int fd;
@@ -1213,6 +1285,13 @@
 	if (0 == fd)
 	{
 		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		return IPACM_FAILURE;
+	}
+	if (prop->num_ext_props > MAX_WAN_UL_FILTER_RULES)
+	{
+		IPACMERR("number of modem UL rules > MAX_WAN_UL_FILTER_RULES, aborting...\n");
+		close(fd);
+		return IPACM_FAILURE;
 	}
 
 	memset(&flt_index, 0, sizeof(flt_index));
@@ -1264,35 +1343,20 @@
 		goto fail;
 	}
 
-	if(iptype == IPA_IP_v4)
+	index = IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, iptype);
+
+#ifndef FEATURE_IPA_ANDROID
+	if(iptype == IPA_IP_v4 && index != exp_index_v4)
 	{
-#ifdef FEATURE_ETH_BRIDGE_LE
-		offset = IPV4_DEFAULT_FILTERTING_RULES + 2 * IPACM_Iface::ipacmcfg->ipa_num_private_subnet
-				+ IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_USB_CLIENT;
-#else
-#ifndef CT_OPT
-		offset = 2*(IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
-#else
-		offset = 2*(IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
-#endif
-#ifdef FEATURE_IPA_ANDROID
-		offset = offset + 2 * (IPA_MAX_PRIVATE_SUBNET_ENTRIES - IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
-#endif
-#endif
+		IPACMDBG_DMESG("### WARNING ### num flt rules for IPv4 on client %d is not expected: %d expected value: %d",
+			rx_prop->rx[0].src_pipe, index, exp_index_v4);
 	}
-	else
+	if(iptype == IPA_IP_v6 && index != exp_index_v6)
 	{
-#ifdef FEATURE_ETH_BRIDGE_LE
-		offset = IPV6_DEFAULT_FILTERTING_RULES + 1 + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_USB_CLIENT + NUM_IPV6_PREFIX_FLT_RULE
-				+ NUM_IPV6_ICMP_FLT_RULE;
-#else
-#ifndef CT_OPT
-		offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR) + NUM_IPV6_PREFIX_FLT_RULE + NUM_IPV6_ICMP_FLT_RULE;
-#else
-		offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR) + NUM_IPV6_PREFIX_FLT_RULE + NUM_IPV6_ICMP_FLT_RULE;
-#endif
-#endif
+		IPACMDBG_DMESG("### WARNING ### num flt rules for IPv6 on client %d is not expected: %d expected value: %d",
+			rx_prop->rx[0].src_pipe, index, exp_index_v6);
 	}
+#endif
 
 	for(cnt=0; cnt<prop->num_ext_props; cnt++)
 	{
@@ -1302,8 +1366,9 @@
 		flt_rule_entry.rule.rt_tbl_idx = prop->prop[cnt].rt_tbl_idx;
 		memcpy(&pFilteringTable->rules[cnt], &flt_rule_entry, sizeof(flt_rule_entry));
 
-		flt_index.filter_index_list[cnt].filter_index = offset+cnt;
-		IPACMDBG_H("Modem UL filtering rule %d has index %d\n", cnt, offset+cnt);
+		IPACMDBG_H("Modem UL filtering rule %d has index %d\n", cnt, index);
+		flt_index.filter_index_list[cnt].filter_index = index;
+		index++;
 
 		flt_index.filter_index_list[cnt].filter_handle = prop->prop[cnt].filter_hdl;
 	}
@@ -1330,6 +1395,7 @@
 				wan_ul_fl_rule_hdl_v4[num_wan_ul_fl_rule_v4] = pFilteringTable->rules[i].flt_rule_hdl;
 				num_wan_ul_fl_rule_v4++;
 			}
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, pFilteringTable->num_rules);
 		}
 		else if(iptype == IPA_IP_v6)
 		{
@@ -1338,6 +1404,7 @@
 				wan_ul_fl_rule_hdl_v6[num_wan_ul_fl_rule_v6] = pFilteringTable->rules[i].flt_rule_hdl;
 				num_wan_ul_fl_rule_v6++;
 			}
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, pFilteringTable->num_rules);
 		}
 		else
 		{
@@ -1739,8 +1806,8 @@
 	}
 
 	IPACMDBG_H("Received mac_addr 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]);
+			mac_addr[0], mac_addr[1], mac_addr[2],
+			mac_addr[3], mac_addr[4], mac_addr[5]);
 
 	wlan_index = get_wlan_client_index(mac_addr);
 	if (wlan_index == IPACM_INVALID_INDEX)
@@ -1756,31 +1823,31 @@
 		return IPACM_SUCCESS;
 	}
 
-        if (iptype==IPA_IP_v4)
+	if (iptype==IPA_IP_v4)
 	{
-	IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wlan_index, iptype,
-					 get_client_memptr(wlan_client, wlan_index)->ipv4_set,
-					 get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4);
+		IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wlan_index, iptype,
+				get_client_memptr(wlan_client, wlan_index)->ipv4_set,
+				get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4);
 	}
-        else
+	else
 	{
-	  IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wlan_index, iptype,
-					 get_client_memptr(wlan_client, wlan_index)->ipv6_set,
-					 get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6);
+		IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wlan_index, iptype,
+				get_client_memptr(wlan_client, wlan_index)->ipv6_set,
+				get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6);
 	}
 
 
 	/* Add default  Qos routing rules if not set yet */
 	if ((iptype == IPA_IP_v4
-			 && get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false
-			 && get_client_memptr(wlan_client, wlan_index)->ipv4_set == true)
+				&& get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false
+				&& get_client_memptr(wlan_client, wlan_index)->ipv4_set == true)
 			|| (iptype == IPA_IP_v6
-		            && get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 < get_client_memptr(wlan_client, wlan_index)->ipv6_set
-					))
+				&& get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 < get_client_memptr(wlan_client, wlan_index)->ipv6_set
+			   ))
 	{
 		rt_rule = (struct ipa_ioc_add_rt_rule *)
-			 calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
-						NUM * sizeof(struct ipa_rt_rule_add));
+			calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+					NUM * sizeof(struct ipa_rt_rule_add));
 
 		if (rt_rule == NULL)
 		{
@@ -1788,133 +1855,152 @@
 			return IPACM_FAILURE;
 		}
 
-		        rt_rule->commit = 1;
-	                rt_rule->num_rules = (uint8_t)NUM;
-		        rt_rule->ip = iptype;
+		rt_rule->commit = 1;
+		rt_rule->num_rules = (uint8_t)NUM;
+		rt_rule->ip = iptype;
 
 
 		for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
-  	        {
+		{
 
-		        if(iptype != tx_prop->tx[tx_index].ip)
-		        {
-		   	        IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
-		   	  				    tx_index, tx_prop->tx[tx_index].ip,iptype);
-		   	        continue;
-		        }
+			if(iptype != tx_prop->tx[tx_index].ip)
+			{
+				IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+						tx_index, tx_prop->tx[tx_index].ip,iptype);
+				continue;
+			}
 
-  	   	        rt_rule_entry = &rt_rule->rules[0];
+			rt_rule_entry = &rt_rule->rules[0];
 			rt_rule_entry->at_rear = 0;
 
 			if (iptype == IPA_IP_v4)
 			{
-		                IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wlan_index,
-		  				        get_client_memptr(wlan_client, wlan_index)->v4_addr);
+				IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wlan_index,
+						get_client_memptr(wlan_client, wlan_index)->v4_addr);
 
-                                IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
-		  				 wlan_index,
-		  				 get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4);
+				IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+						wlan_index,
+						get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4);
 				strncpy(rt_rule->rt_tbl_name,
-								IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
-								sizeof(rt_rule->rt_tbl_name));
+						IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
+						sizeof(rt_rule->rt_tbl_name));
 
 
-			        rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
-			        memcpy(&rt_rule_entry->rule.attrib,
-						 &tx_prop->tx[tx_index].attrib,
-						 sizeof(rt_rule_entry->rule.attrib));
-			        rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
-		   	        rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4;
+				if(IPACM_Iface::ipacmcfg->isMCC_Mode)
+				{
+					IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+							tx_prop->tx[tx_index].alt_dst_pipe);
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+				}
+				else
+				{
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+				}
+
+				memcpy(&rt_rule_entry->rule.attrib,
+						&tx_prop->tx[tx_index].attrib,
+						sizeof(rt_rule_entry->rule.attrib));
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+				rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4;
 				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wlan_client, wlan_index)->v4_addr;
 				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
 
-			        if (false == m_routing.AddRoutingRule(rt_rule))
-  	                        {
-  	          	            IPACMERR("Routing rule addition failed!\n");
-  	          	            free(rt_rule);
-  	          	            return IPACM_FAILURE;
-			        }
+				if (false == m_routing.AddRoutingRule(rt_rule))
+				{
+					IPACMERR("Routing rule addition failed!\n");
+					free(rt_rule);
+					return IPACM_FAILURE;
+				}
 
-			        /* copy ipv4 RT hdl */
-		                get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
-  	   	                rt_rule->rules[0].rt_rule_hdl;
-		                IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
-		      	        get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
-  	   	        }
-  	   	        else
-  	   	        {
-		            for(v6_num = get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6;v6_num < get_client_memptr(wlan_client, wlan_index)->ipv6_set;v6_num++)
-			    {
-                                IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
-		  	    			 wlan_index,
-		  	    			 get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6);
-
-		                /* v6 LAN_RT_TBL */
-			    	strncpy(rt_rule->rt_tbl_name,
-			    					IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
-			    					sizeof(rt_rule->rt_tbl_name));
-
-		                /* Support QCMAP LAN traffic feature, send to A5 */
-				rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
-			        memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
-		   	        rt_rule_entry->rule.hdr_hdl = 0;
-			        rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
-				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
-				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
-				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
-				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
-
-   	                        if (false == m_routing.AddRoutingRule(rt_rule))
-  	                        {
-  	                	    IPACMERR("Routing rule addition failed!\n");
-  	                	    free(rt_rule);
-  	                	    return IPACM_FAILURE;
-			        }
-
-		                get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
-		                IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
-		            				 get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[v6_num], iptype);
-
-			        /*Copy same rule to v6 WAN RT TBL*/
-  	                        strncpy(rt_rule->rt_tbl_name,
-  	                 					IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
-  	                 					sizeof(rt_rule->rt_tbl_name));
-
-                                /* Downlink traffic from Wan iface, directly through IPA */
-				rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
-			        memcpy(&rt_rule_entry->rule.attrib,
-						 &tx_prop->tx[tx_index].attrib,
-						 sizeof(rt_rule_entry->rule.attrib));
-		   	        rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6;
-			        rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
-		   	        rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
-				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
-				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
-				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
-				rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
-
-		               if (false == m_routing.AddRoutingRule(rt_rule))
-		               {
-			           IPACMERR("Routing rule addition failed!\n");
-			           free(rt_rule);
-			           return IPACM_FAILURE;
-		               }
-
-		                get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
-
+				/* copy ipv4 RT hdl */
+				get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+					rt_rule->rules[0].rt_rule_hdl;
 				IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
-		            				 get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num], iptype);
-			    }
+						get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
+			}
+			else
+			{
+				for(v6_num = get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6;v6_num < get_client_memptr(wlan_client, wlan_index)->ipv6_set;v6_num++)
+				{
+					IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+							wlan_index,
+							get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6);
+
+					/* v6 LAN_RT_TBL */
+					strncpy(rt_rule->rt_tbl_name,
+							IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+							sizeof(rt_rule->rt_tbl_name));
+
+					/* Support QCMAP LAN traffic feature, send to A5 */
+					rt_rule_entry->rule.dst = iface_query->excp_pipe;
+					memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
+					rt_rule_entry->rule.hdr_hdl = 0;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+					if (false == m_routing.AddRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule addition failed!\n");
+						free(rt_rule);
+						return IPACM_FAILURE;
+					}
+
+					get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+							get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[v6_num], iptype);
+
+					/*Copy same rule to v6 WAN RT TBL*/
+					strncpy(rt_rule->rt_tbl_name,
+							IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
+							sizeof(rt_rule->rt_tbl_name));
+
+					/* Downlink traffic from Wan iface, directly through IPA */
+					if(IPACM_Iface::ipacmcfg->isMCC_Mode)
+					{
+						IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+								tx_prop->tx[tx_index].alt_dst_pipe);
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+					}
+					else
+					{
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+					}
+					memcpy(&rt_rule_entry->rule.attrib,
+							&tx_prop->tx[tx_index].attrib,
+							sizeof(rt_rule_entry->rule.attrib));
+					rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+					if (false == m_routing.AddRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule addition failed!\n");
+						free(rt_rule);
+						return IPACM_FAILURE;
+					}
+
+					get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+
+					IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+							get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num], iptype);
+				}
 			}
 
-  	        } /* end of for loop */
+		} /* end of for loop */
 
 		free(rt_rule);
 
@@ -2123,6 +2209,14 @@
 #ifdef FEATURE_ETH_BRIDGE_LE
 		if(wlan_ap_index == 0)
 		{
+			/* delete IPv4 icmp filter rules */
+			if(m_filtering.DeleteFilteringHdls(ipv4_icmp_flt_rule_hdl, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE) == false)
+			{
+				IPACMERR("Error Deleting ICMPv4 Filtering Rule, aborting...\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE);
 			/* delete default filter rules */
 			for(i=0; i<IPV4_DEFAULT_FILTERTING_RULES; i++)
 			{
@@ -2163,17 +2257,6 @@
 		}
 		IPACMDBG_H("Deleted guest ap v4 filter rules successfully.\n");
 #endif
-
-		/* delete icmp filter rules */
-		if(wlan_ap_index == 0)
-		{
-			if(m_filtering.DeleteFilteringHdls(ipv6_icmp_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE) == false)
-			{
-				IPACMERR("Error Deleting ICMPv6 Filtering Rule, aborting...\n");
-				res = IPACM_FAILURE;
-				goto fail;
-			}
-		}
 #ifndef FEATURE_ETH_BRIDGE_LE
 #ifdef CT_OPT
 		IPACMDBG_H("Delete tcp control flt rules.\n");
@@ -2232,6 +2315,17 @@
 	/* Delete v6 filtering rules */
 	if (ip_type != IPA_IP_v4 && rx_prop != NULL)
 	{
+		/* delete icmp filter rules */
+		if(wlan_ap_index == 0)
+		{
+			if(m_filtering.DeleteFilteringHdls(ipv6_icmp_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE) == false)
+			{
+				IPACMERR("Error Deleting ICMPv6 Filtering Rule, aborting...\n");
+				res = IPACM_FAILURE;
+				goto fail;
+			}
+			IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE);
+		}
 		IPACMDBG_H("Delete default %d v6 filter rules\n", IPV6_DEFAULT_FILTERTING_RULES);
 		/* delete default filter rules */
 #ifdef FEATURE_ETH_BRIDGE_LE
@@ -2426,9 +2520,15 @@
 
 	for (i = 0; i < num_wifi_client; i++)
 	{
-		free(get_client_memptr(wlan_client, i)->p_hdr_info);
+		if(get_client_memptr(wlan_client, i)->p_hdr_info != NULL)
+		{
+			free(get_client_memptr(wlan_client, i)->p_hdr_info);
+		}
 	}
-	free(wlan_client);
+	if(wlan_client != NULL)
+	{
+		free(wlan_client);
+	}
 	if (tx_prop != NULL)
 	{
 		free(tx_prop);
@@ -2977,6 +3077,7 @@
 		}
 		else
 		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, num_rule);
 			/* copy filter rule hdls */
 			for (int i = 0; i < num_rule; i++)
 			{
@@ -3027,6 +3128,7 @@
 		}
 		else
 		{
+			IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, num_rule);
 			/* copy filter rule hdls */
 			for (int i = 0; i < num_rule; i++)
 			{
@@ -3088,11 +3190,13 @@
 			IPACMERR("Failed to delete ipv4 dummy flt rules.\n");
 			return;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_v4_dummy_rule);
 		if(m_filtering.DeleteFilteringHdls(IPACM_Wlan::dummy_flt_rule_hdl_v6, IPA_IP_v6, num_v6_dummy_rule) == false)
 		{
 			IPACMERR("Failed to delete ipv6 dummy flt rules.\n");
 			return;
 		}
+		IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_v6_dummy_rule);
 
 		free(IPACM_Wlan::dummy_flt_rule_hdl_v4);
 		IPACM_Wlan::dummy_flt_rule_hdl_v4 = NULL;
@@ -3166,11 +3270,14 @@
 
 	flt_rule.rule.eq_attrib.rule_eq_bitmap = 0;
 
-	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
-	flt_rule.rule.eq_attrib.metadata_meq32_present = 1;
-	flt_rule.rule.eq_attrib.metadata_meq32.offset = 0;
-	flt_rule.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
-	flt_rule.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
+	if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA)
+	{
+		flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
+		flt_rule.rule.eq_attrib.metadata_meq32_present = 1;
+		flt_rule.rule.eq_attrib.metadata_meq32.offset = 0;
+		flt_rule.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
+		flt_rule.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
+	}
 
 	flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
 	flt_rule.rule.eq_attrib.protocol_eq_present = 1;
@@ -3518,6 +3625,11 @@
 		IPACMERR("MAC address is empty.\n");
 		return IPACM_FAILURE;
 	}
+	if(wlan_ap_index != 0)
+	{
+		IPACMDBG_H("This is WLAN interface index %d, ignore.\n", wlan_ap_index);
+		return IPACM_SUCCESS;
+	}
 	if(IPACM_Lan::wlan_to_usb_hdr_proc_ctx.valid == false)
 	{
 		IPACMDBG_H("WLAN to USB hdr proc ctx has not been set, don't add USB client specific flt rule.\n");
@@ -3595,6 +3707,7 @@
 	}
 
 	memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule.rule.attrib));
+	flt_rule.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);	//remove meta data mask
 	if(IPACM_Lan::wlan_hdr_type == IPA_HDR_L2_ETHERNET_II)
 	{
 		flt_rule.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
@@ -4230,8 +4343,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
 			{
@@ -4561,3 +4684,464 @@
 	IPACM_Lan::num_wlan_client--;
 	return;
 }
+
+void IPACM_Wlan::handle_SCC_MCC_switch(ipa_ip_type iptype)
+{
+	struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+	struct ipa_rt_rule_mdfy *rt_rule_entry;
+	uint32_t tx_index;
+	int wlan_index, v6_num;
+	const int NUM = 1;
+	int num_wifi_client_tmp = IPACM_Wlan::num_wifi_client;
+	bool isAdded = false;
+
+	if (tx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return;
+	}
+
+	if (rt_rule == NULL)
+	{
+		rt_rule = (struct ipa_ioc_mdfy_rt_rule *)
+			calloc(1, sizeof(struct ipa_ioc_mdfy_rt_rule) +
+					NUM * sizeof(struct ipa_rt_rule_mdfy));
+
+		if (rt_rule == NULL)
+		{
+			PERROR("Error Locate ipa_ioc_mdfy_rt_rule memory...\n");
+			return;
+		}
+
+		rt_rule->commit = 0;
+		rt_rule->num_rules = NUM;
+		rt_rule->ip = iptype;
+	}
+	rt_rule_entry = &rt_rule->rules[0];
+
+	/* modify ipv4 routing rule */
+	if (iptype == IPA_IP_v4)
+	{
+		for (wlan_index = 0; wlan_index < num_wifi_client_tmp; wlan_index++)
+		{
+			IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n",
+					wlan_index, iptype,
+					get_client_memptr(wlan_client, wlan_index)->ipv4_set,
+					get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4);
+
+			if (get_client_memptr(wlan_client, wlan_index)->power_save_set == true ||
+					get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false)
+			{
+				IPACMDBG_H("client %d route rules not set\n", wlan_index);
+				continue;
+			}
+
+			IPACMDBG_H("Modify client %d route rule\n", wlan_index);
+			for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if (iptype != tx_prop->tx[tx_index].ip)
+				{
+					IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d ignore\n",
+							tx_index, tx_prop->tx[tx_index].ip, iptype);
+					continue;
+				}
+
+				IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wlan_index,
+						get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+				IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+						wlan_index,
+						get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4);
+
+				if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+				{
+					IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+							tx_prop->tx[tx_index].alt_dst_pipe);
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+				}
+				else
+				{
+					rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+				}
+
+				memcpy(&rt_rule_entry->rule.attrib,
+						&tx_prop->tx[tx_index].attrib,
+						sizeof(rt_rule_entry->rule.attrib));
+
+				rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+				rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4;
+
+				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wlan_client, wlan_index)->v4_addr;
+				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+				IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+						get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
+
+				rt_rule_entry->rt_rule_hdl =
+					get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+				if (false == m_routing.ModifyRoutingRule(rt_rule))
+				{
+					IPACMERR("Routing rule modify failed!\n");
+					free(rt_rule);
+					return;
+				}
+				isAdded = true;
+			}
+
+		}
+	}
+
+	/* modify ipv6 routing rule */
+	if (iptype == IPA_IP_v6)
+	{
+		for (wlan_index = 0; wlan_index < num_wifi_client_tmp; wlan_index++)
+		{
+
+			IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wlan_index, iptype,
+					get_client_memptr(wlan_client, wlan_index)->ipv6_set,
+					get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6);
+
+			if (get_client_memptr(wlan_client, wlan_index)->power_save_set == true ||
+					(get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 <
+					 get_client_memptr(wlan_client, wlan_index)->ipv6_set) )
+			{
+				IPACMDBG_H("client %d route rules not set\n", wlan_index);
+				continue;
+			}
+
+			IPACMDBG_H("Modify client %d route rule\n", wlan_index);
+			for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+			{
+				if (iptype != tx_prop->tx[tx_index].ip)
+				{
+					IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d Ignore\n",
+							tx_index, tx_prop->tx[tx_index].ip, iptype);
+					continue;
+				}
+
+				for (v6_num = get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6;
+						v6_num < get_client_memptr(wlan_client, wlan_index)->ipv6_set;
+						v6_num++)
+				{
+
+					IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+							wlan_index,
+							get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6);
+
+					if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+					{
+						IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+								tx_prop->tx[tx_index].alt_dst_pipe);
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+					}
+					else
+					{
+						rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+					}
+
+					memcpy(&rt_rule_entry->rule.attrib,
+							&tx_prop->tx[tx_index].attrib,
+							sizeof(rt_rule_entry->rule.attrib));
+
+					rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6;
+					rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+					rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+					rt_rule_entry->rt_rule_hdl =
+						get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num];
+
+					if (false == m_routing.ModifyRoutingRule(rt_rule))
+					{
+						IPACMERR("Routing rule modify failed!\n");
+						free(rt_rule);
+						return;
+					}
+					isAdded = true;
+				}
+			}
+
+		}
+	}
+
+
+	if (isAdded)
+	{
+		if (false == m_routing.Commit(iptype))
+		{
+			IPACMERR("Routing rule modify commit failed!\n");
+			free(rt_rule);
+			return;
+		}
+
+		IPACMDBG("Routing rule modified successfully \n");
+	}
+
+	if(rt_rule)
+	{
+		free(rt_rule);
+	}
+	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..03af08c 100644
--- a/ipacm/src/IPACM_Xml.cpp
+++ b/ipacm/src/IPACM_Xml.cpp
@@ -234,6 +234,28 @@
 					}
 				}
 				else if (IPACM_util_icmp_string((char*)xml_node->name,
+																	ODUEMBMS_OFFLOAD_TAG) == 0)
+				{
+					IPACMDBG("inside ODU-XML\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->odu_embms_enable = true;
+							IPACMDBG("router-mode enable %d buf(%d)\n", config->odu_embms_enable, atoi(content_buf));
+						}
+						else
+						{
+							config->odu_embms_enable = false;
+							IPACMDBG("router-mode enable %d buf(%d)\n", config->odu_embms_enable, atoi(content_buf));
+						}
+					}
+				}
+				else if (IPACM_util_icmp_string((char*)xml_node->name,
 																				NAME_TAG) == 0)
 				{
 					content = IPACM_read_content_element(xml_node);
@@ -292,6 +314,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..6b3d6b9 100644
--- a/ipacm/src/IPACM_cfg.xml
+++ b/ipacm/src/IPACM_cfg.xml
@@ -2,6 +2,7 @@
 <system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ipacm_cfg.xsd">
 	<ODUCFG>
 		<Mode>router</Mode>
+		<eMBMS_offload>0</eMBMS_offload>
 	</ODUCFG>
 	<IPACM>
 		<IPACMIface>
@@ -12,6 +13,7 @@
 			<Iface>
 			   <Name>ecm0</Name>
 			   <Category>LAN</Category>
+			   <Mode>ROUTER</Mode>
 			</Iface>
 			<Iface>
 			   <Name>rmnet_data0</Name>
@@ -144,4 +146,4 @@
  	        <MaxNatEntries>500</MaxNatEntries>
 		</IPACMNAT>
 		</IPACM>
-</system>
\ No newline at end of file
+</system>
diff --git a/ipanat/src/ipa_nat_drvi.c b/ipanat/src/ipa_nat_drvi.c
index 74161a7..32114b5 100644
--- a/ipanat/src/ipa_nat_drvi.c
+++ b/ipanat/src/ipa_nat_drvi.c
@@ -665,6 +665,9 @@
 		return -EINVAL;
 	}
 
+	/* Reset the nat table before posting init cmd */
+	ipa_nati_reset_tbl(tbl_indx);
+
 	/* Initialize the ipa hw with nat table dimensions */
 	ret = ipa_nati_post_ipv4_init_cmd(tbl_indx);
 	if (0 != ret) {
@@ -672,8 +675,6 @@
 		return -EINVAL;
 	}
 
-	ipa_nati_reset_tbl(tbl_indx);
-
 	/* Return table handle */
 	ipv4_nat_cache.table_cnt++;
 	*tbl_hdl = ipv4_nat_cache.table_cnt;