Merge "IPACM: change src mac to bridge0"
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index b40d91d..677b122 100644
--- a/ipacm/inc/IPACM_Defs.h
+++ b/ipacm/inc/IPACM_Defs.h
@@ -113,6 +113,7 @@
 #define TCP_SYN_SHIFT 17
 #define TCP_RST_SHIFT 18
 #define NUM_TCP_CTL_FLT_RULE 3
+#define NUM_IPV6_PREFIX_FLT_RULE 1
 
 /*---------------------------------------------------------------------------
 										Return values indicating error status
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
index 3579567..62ea189 100644
--- a/ipacm/inc/IPACM_Lan.h
+++ b/ipacm/inc/IPACM_Lan.h
@@ -55,7 +55,6 @@
 #define IPA_NUM_ODU_ROUTE_RULES 2
 #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
 
 /* ndc bandwidth ipatetherstats <ifaceIn> <ifaceOut> */
@@ -306,7 +305,9 @@
 	/*handle lan2lan client active*/
 	int handle_lan2lan_client_active(ipacm_event_data_all *data, ipa_cm_event_id event);
 
-	int install_ipv6_prefix_flt_rule(uint32_t* prefix);
+	virtual int install_ipv6_prefix_flt_rule(uint32_t* prefix);
+
+	virtual void delete_ipv6_prefix_flt_rule();
 
 	int install_ipv6_icmp_flt_rule();
 
diff --git a/ipacm/inc/IPACM_Wlan.h b/ipacm/inc/IPACM_Wlan.h
index d14368f..6a2d53a 100644
--- a/ipacm/inc/IPACM_Wlan.h
+++ b/ipacm/inc/IPACM_Wlan.h
@@ -319,6 +319,10 @@
 	/*handle wlan access mode switch */
 	void eth_bridge_handle_wlan_mode_switch();
 
+	virtual int install_ipv6_prefix_flt_rule(uint32_t* prefix);
+
+	virtual void delete_ipv6_prefix_flt_rule();
+
 };
 
 
diff --git a/ipacm/src/Android.mk b/ipacm/src/Android.mk
index 5042501..5482a0b 100644
--- a/ipacm/src/Android.mk
+++ b/ipacm/src/Android.mk
@@ -30,6 +30,11 @@
 ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
 LOCAL_CFLAGS += -DDEBUG
 endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),msm8998)
+LOCAL_CFLAGS += -DFEATURE_IPA_V3
+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
diff --git a/ipacm/src/IPACM_Filtering.cpp b/ipacm/src/IPACM_Filtering.cpp
index 931aff4..bd8dadb 100644
--- a/ipacm/src/IPACM_Filtering.cpp
+++ b/ipacm/src/IPACM_Filtering.cpp
@@ -261,13 +261,27 @@
 
 		if (num_rules > 0)
 		{
+#ifndef FEATURE_IPA_V3
 			qmi_rule_msg.filter_spec_list_valid = true;
+#else /* defined (FEATURE_IPA_V3) */
+			qmi_rule_msg.filter_spec_ex_list_valid = true;
+#endif
 		}
 		else
 		{
+#ifndef FEATURE_IPA_V3
 			qmi_rule_msg.filter_spec_list_valid = false;
+#else /* defined (FEATURE_IPA_V3) */
+			qmi_rule_msg.filter_spec_ex_list_valid = false;
+#endif
 		}
+
+#ifndef FEATURE_IPA_V3
 		qmi_rule_msg.filter_spec_list_len = num_rules;
+#else /* defined (FEATURE_IPA_V3) */
+		qmi_rule_msg.filter_spec_ex_list_len = num_rules;
+#endif
+
 		qmi_rule_msg.source_pipe_index_valid = 0;
 
 		IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
@@ -278,18 +292,32 @@
 			{
 				if (pos < QMI_IPA_MAX_FILTERS_V01)
 				{
-				qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
-				qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
-				qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
-				qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
-				qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
-				qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
-				qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
-
-				memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule, &rule_table_v4->rules[cnt].rule.eq_attrib, 
-					sizeof(struct ipa_filter_rule_type_v01));
-				pos++;
-			}
+#ifndef FEATURE_IPA_V3
+					qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
+					qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
+					qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
+					qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
+					qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
+					qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
+					qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
+					memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
+						&rule_table_v4->rules[cnt].rule.eq_attrib,
+						sizeof(struct ipa_filter_rule_type_v01));
+#else /* defined (FEATURE_IPA_V3) */
+					qmi_rule_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
+					qmi_rule_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
+					qmi_rule_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
+					qmi_rule_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
+					qmi_rule_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
+					qmi_rule_msg.filter_spec_ex_list[pos].mux_id = mux_id;
+					qmi_rule_msg.filter_spec_ex_list[pos].rule_id = rule_table_v4->rules[cnt].rule.rule_id;
+					qmi_rule_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v4->rules[cnt].rule.hashable;
+					memcpy(&qmi_rule_msg.filter_spec_ex_list[pos].filter_rule,
+						&rule_table_v4->rules[cnt].rule.eq_attrib,
+						sizeof(struct ipa_filter_rule_type_v01));
+#endif
+					pos++;
+				}
 				else
 				{
 					IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
@@ -303,18 +331,32 @@
 			{
 				if (pos < QMI_IPA_MAX_FILTERS_V01)
 				{
-				qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
-				qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
-				qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
-				qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
-				qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
-				qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
-				qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
-
-				memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule, &rule_table_v6->rules[cnt].rule.eq_attrib, 
-					sizeof(struct ipa_filter_rule_type_v01));
-				pos++;
-			}
+#ifndef FEATURE_IPA_V3
+					qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
+					qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
+					qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
+					qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
+					qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
+					qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
+					qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
+					memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
+						&rule_table_v6->rules[cnt].rule.eq_attrib,
+						sizeof(struct ipa_filter_rule_type_v01));
+#else /* defined (FEATURE_IPA_V3) */
+					qmi_rule_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
+					qmi_rule_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
+					qmi_rule_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
+					qmi_rule_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
+					qmi_rule_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
+					qmi_rule_msg.filter_spec_ex_list[pos].mux_id = mux_id;
+					qmi_rule_msg.filter_spec_ex_list[pos].rule_id = rule_table_v6->rules[cnt].rule.rule_id;
+					qmi_rule_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v6->rules[cnt].rule.hashable;
+					memcpy(&qmi_rule_msg.filter_spec_ex_list[pos].filter_rule,
+						&rule_table_v6->rules[cnt].rule.eq_attrib,
+						sizeof(struct ipa_filter_rule_type_v01));
+#endif
+					pos++;
+				}
 				else
 				{
 					IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
diff --git a/ipacm/src/IPACM_Iface.cpp b/ipacm/src/IPACM_Iface.cpp
index cbf1502..5dc7647 100644
--- a/ipacm/src/IPACM_Iface.cpp
+++ b/ipacm/src/IPACM_Iface.cpp
@@ -744,6 +744,10 @@
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.rule.hashable = IPA_RULE_NON_HASHABLE;
+#endif
 		IPACMDBG_H("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
 		memcpy(&flt_rule_entry.rule.attrib,
 					 &rx_prop->rx[0].attrib,
@@ -815,7 +819,6 @@
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
-
 		/* Configuring Multicast Filtering Rule */
 		memcpy(&flt_rule_entry.rule.attrib,
 					 &rx_prop->rx[0].attrib,
@@ -865,7 +868,6 @@
 		flt_rule_entry.rule.to_uc = 0;
 		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
 		flt_rule_entry.rule.eq_attrib_type = 1;
-
 		flt_rule_entry.rule.eq_attrib.rule_eq_bitmap = 0;
 
 		if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA)
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index eb7243b..0878d29 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -1241,7 +1241,12 @@
 		memset(&flt_index, 0, sizeof(flt_index));
 		flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
 		flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
 		flt_index.filter_index_list_len = 0;
+#else /* defined (FEATURE_IPA_V3) */
+		flt_index.rule_id_valid = 1;
+		flt_index.rule_id_len = 0;
+#endif
 		flt_index.embedded_pipe_index_valid = 1;
 		flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
 		flt_index.retain_header_valid = 1;
@@ -1393,7 +1398,6 @@
 		ipv6_addr[num_dft_rt_v6][1] = data->ipv6_addr[1];
 		ipv6_addr[num_dft_rt_v6][2] = data->ipv6_addr[2];
 		ipv6_addr[num_dft_rt_v6][3] = data->ipv6_addr[3];
-
 		if (false == m_routing.AddRoutingRule(rt_rule))
 		{
 			IPACMERR("Routing rule addition failed!\n");
@@ -1514,7 +1518,6 @@
 			flt_rule_entry.flt_rule_hdl = -1;
 			flt_rule_entry.status = -1;
 			flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
-
                         /* Support private subnet feature including guest-AP can't talk to primary AP etc */
 			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
 			IPACMDBG_H(" private filter rule use table: %s\n",IPACM_Iface::ipacmcfg->rt_tbl_default_v4.name);
@@ -1669,7 +1672,7 @@
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
-			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+		flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
 
 		memcpy(&flt_rule_entry.rule.attrib,
 					 &rx_prop->rx[0].attrib,
@@ -2217,7 +2220,6 @@
 		   	    rt_rule_entry->rule.hdr_hdl = get_client_memptr(eth_client, eth_index)->hdr_hdl_v4;
 				rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(eth_client, eth_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");
@@ -2257,7 +2259,6 @@
 					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");
@@ -2287,7 +2288,6 @@
 					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");
@@ -2559,7 +2559,6 @@
 		{
 			rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0;
 			rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
-
 			if (false == m_routing.AddRoutingRule(rt_rule))
 			{
 				IPACMERR("Routing rule addition failed!\n");
@@ -2582,7 +2581,6 @@
 			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");
@@ -3268,17 +3266,25 @@
 	memset(&flt_index, 0, sizeof(flt_index));
 	flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
 	flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
 	flt_index.filter_index_list_len = prop->num_ext_props;
+#else /* defined (FEATURE_IPA_V3) */
+	flt_index.rule_id_valid = 1;
+	flt_index.rule_id_len = prop->num_ext_props;
+#endif
 	flt_index.embedded_pipe_index_valid = 1;
 	flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
 	flt_index.retain_header_valid = 1;
 	flt_index.retain_header = 0;
 	flt_index.embedded_call_mux_id_valid = 1;
 	flt_index.embedded_call_mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
-
-	IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n", flt_index.source_pipe_index,
-				flt_index.filter_index_list_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
-
+#ifndef FEATURE_IPA_V3
+	IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n",
+		flt_index.source_pipe_index, flt_index.filter_index_list_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
+#else /* defined (FEATURE_IPA_V3) */
+	IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n",
+		flt_index.source_pipe_index, flt_index.rule_id_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
+#endif
 	len = sizeof(struct ipa_ioc_add_flt_rule) + prop->num_ext_props * sizeof(struct ipa_flt_rule_add);
 	pFilteringTable = (struct ipa_ioc_add_flt_rule*)malloc(len);
 	if (pFilteringTable == NULL)
@@ -3296,6 +3302,10 @@
 
 	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
 	flt_rule_entry.at_rear = 1;
+#ifdef FEATURE_IPA_V3
+	if (flt_rule_entry.rule.eq_attrib.ipv4_frag_eq_present)
+		flt_rule_entry.at_rear = 0;
+#endif
 	flt_rule_entry.flt_rule_hdl = -1;
 	flt_rule_entry.status = -1;
 
@@ -3358,13 +3368,20 @@
 			IPACMDBG_H("xlat meta-data is modified for rule: %d has index %d with xlat_mux_id: %d\n",
 					cnt, index, xlat_mux_id);
 		}
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = prop->prop[cnt].is_rule_hashable;
+		flt_rule_entry.rule.rule_id = prop->prop[cnt].rule_id;
+#endif
 		memcpy(&pFilteringTable->rules[cnt], &flt_rule_entry, sizeof(flt_rule_entry));
 
 		IPACMDBG_H("Modem UL filtering rule %d has index %d\n", cnt, index);
+#ifndef FEATURE_IPA_V3
 		flt_index.filter_index_list[cnt].filter_index = index;
-		index++;
-
 		flt_index.filter_index_list[cnt].filter_handle = prop->prop[cnt].filter_hdl;
+#else /* defined (FEATURE_IPA_V3) */
+		flt_index.rule_id[cnt] = prop->prop[cnt].rule_id;
+#endif
+		index++;
 	}
 
 	if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
@@ -3424,12 +3441,9 @@
 		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
 		return IPACM_FAILURE;
 	}
-	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);
+
+	delete_ipv6_prefix_flt_rule();
+
 	if(is_sta_mode == false)
 	{
 		if (num_wan_ul_fl_rule_v6 > MAX_WAN_UL_FILTER_RULES)
@@ -3438,6 +3452,13 @@
 			close(fd);
 			return IPACM_FAILURE;
 		}
+		if (num_wan_ul_fl_rule_v6 == 0)
+		{
+			IPACMERR("No modem UL rules were installed, return...\n");
+			close(fd);
+			return IPACM_FAILURE;
+		}
+
 		if (m_filtering.DeleteFilteringHdls(wan_ul_fl_rule_hdl_v6,
 			IPA_IP_v6, num_wan_ul_fl_rule_v6) == false)
 		{
@@ -3452,7 +3473,12 @@
 		memset(&flt_index, 0, sizeof(flt_index));
 		flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
 		flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
 		flt_index.filter_index_list_len = 0;
+#else /* defined (FEATURE_IPA_V3) */
+		flt_index.rule_id_valid = 1;
+		flt_index.rule_id_len = 0;
+#endif
 		flt_index.embedded_pipe_index_valid = 1;
 		flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
 		flt_index.retain_header_valid = 1;
@@ -3775,7 +3801,6 @@
 	flt_rule.flt_rule_hdl = -1;
 	flt_rule.status = -1;
 	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
-
 	memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
 			sizeof(flt_rule.rule.attrib));
 
@@ -4381,7 +4406,6 @@
 			rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
 			rt_rule_entry->rule.attrib.u.v4.dst_addr      = dst_v4_addr;
 			rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
-
 			if(m_routing.AddRoutingRule(rt_rule) == false)
 			{
 				IPACMERR("Routing rule addition failed\n");
@@ -4443,7 +4467,6 @@
 			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(m_routing.AddRoutingRule(rt_rule) == false)
 			{
 				IPACMERR("Routing rule addition failed\n");
@@ -4643,7 +4666,6 @@
 		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);
@@ -4705,6 +4727,9 @@
 	flt_rule.rule.retain_hdr = 1;
 	flt_rule.rule.to_uc = 0;
 	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+	flt_rule.rule.hashable = IPA_RULE_NON_HASHABLE;
+#endif
 	flt_rule.rule.eq_attrib_type = 1;
 
 	flt_rule.rule.eq_attrib.rule_eq_bitmap = 0;
@@ -4811,7 +4836,6 @@
 	flt_rule.flt_rule_hdl = -1;
 	flt_rule.status = -1;
 	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
-
 	memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
 			sizeof(flt_rule.rule.attrib));
 
@@ -4980,7 +5004,9 @@
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
-
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = IPA_RULE_NON_HASHABLE;
+#endif
 		memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
 		flt_rule_entry.rule.attrib.attrib_mask = flt_rule_entry.rule.attrib.attrib_mask & ~((uint32_t)IPA_FLT_META_DATA);
 		flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
@@ -5011,6 +5037,17 @@
 	return IPACM_SUCCESS;
 }
 
+void IPACM_Lan::delete_ipv6_prefix_flt_rule()
+{
+	if(m_filtering.DeleteFilteringHdls(ipv6_prefix_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE) == false)
+	{
+		IPACMERR("Failed to delete ipv6 prefix flt rule.\n");
+		return;
+	}
+	IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE);
+	return;
+}
+
 int IPACM_Lan::install_ipv6_icmp_flt_rule()
 {
 
@@ -5044,7 +5081,9 @@
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
-
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = IPA_RULE_NON_HASHABLE;
+#endif
 		memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
 		flt_rule_entry.rule.attrib.attrib_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;
@@ -5136,7 +5175,6 @@
 	flt_rule.flt_rule_hdl = -1;
 	flt_rule.status = -1;
 	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
-
 	memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
 			sizeof(flt_rule.rule.attrib));
 
@@ -5287,7 +5325,6 @@
 	flt_rule.flt_rule_hdl = -1;
 	flt_rule.status = -1;
 	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
-
 	memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
 			sizeof(flt_rule.rule.attrib));
 
@@ -6460,7 +6497,6 @@
 			position++;
 		}
 	}
-
 	if(false == m_routing.AddRoutingRule(rt_rule_table))
 	{
 		IPACMERR("Routing rule addition failed!\n");
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index a9bfc53..cf8d98e 100644
--- a/ipacm/src/IPACM_Wan.cpp
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -271,7 +271,9 @@
 	    	ipv6_addr[num_dft_rt_v6][1] = data->ipv6_addr[1];
 	    	ipv6_addr[num_dft_rt_v6][2] = data->ipv6_addr[2];
 	    	ipv6_addr[num_dft_rt_v6][3] = data->ipv6_addr[3];
-
+#ifdef FEATURE_IPA_V3
+		rt_rule_entry->rule.hashable = IPA_RULE_NON_HASHABLE;
+#endif
 	        if (false == m_routing.AddRoutingRule(rt_rule))
 	        {
 	        	IPACMERR("Routing rule addition failed!\n");
@@ -355,7 +357,6 @@
 				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 |= IPA_FLT_DST_ADDR;
@@ -450,7 +451,9 @@
 		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;
-
+#ifdef FEATURE_IPA_V3
+		rt_rule_entry->rule.hashable = IPA_RULE_NON_HASHABLE;
+#endif
 		if (false == m_routing.AddRoutingRule(rt_rule))
 		{
 			IPACMERR("Routing rule addition failed!\n");
@@ -1363,7 +1366,6 @@
 			{
 				rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0;
 				rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
-
 				if (false == m_routing.AddRoutingRule(rt_rule))
 				{
 		    		IPACMERR("Routing rule addition failed!\n");
@@ -1386,7 +1388,6 @@
 				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");
@@ -1435,7 +1436,6 @@
 		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");
@@ -1918,6 +1918,10 @@
 
 		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
 		flt_rule_entry.at_rear = true;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.rule.hashable = IPA_RULE_NON_HASHABLE;
+#endif
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
@@ -1997,7 +2001,9 @@
 					flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
 				}
             }
-
+#ifdef FEATURE_IPA_V3
+			flt_rule_entry.at_rear = true;
+#endif
 			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
 			memcpy(&flt_rule_entry.rule.attrib,
 						 &rx_prop->rx[0].attrib,
@@ -2073,7 +2079,6 @@
 			        {
 			            flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
                     }
-
 					memcpy(&flt_rule_entry.rule.attrib,
 								 &firewall_config.extd_firewall_entries[i].attrib,
 								 sizeof(struct ipa_rule_attrib));
@@ -2202,7 +2207,6 @@
 					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,
 						 &rx_prop->rx[0].attrib,
@@ -2308,7 +2312,6 @@
 			  flt_rule_entry.at_rear = true;
 			  flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
                         }
-
 			memcpy(&flt_rule_entry.rule.attrib,
 						 &rx_prop->rx[0].attrib,
 						 sizeof(struct ipa_rule_attrib));
@@ -2378,7 +2381,6 @@
 			            {
 					flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
                                     }
-
 		    			flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
 					memcpy(&flt_rule_entry.rule.attrib,
 								 &firewall_config.extd_firewall_entries[i].attrib,
@@ -2508,7 +2510,6 @@
 			  flt_rule_entry.at_rear = true;
 			  flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
                         }
-
 			memcpy(&flt_rule_entry.rule.attrib,
 						 &rx_prop->rx[0].attrib,
 						 sizeof(struct ipa_rule_attrib));
@@ -2599,8 +2600,10 @@
 			check_dft_firewall_rules_attr_mask(&firewall_config))
 	{
 		memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
-
 		flt_rule_entry.at_rear = true;
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = false;
+#endif
 		flt_rule_entry.flt_rule_hdl = -1;
 		flt_rule_entry.status = -1;
 
@@ -2608,7 +2611,10 @@
 		flt_rule_entry.rule.to_uc = 0;
 		flt_rule_entry.rule.eq_attrib_type = 1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
-
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.at_rear = false;
+		flt_rule_entry.rule.hashable = IPA_RULE_NON_HASHABLE;
+#endif
 		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
 		rt_tbl_idx.ip = IPA_IP_v6;
 		strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
@@ -2674,7 +2680,6 @@
 					{
 						flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
 					}
-
 					memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
 					rt_tbl_idx.ip = iptype;
 					if(flt_rule_entry.rule.action == IPA_PASS_TO_ROUTING)
@@ -2809,7 +2814,6 @@
 				flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
 			}
 		}
-
 		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
 		rt_tbl_idx.ip = iptype;
 
@@ -2882,7 +2886,6 @@
 					flt_rule_entry.rule.to_uc = 0;
 					flt_rule_entry.rule.eq_attrib_type = 1;
 					flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
-
 					memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
 					rt_tbl_idx.ip = iptype;
 
@@ -2993,7 +2996,6 @@
 		flt_rule_entry.rule.to_uc = 0;
 		flt_rule_entry.rule.eq_attrib_type = 1;
 		flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
-
 		memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
 		rt_tbl_idx.ip = iptype;
 		/* firewall disable, all traffic are allowed */
@@ -3383,9 +3385,15 @@
 
 		for (cnt = 0; cnt < ext_prop->num_ext_props; cnt++)
 		{
-			IPACMDBG_H("Ex(%d): ip-type: %d, mux_id: %d, flt_action: %d\n, rt_tbl_idx: %d, flt_hdr: %d  is_xlat_rule: %d\n",
-					cnt, ext_prop->ext[cnt].ip, ext_prop->ext[cnt].mux_id, ext_prop->ext[cnt].action,
-					ext_prop->ext[cnt].rt_tbl_idx, ext_prop->ext[cnt].filter_hdl, ext_prop->ext[cnt].is_xlat_rule);
+#ifndef FEATURE_IPA_V3
+			IPACMDBG_H("Ex(%d): ip-type: %d, mux_id: %d, flt_action: %d\n, rt_tbl_idx: %d, is_xlat_rule: %d flt_hdl: %d\n",
+				cnt, ext_prop->ext[cnt].ip, ext_prop->ext[cnt].mux_id, ext_prop->ext[cnt].action,
+				ext_prop->ext[cnt].rt_tbl_idx, ext_prop->ext[cnt].is_xlat_rule, ext_prop->ext[cnt].filter_hdl);
+#else /* defined (FEATURE_IPA_V3) */
+			IPACMDBG_H("Ex(%d): ip-type: %d, mux_id: %d, flt_action: %d\n, rt_tbl_idx: %d, is_xlat_rule: %d rule_id: %d\n",
+				cnt, ext_prop->ext[cnt].ip, ext_prop->ext[cnt].mux_id, ext_prop->ext[cnt].action,
+				ext_prop->ext[cnt].rt_tbl_idx, ext_prop->ext[cnt].is_xlat_rule, ext_prop->ext[cnt].rule_id);
+#endif
 		}
 
 		if(IPACM_Wan::is_ext_prop_set == false)
@@ -5422,7 +5430,6 @@
 				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))
 				{
 					IPACMERR("Routing rule addition failed!\n");
@@ -5470,7 +5477,6 @@
 					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");
@@ -5502,7 +5508,6 @@
 					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");
@@ -5587,6 +5592,7 @@
 		{
 			rt_rule_entry->rule.attrib.u.v4.dst_addr      = 0;
 			rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
+			rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v4;
 			rt_rule_entry->rt_rule_hdl = wan_route_rule_v4_hdl[tx_index];
 		}
 		else
@@ -5600,8 +5606,10 @@
 			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->rule.hdr_hdl = hdr_hdl_sta_v6;
 			rt_rule_entry->rt_rule_hdl = wan_route_rule_v6_hdl[tx_index];
 		}
+		IPACMDBG_H("Header handle: 0x%x\n", rt_rule_entry->rule.hdr_hdl);
 
 		if (isSCCMode)
 		{
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 97a6192..bb70724 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -114,14 +114,14 @@
 	exp_index_v4 = IPV4_DEFAULT_FILTERTING_RULES + IPACM_Iface::ipacmcfg->ipa_num_private_subnet
 			+ IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT + NUM_IPV4_ICMP_FLT_RULE;
 	exp_index_v6 = IPV6_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT
-			+ NUM_IPV6_PREFIX_FLT_RULE + NUM_IPV6_ICMP_FLT_RULE;
+			+ 2 * 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;
+	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;
+	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);
@@ -372,10 +372,8 @@
 					{
 						if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
 						{
-							if(wlan_ap_index == 0) //install ipv6 prefix rule only once
-							{
-								install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
-							}
+							install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
+
 							if(IPACM_Wan::backhaul_is_sta_mode == false)
 							{
 								ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
@@ -446,10 +444,8 @@
 		{
 			if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
 			{
-				if(wlan_ap_index == 0) //install ipv6 prefix rule only once
-				{
-					install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix);
-				}
+				install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix);
+
 				if(data_wan_tether->is_sta == false)
 				{
 					ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
@@ -509,11 +505,6 @@
 			/* reset wifi-client ipv6 rt-rules */
 			handle_wlan_client_reset_rt(IPA_IP_v6);
 
-			if(data_wan_tether->is_sta == false && wlan_ap_index > 0)
-			{
-				IPACMDBG_H("This is not the first AP instance and not STA mode, ignore WAN_DOWN event.\n");
-				return;
-			}
 			if (rx_prop != NULL)
 			{
 				if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
@@ -560,10 +551,8 @@
 		IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
 		if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
 		{
-			if(wlan_ap_index == 0) //install ipv6 prefix rule only once
-			{
-				install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
-			}
+			install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
+
 			if(data_wan->is_sta == false)
 			{
 				ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
@@ -612,11 +601,6 @@
 		/* reset wifi-client ipv6 rt-rules */
 		handle_wlan_client_reset_rt(IPA_IP_v6);
 		IPACMDBG_H("Backhaul is sta mode ? %d\n", data_wan->is_sta);
-		if(data_wan->is_sta == false && wlan_ap_index > 0)
-		{
-			IPACMDBG_H("This is not the first AP instance and not STA mode, ignore WAN_DOWN event.\n");
-			return;
-		}
 		if (rx_prop != NULL)
 		{
 			if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
@@ -1561,17 +1545,25 @@
 	memset(&flt_index, 0, sizeof(flt_index));
 	flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
 	flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
 	flt_index.filter_index_list_len = prop->num_ext_props;
+#else  /* defined (FEATURE_IPA_V3) */
+	flt_index.rule_id_valid = 1;
+	flt_index.rule_id_len = prop->num_ext_props;
+#endif
 	flt_index.embedded_pipe_index_valid = 1;
 	flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
 	flt_index.retain_header_valid = 1;
 	flt_index.retain_header = 0;
 	flt_index.embedded_call_mux_id_valid = 1;
 	flt_index.embedded_call_mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
-
-	IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n", flt_index.source_pipe_index,
-				flt_index.filter_index_list_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
-
+#ifndef FEATURE_IPA_V3
+	IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n",
+		flt_index.source_pipe_index, flt_index.filter_index_list_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
+#else /* defined (FEATURE_IPA_V3) */
+	IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n",
+		flt_index.source_pipe_index, flt_index.rule_id_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
+#endif
 	len = sizeof(struct ipa_ioc_add_flt_rule) + prop->num_ext_props * sizeof(struct ipa_flt_rule_add);
 	pFilteringTable = (struct ipa_ioc_add_flt_rule*)malloc(len);
 	if (pFilteringTable == NULL)
@@ -1590,6 +1582,10 @@
 
 	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
 	flt_rule_entry.at_rear = 1;
+#ifdef FEATURE_IPA_V3
+	if (flt_rule_entry.rule.eq_attrib.ipv4_frag_eq_present)
+		flt_rule_entry.at_rear = 0;
+#endif
 	flt_rule_entry.flt_rule_hdl = -1;
 	flt_rule_entry.status = -1;
 
@@ -1641,14 +1637,20 @@
 			IPACMDBG_H("xlat meta-data is modified for rule: %d has index: %d with xlat_mux_id: %d\n",
 					cnt, index, xlat_mux_id);
                 }
-
+#ifdef FEATURE_IPA_V3
+		flt_rule_entry.rule.hashable = prop->prop[cnt].is_rule_hashable;
+		flt_rule_entry.rule.rule_id = prop->prop[cnt].rule_id;
+#endif
 		memcpy(&pFilteringTable->rules[cnt], &flt_rule_entry, sizeof(flt_rule_entry));
 
 		IPACMDBG_H("Modem UL filtering rule %d has index %d\n", cnt, index);
+#ifndef FEATURE_IPA_V3
 		flt_index.filter_index_list[cnt].filter_index = index;
-		index++;
-
 		flt_index.filter_index_list[cnt].filter_handle = prop->prop[cnt].filter_hdl;
+#else /* defined (FEATURE_IPA_V3) */
+		flt_index.rule_id[cnt] = prop->prop[cnt].rule_id;
+#endif
+		index++;
 	}
 
 	if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
@@ -2202,7 +2204,6 @@
 				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");
@@ -2242,7 +2243,6 @@
 					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");
@@ -2283,7 +2283,6 @@
 					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");
@@ -2497,7 +2496,7 @@
 	if (IPACM_Wan::isWanUP_V6(ipa_if_num) && rx_prop != NULL)
 	{
 		IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
-		IPACM_Lan::handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode);
+		handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode);
 	}
 	IPACMDBG_H("finished deleting wan filtering rules\n ");
 
@@ -3265,14 +3264,14 @@
 		}
 #ifdef FEATURE_ETH_BRIDGE_LE
 		num_v4_dummy_rule = IPV4_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
-		num_v6_dummy_rule = IPV6_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT;
+		num_v6_dummy_rule = IPV6_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT + 2 * NUM_IPV6_PREFIX_FLT_RULE;
 #else
 #ifndef CT_OPT
 		num_v4_dummy_rule = 2*(IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
-		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR);
+		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + NUM_IPV6_PREFIX_FLT_RULE);
 #else
 		num_v4_dummy_rule = 2*(IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
-		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR);
+		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + NUM_IPV6_PREFIX_FLT_RULE);
 #endif
 #ifdef FEATURE_IPA_ANDROID
 		num_v4_dummy_rule = num_v4_dummy_rule - 2* IPACM_Iface::ipacmcfg->ipa_num_private_subnet + 2 * IPA_MAX_PRIVATE_SUBNET_ENTRIES;
@@ -3338,7 +3337,6 @@
 	flt_rule.flt_rule_hdl = -1;
 	flt_rule.status = -1;
 	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
-
 	memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
 			sizeof(flt_rule.rule.attrib));
 
@@ -3457,10 +3455,10 @@
 		}
 #ifndef CT_OPT
 		num_v4_dummy_rule = 2*(IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
-		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR);
+		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + NUM_IPV6_PREFIX_FLT_RULE);
 #else
 		num_v4_dummy_rule = 2*(IPV4_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
-		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR);
+		num_v6_dummy_rule = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + NUM_IPV6_PREFIX_FLT_RULE);
 #endif
 #ifdef FEATURE_IPA_ANDROID
 		num_v4_dummy_rule = num_v4_dummy_rule - 2* IPACM_Iface::ipacmcfg->ipa_num_private_subnet + 2 * IPA_MAX_PRIVATE_SUBNET_ENTRIES;
@@ -3468,7 +3466,7 @@
 
 #ifdef FEATURE_ETH_BRIDGE_LE
 		num_v4_dummy_rule = IPV4_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
-		num_v6_dummy_rule = IPV6_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT;
+		num_v6_dummy_rule = IPV6_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT + 2 * NUM_IPV6_PREFIX_FLT_RULE;
 #endif
 
 		if(m_filtering.DeleteFilteringHdls(IPACM_Wlan::dummy_flt_rule_hdl_v4, IPA_IP_v4, num_v4_dummy_rule) == false)
@@ -4519,7 +4517,6 @@
 			position++;
 		}
 	}
-
 	if(false == m_routing.AddRoutingRule(rt_rule_table))
 	{
 		IPACMERR("Routing rule addition failed!\n");
@@ -5519,3 +5516,95 @@
 	free(pFilteringTable);
 	return res;
 }
+
+int IPACM_Wlan::install_ipv6_prefix_flt_rule(uint32_t* prefix)
+{
+	int i, len, res = IPACM_SUCCESS, offset;
+	struct ipa_flt_rule_mdfy flt_rule;
+	struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
+
+	if (rx_prop == NULL)
+	{
+		IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+		return IPACM_SUCCESS;
+	}
+
+	if(IPACM_Wlan::dummy_flt_rule_hdl_v6 == NULL)
+	{
+		IPACMERR("Dummy ipv6 flt rule has not been installed.\n");
+		return IPACM_FAILURE;
+	}
+	if(wlan_ap_index >= 2)
+	{
+		IPACMERR("Cannot support more than 2 WLAN AP, abort.\n");
+		return IPACM_FAILURE;
+	}
+
+#ifdef FEATURE_ETH_BRIDGE_LE
+	offset = IPV6_DEFAULT_FILTERTING_RULES + IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_LAN_CLIENT + wlan_ap_index;
+#else
+#ifndef CT_OPT
+	offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR) + wlan_ap_index;
+#else
+	offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR) + wlan_ap_index;
+#endif
+#endif
+
+	len = sizeof(struct ipa_ioc_mdfy_flt_rule) + sizeof(struct ipa_flt_rule_mdfy);
+	pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
+	if (!pFilteringTable)
+	{
+		IPACMERR("Failed to allocate ipa_ioc_mdfy_flt_rule memory...\n");
+		return IPACM_FAILURE;
+	}
+	memset(pFilteringTable, 0, len);
+
+	pFilteringTable->commit = 1;
+	pFilteringTable->ip = IPA_IP_v6;
+	pFilteringTable->num_rules = 1;
+
+	memset(&flt_rule, 0, sizeof(flt_rule));
+	flt_rule.status = -1;
+	flt_rule.rule_hdl = IPACM_Wlan::dummy_flt_rule_hdl_v6[offset];
+
+	flt_rule.rule.retain_hdr = 1;
+	flt_rule.rule.to_uc = 0;
+	flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
+	flt_rule.rule.eq_attrib_type = 0;
+
+	memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule.rule.attrib));
+	flt_rule.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+	flt_rule.rule.attrib.u.v6.dst_addr[0] = prefix[0];
+	flt_rule.rule.attrib.u.v6.dst_addr[1] = prefix[1];
+	flt_rule.rule.attrib.u.v6.dst_addr[2] = 0x0;
+	flt_rule.rule.attrib.u.v6.dst_addr[3] = 0x0;
+	flt_rule.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+	flt_rule.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+	flt_rule.rule.attrib.u.v6.dst_addr_mask[2] = 0x0;
+	flt_rule.rule.attrib.u.v6.dst_addr_mask[3] = 0x0;
+	memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(flt_rule));
+
+	if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
+	{
+		IPACMERR("Failed to modify tcp control filtering rules.\n");
+		free(pFilteringTable);
+		return IPACM_FAILURE;
+	}
+	else
+	{
+		ipv6_prefix_flt_rule_hdl[0] = IPACM_Wlan::dummy_flt_rule_hdl_v6[offset];
+		IPACMDBG_H("IPv6 prefix filter rule HDL:0x%x\n", ipv6_prefix_flt_rule_hdl[0]);
+	}
+
+	free(pFilteringTable);
+	return IPACM_SUCCESS;
+}
+
+void IPACM_Wlan::delete_ipv6_prefix_flt_rule()
+{
+	if(reset_to_dummy_flt_rule(IPA_IP_v6, ipv6_prefix_flt_rule_hdl[0]) == IPACM_FAILURE)
+	{
+		IPACMERR("Failed to delete ipv6 prefix flt rule.\n");
+	}
+	return;
+}
diff --git a/ipacm/src/Makefile.am b/ipacm/src/Makefile.am
index 4ee0a08..2fdb3f8 100644
--- a/ipacm/src/Makefile.am
+++ b/ipacm/src/Makefile.am
@@ -3,6 +3,7 @@
 	      ${LIBXML_CFLAGS}
 AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
 AM_CPPFLAGS	+= -DDEBUG -g -DFEATURE_ETH_BRIDGE_LE
+AM_CPPFLAGS += -DFEATURE_IPA_V3
 
 ipacm_SOURCES =	IPACM_Main.cpp \
 		IPACM_Conntrack_NATApp.cpp\