ipacm: add frag rule for UDP DL MHI offload

Add a parameter in add_filtering_rule to specify mhi legacy path.
Add filtering rule to use Legacy MHI path for UDP DL fragments.

Change-Id: I955a25991c9a8bfa7d40d701e5fc2a7e91a8f28e
diff --git a/ipacm/inc/IPACM_Filtering.h b/ipacm/inc/IPACM_Filtering.h
index d216a00..5ceab75 100644
--- a/ipacm/inc/IPACM_Filtering.h
+++ b/ipacm/inc/IPACM_Filtering.h
@@ -65,7 +65,7 @@
 													 uint8_t num_rules);
 
 	bool AddWanDLFilteringRule(struct ipa_ioc_add_flt_rule const *rule_table_v4, struct ipa_ioc_add_flt_rule const * rule_table_v6, uint8_t mux_id);
-	bool AddOffloadFilteringRule(struct ipa_ioc_add_flt_rule *flt_rule_tbl, uint8_t mux_id);
+	bool AddOffloadFilteringRule(struct ipa_ioc_add_flt_rule *flt_rule_tbl, uint8_t mux_id, uint8_t default_path);
 	bool DelOffloadFilteringRule(struct ipa_ioc_del_flt_rule const *flt_rule_tbl);
 	bool SendFilteringRuleIndex(struct ipa_fltr_installed_notif_req_msg_v01* table);
 	bool ModifyFilteringRule(struct ipa_ioc_mdfy_flt_rule* ruleTable);
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
index d66224a..c71d4ca 100644
--- a/ipacm/inc/IPACM_Wan.h
+++ b/ipacm/inc/IPACM_Wan.h
@@ -364,6 +364,9 @@
 	uint32_t hdr_hdl_dummy_v6;
 	uint32_t hdr_proc_hdl_dummy_v6;
 
+	/* handle for UDP mhi frag rule */
+	uint32_t mhi_dl_v4_frag_hdl;
+
 	inline ipa_wan_client* get_client_memptr(ipa_wan_client *param, int cnt)
 	{
 	    char *ret = ((char *)param) + (wan_client_len * cnt);
@@ -622,6 +625,10 @@
 	int add_dummy_rx_hdr();
 
 	int handle_coalesce_evt();
+
+	int add_offload_frag_rule();
+
+	int delete_offload_frag_rule();
 };
 
 #endif /* IPACM_WAN_H */
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
index 9828036..c1f47e1 100644
--- a/ipacm/src/IPACM_Conntrack_NATApp.cpp
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -579,7 +579,7 @@
 		sizeof(flt_rule_entry.rule.eq_attrib));
 	memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
 
-	if(false == IPACM_Iface::m_filtering.AddOffloadFilteringRule(pFilteringTable, pub_mux_id))
+	if(false == IPACM_Iface::m_filtering.AddOffloadFilteringRule(pFilteringTable, pub_mux_id, 0))
 	{
 		IPACMERR("Failed to install WAN DL filtering table.\n");
 		res = IPACM_FAILURE;
diff --git a/ipacm/src/IPACM_Filtering.cpp b/ipacm/src/IPACM_Filtering.cpp
index a65b769..a5c2bf5 100644
--- a/ipacm/src/IPACM_Filtering.cpp
+++ b/ipacm/src/IPACM_Filtering.cpp
@@ -463,7 +463,7 @@
 	return true;
 }
 
-bool IPACM_Filtering::AddOffloadFilteringRule(struct ipa_ioc_add_flt_rule *flt_rule_tbl, uint8_t mux_id)
+bool IPACM_Filtering::AddOffloadFilteringRule(struct ipa_ioc_add_flt_rule *flt_rule_tbl, uint8_t mux_id, uint8_t default_path)
 {
 #ifdef WAN_IOCTL_ADD_OFFLOAD_CONNECTION
 	int ret = 0, cnt, pos = 0;
@@ -525,7 +525,14 @@
 		}
 		qmi_add_msg.filter_spec_ex2_list_len = flt_rule_tbl->num_rules;
 
-		IPACMDBG_H("passing %d offload req to modem.\n", flt_rule_tbl->num_rules);
+		/* check if we want to take default MHI path */
+		if (default_path)
+		{
+			qmi_add_msg.default_mhi_path_valid = true;
+			qmi_add_msg.default_mhi_path = true;
+		}
+
+		IPACMDBG_H("passing %d offload req to modem. default %d\n", flt_rule_tbl->num_rules, qmi_add_msg.default_mhi_path);
 
 		if(flt_rule_tbl != NULL)
 		{
@@ -581,7 +588,7 @@
 #else
 	if(flt_rule_tbl != NULL)
 	{
-		IPACMERR("Not support (%d) AddOffloadFilteringRule with mux-id (%d)\n", flt_rule_tbl->num_rules, mux_id);
+		IPACMERR("Not support (%d) AddOffloadFilteringRule with mux-id (%d) and default path = %d\n", flt_rule_tbl->num_rules, mux_id, default_path);
 	}
 	return false;
 #endif
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 356cac8..8067053 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -6124,7 +6124,7 @@
 		sizeof(flt_rule_entry.rule.eq_attrib));
 	memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
 
-	if(false == m_filtering.AddOffloadFilteringRule(pFilteringTable, mux_id))
+	if(false == m_filtering.AddOffloadFilteringRule(pFilteringTable, mux_id, 0))
 	{
 		IPACMERR("Failed to install WAN DL filtering table.\n");
 		res = IPACM_FAILURE;
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index 6f46f70..dca5d5c 100644
--- a/ipacm/src/IPACM_Wan.cpp
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -1820,11 +1820,17 @@
 			IPACMDBG_H("Setting up QMAP ID %d.\n", ext_prop->ext[0].mux_id);
 			IPACM_Iface::ipacmcfg->SetQmapId(ext_prop->ext[0].mux_id);
 			/* sending mux-id info to PCIE-modem for UL */
-			if(false == m_filtering.AddOffloadFilteringRule(NULL, ext_prop->ext[0].mux_id))
+			if(false == m_filtering.AddOffloadFilteringRule(NULL, ext_prop->ext[0].mux_id, 0))
 			{
 				IPACMERR("Failed to send mux id info to modem.\n");
 				return IPACM_FAILURE;
 			}
+			/* send UL UDP frag filtering rule */
+			if(iptype==IPA_IP_v4 && add_offload_frag_rule())
+			{
+				IPACMERR("Failed to send DL frag rule to modem.\n");
+				return IPACM_FAILURE;
+			}
 		}
 		else
 		{
@@ -4670,6 +4676,13 @@
 			{
 				memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
 			}
+
+			/* Delete MHI frag rule */
+			if(delete_offload_frag_rule())
+			{
+				IPACMERR("Failed to delete DL frag rule \n");
+				return IPACM_FAILURE;
+			}
 		}
 		else
 		{
@@ -7201,3 +7214,144 @@
 	}
 	return res;
 }
+
+int IPACM_Wan::add_offload_frag_rule()
+{
+	int fd;
+	int len, res = IPACM_SUCCESS;
+	uint8_t mux_id;
+	ipa_ioc_add_flt_rule *pFilteringTable = NULL;
+
+	mux_id = ext_prop->ext[0].mux_id;
+	/* contruct filter rules to pcie modem */
+	struct ipa_flt_rule_add flt_rule_entry;
+	ipa_ioc_generate_flt_eq flt_eq;
+
+	/* construct rule */
+	IPACMDBG_H("adding MHi frag rule\n");
+	len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+	pFilteringTable = (struct ipa_ioc_add_flt_rule*)malloc(len);
+	if (pFilteringTable == NULL)
+	{
+		IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+		return IPACM_FAILURE;
+	}
+	memset(pFilteringTable, 0, len);
+
+	pFilteringTable->commit = 1;
+	pFilteringTable->global = false;
+	pFilteringTable->ip = IPA_IP_v4;
+	pFilteringTable->num_rules = (uint8_t)1;
+
+	/* Configuring Fragment Filtering Rule */
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+	flt_rule_entry.at_rear = false;
+	flt_rule_entry.flt_rule_hdl = -1;
+	flt_rule_entry.status = -1;
+
+	flt_rule_entry.rule.retain_hdr = 1;
+	flt_rule_entry.rule.to_uc = 0;
+	flt_rule_entry.rule.eq_attrib_type = 1;
+	flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+	flt_rule_entry.rule.hashable = true;
+#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,
+				sizeof(flt_rule_entry.rule.attrib));
+
+	flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+
+	/* generate eq */
+	memset(&flt_eq, 0, sizeof(flt_eq));
+	memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+	flt_eq.ip = IPA_IP_v4;
+
+	fd = open(IPA_DEVICE_NAME, O_RDWR);
+	if (fd < 0)
+	{
+		IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+		free(pFilteringTable);
+		return IPACM_FAILURE;
+	}
+
+	if(0 != ioctl(fd, IPA_IOC_GENERATE_FLT_EQ, &flt_eq)) //define and cpy attribute to this struct
+	{
+		IPACMERR("Failed to get eq_attrib\n");
+		goto fail;
+	}
+	memcpy(&flt_rule_entry.rule.eq_attrib,
+		&flt_eq.eq_attrib,
+		sizeof(flt_rule_entry.rule.eq_attrib));
+	memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+	/* add rule */
+	if(false == m_filtering.AddOffloadFilteringRule(pFilteringTable, mux_id, 1))
+	{
+		IPACMERR("Failed to install WAN DL filtering table.\n");
+		res = IPACM_FAILURE;
+		goto fail;
+	}
+
+	/* save handle */
+	mhi_dl_v4_frag_hdl = pFilteringTable->rules[0].flt_rule_hdl;
+
+fail:
+	close(fd);
+	if(pFilteringTable != NULL)
+	{
+		free(pFilteringTable);
+	}
+	return res;
+}
+
+int IPACM_Wan::delete_offload_frag_rule()
+{
+	int len, res = true;
+	ipa_ioc_del_flt_rule *pFilteringTable = NULL;
+
+	struct ipa_flt_rule_del flt_rule_entry;
+
+	IPACMDBG_H("deleting MHI frag rule \n");
+	len = sizeof(struct ipa_ioc_del_flt_rule) + sizeof(struct ipa_flt_rule_del);
+	pFilteringTable = (struct ipa_ioc_del_flt_rule*)malloc(len);
+	if (pFilteringTable == NULL)
+	{
+		IPACMERR("Error Locate ipa_ioc_del_flt_rule memory...\n");
+		return false;
+	}
+	memset(pFilteringTable, 0, len);
+
+	pFilteringTable->commit = 1;
+	pFilteringTable->ip = IPA_IP_v4;
+	pFilteringTable->num_hdls = (uint8_t)1;
+
+	if (mhi_dl_v4_frag_hdl == 0)
+	{
+		IPACMERR("invalid dl_v4_frag_hdl.\n");
+		res = false;
+		goto fail;
+	}
+
+	/* Configuring Software-Routing Filtering Rule */
+	memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_del));
+	flt_rule_entry.hdl = mhi_dl_v4_frag_hdl;
+
+	memcpy(&(pFilteringTable->hdl[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_del));
+
+	if(false == m_filtering.DelOffloadFilteringRule(pFilteringTable))
+	{
+		IPACMERR("Failed to delete DL offload frag rule.\n");
+		res = false;
+		goto fail;
+	}
+	mhi_dl_v4_frag_hdl = 0;
+
+fail:
+	if(pFilteringTable != NULL)
+	{
+		free(pFilteringTable);
+	}
+	return res;
+}
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index af74be4..173c41f 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -2518,7 +2518,7 @@
 		sizeof(flt_rule_entry.rule.eq_attrib));
 	memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
 
-	if(false == m_filtering.AddOffloadFilteringRule(pFilteringTable, mux_id))
+	if(false == m_filtering.AddOffloadFilteringRule(pFilteringTable, mux_id, 0))
 	{
 		IPACMERR("Failed to install WAN DL filtering table.\n");
 		res = IPACM_FAILURE;