IPACM: fix IPv6 embedded call not working issue
Fix IPv6 embedded data call not working issue. Specifically,
we added WAN interface IP based filtering rule on WAN pipe
when WAN is USB cradle or WLAN STA, and added IPv6 prefix
based filtering rule on LAN pipe to make embedded IPv6 data
path work.
Change-Id: I97eab078cdb1ed25298922515d1bb99e50bbbfff
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
index 3957d4c..46a9bc6 100644
--- a/ipacm/inc/IPACM_Defs.h
+++ b/ipacm/inc/IPACM_Defs.h
@@ -257,6 +257,7 @@
char ifname[IPA_IFACE_NAME_LEN];
uint32_t ipv4_addr;
uint32_t addr_mask;
+ uint32_t ipv6_prefix[2];
bool is_sta;
}ipacm_event_iface_up;
diff --git a/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
index 1f561fa..854c272 100644
--- a/ipacm/inc/IPACM_Lan.h
+++ b/ipacm/inc/IPACM_Lan.h
@@ -53,6 +53,7 @@
#define IPA_WAN_DEFAULT_FILTER_RULE_HANDLES 1
#define IPA_PRIV_SUBNET_FILTER_RULE_HANDLES 3
#define MAX_WAN_UL_FILTER_RULES 20
+#define NUM_IPV6_PREFIX_FLT_RULE 1
/* store each lan-iface unicast routing rule and its handler*/
struct ipa_lan_rt_rule
@@ -164,6 +165,8 @@
/*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);
+
void post_del_self_evt();
lan2lan_flt_rule_hdl lan2lan_flt_rule_hdl_v4[MAX_OFFLOAD_PAIR];
@@ -186,6 +189,8 @@
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];
+ uint32_t ipv6_prefix_flt_rule_hdl[NUM_IPV6_PREFIX_FLT_RULE];
+
int num_wan_ul_fl_rule_v4;
int num_wan_ul_fl_rule_v6;
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
index b60bb26..c650128 100644
--- a/ipacm/inc/IPACM_Wan.h
+++ b/ipacm/inc/IPACM_Wan.h
@@ -88,6 +88,7 @@
ipacm_wan_iface_type m_is_sta_mode;
static bool backhaul_is_sta_mode;
static bool is_ext_prop_set;
+ static uint32_t backhaul_ipv6_prefix[2];
private:
uint32_t *wan_route_rule_v4_hdl;
@@ -98,6 +99,8 @@
uint32_t firewall_hdl_v4[IPACM_MAX_FIREWALL_ENTRIES];
uint32_t firewall_hdl_v6[IPACM_MAX_FIREWALL_ENTRIES];
uint32_t dft_wan_fl_hdl[IPA_NUM_DEFAULT_WAN_FILTER_RULES];
+ uint32_t ipv6_dest_flt_rule_hdl[MAX_DEFAULT_v6_ROUTE_RULES];
+ int num_ipv6_dest_flt_rule;
int num_firewall_v4,num_firewall_v6;
uint32_t wan_v4_addr;
bool active_v4;
@@ -117,6 +120,8 @@
bool is_default_gateway;
+ uint32_t ipv6_prefix[2];
+
/* IPACM firewall Configuration file*/
IPACM_firewall_conf_t firewall_config;
@@ -169,6 +174,8 @@
void change_to_network_order(ipa_ip_type iptype, ipa_rule_attrib* attrib);
+ bool is_global_ipv6_addr(uint32_t* ipv6_addr);
+
int m_fd_ipa;
};
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
index 1f967ea..433b029 100644
--- a/ipacm/src/IPACM_Lan.cpp
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -99,6 +99,7 @@
is_mode_switch = false;
if_ipv4_subnet =0;
memset(private_fl_rule_hdl, 0, IPA_MAX_PRIVATE_SUBNET_ENTRIES * sizeof(uint32_t));
+ memset(ipv6_prefix_flt_rule_hdl, 0, NUM_IPV6_PREFIX_FLT_RULE * sizeof(uint32_t));
return;
}
@@ -264,6 +265,7 @@
{
if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
{
+ 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);
@@ -345,6 +347,7 @@
IPACMDBG("Backhaul is sta mode?%d\n", data_wan->is_sta);
if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
{
+ install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
if(data_wan->is_sta == false)
{
ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
@@ -2040,11 +2043,17 @@
}
#ifdef CT_OPT
- flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR;
+ flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR + NUM_IPV6_PREFIX_FLT_RULE;
#else
- flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR;
+ flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR + NUM_IPV6_PREFIX_FLT_RULE;
#endif
+ if(m_filtering.DeleteFilteringHdls(ipv6_prefix_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE) == false)
+ {
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
if(is_sta_mode == false)
{
if (num_wan_ul_fl_rule_v6 > MAX_WAN_UL_FILTER_RULES)
@@ -3491,3 +3500,74 @@
}
return res;
}
+
+int IPACM_Lan::install_ipv6_prefix_flt_rule(uint32_t* prefix)
+{
+ if(prefix == NULL)
+ {
+ IPACMERR("IPv6 prefix is empty.\n");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Receive IPv6 prefix: 0x%08x%08x.\n", prefix[0], prefix[1]);
+
+ 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_v6;
+ 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 = true;
+ 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 = flt_rule_entry.rule.attrib.attrib_mask & ~((uint32_t)IPA_FLT_META_DATA);
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = prefix[0];
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = prefix[1];
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x0;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x0;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x0;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x0;
+ 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
+ {
+ ipv6_prefix_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
+ IPACMDBG("IPv6 prefix filter rule HDL:0x%x\n", ipv6_prefix_flt_rule_hdl[0]);
+ flt_rule_count_v6++;
+ free(flt_rule);
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
index 2c02e31..9c48a9b 100644
--- a/ipacm/src/IPACM_Wan.cpp
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -64,6 +64,8 @@
int IPACM_Wan::num_ipv4_modem_pdn = 0;
int IPACM_Wan::num_ipv6_modem_pdn = 0;
+uint32_t IPACM_Wan::backhaul_ipv6_prefix[2];
+
IPACM_Wan::IPACM_Wan(int iface_index, ipacm_wan_iface_type is_sta_mode) : IPACM_Iface(iface_index)
{
num_firewall_v4 = 0;
@@ -86,6 +88,9 @@
header_partial_default_wan_v6 = false;
hdr_hdl_sta_v4 = 0;
hdr_hdl_sta_v6 = 0;
+ num_ipv6_dest_flt_rule = 0;
+ memset(ipv6_dest_flt_rule_hdl, 0, MAX_DEFAULT_v6_ROUTE_RULES*sizeof(uint32_t));
+ memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
if(m_is_sta_mode == Q6_WAN)
{
@@ -118,8 +123,11 @@
{
struct ipa_ioc_add_rt_rule *rt_rule;
struct ipa_rt_rule_add *rt_rule_entry;
+ struct ipa_ioc_add_flt_rule *flt_rule;
+ struct ipa_flt_rule_add flt_rule_entry;
+
const int NUM_RULES = 1;
- int num_ipv6_addr;
+ int num_ipv6_addr, len;
int res = IPACM_SUCCESS;
if (data->iptype == IPA_IP_v6)
@@ -216,6 +224,69 @@
init_fl_rule(data->iptype);
}
}
+
+ /* add WAN DL interface IP specific flt rule for IPv6 when backhaul is not Q6 */
+ if(m_is_sta_mode != Q6_WAN)
+ {
+ if(rx_prop != NULL && is_global_ipv6_addr(data->ipv6_addr)
+ && num_ipv6_dest_flt_rule < MAX_DEFAULT_v6_ROUTE_RULES)
+ {
+ 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_v6;
+ 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 = true;
+ 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;
+ memcpy(flt_rule_entry.rule.attrib.u.v6.dst_addr, data->ipv6_addr, sizeof(flt_rule_entry.rule.attrib.u.v6.dst_addr));
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ 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);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ ipv6_dest_flt_rule_hdl[num_ipv6_dest_flt_rule] = flt_rule->rules[0].flt_rule_hdl;
+ IPACMDBG("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++;
+ free(flt_rule);
+ }
+ }
+ }
+ /* store ipv6 prefix if the ipv6 address is not link local */
+ if(is_global_ipv6_addr(data->ipv6_addr))
+ {
+ memcpy(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix));
+ }
num_dft_rt_v6++;
}
else
@@ -609,6 +680,8 @@
is_default_gateway = true;
IPACMDBG("Default route is added to iface %s.\n", dev_name);
+ memcpy(backhaul_ipv6_prefix, ipv6_prefix, sizeof(backhaul_ipv6_prefix));
+ IPACMDBG("Setup backhaul ipv6 prefix to be 0x%08x%08x.\n", backhaul_ipv6_prefix[0], backhaul_ipv6_prefix[1]);
if (m_is_sta_mode !=Q6_WAN)
{
@@ -880,10 +953,10 @@
{
wanup_data->is_sta = false;
}
-
+ memcpy(wanup_data->ipv6_prefix, ipv6_prefix, sizeof(wanup_data->ipv6_prefix));
IPACMDBG("Posting IPA_HANDLE_WAN_UP_V6 with below information:\n");
IPACMDBG("if_name:%s, is sta mode: %d\n", wanup_data->ifname, wanup_data->is_sta);
-
+ IPACMDBG("ipv6 prefix: 0x%08x%08x.\n", ipv6_prefix[0], ipv6_prefix[1]);
memset(&evt_data, 0, sizeof(evt_data));
evt_data.event = IPA_HANDLE_WAN_UP_V6;
evt_data.evt_data = (void *)wanup_data;
@@ -3033,10 +3106,11 @@
{
wandown_data->is_sta = false;
}
+ memcpy(wandown_data->ipv6_prefix, ipv6_prefix, sizeof(wandown_data->ipv6_prefix));
evt_data.event = IPA_HANDLE_WAN_DOWN_V6;
evt_data.evt_data = (void *)wandown_data;
/* Insert IPA_HANDLE_WAN_DOWN to command queue */
- IPACMDBG("posting IPA_HANDLE_WAN_DOWN for IPv6 \n");
+ IPACMDBG("posting IPA_HANDLE_WAN_DOWN for IPv6 with prefix 0x%08x%08x\n", ipv6_prefix[0], ipv6_prefix[1]);
IPACM_EvtDispatcher::PostEvt(&evt_data);
IPACMDBG("setup wan_up_v6/active_v6= false \n");
IPACM_Wan::wan_up_v6 = false;
@@ -3124,9 +3198,10 @@
{
wandown_data->is_sta = false;
}
+ memcpy(wandown_data->ipv6_prefix, ipv6_prefix, sizeof(wandown_data->ipv6_prefix));
evt_data.event = IPA_HANDLE_WAN_DOWN_V6;
evt_data.evt_data = (void *)wandown_data;
- IPACMDBG("posting IPA_HANDLE_WAN_DOWN_V6 for IPv6 \n");
+ IPACMDBG("posting IPA_HANDLE_WAN_DOWN_V6 for IPv6 with prefix 0x%08x%08x\n", ipv6_prefix[0], ipv6_prefix[1]);
IPACM_EvtDispatcher::PostEvt(&evt_data);
IPACMDBG("setup wan_up_v6/active_v6= false \n");
@@ -3240,6 +3315,15 @@
goto fail;
}
+ if(num_ipv6_dest_flt_rule > 0)
+ {
+ if(m_filtering.DeleteFilteringHdls(ipv6_dest_flt_rule_hdl, IPA_IP_v6, num_ipv6_dest_flt_rule) == false)
+ {
+ IPACMERR("Failed to delete ipv6 dest flt rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
IPACMDBG("finished delete default v6 filtering rules\n ");
}
@@ -3577,3 +3661,27 @@
return;
}
+bool IPACM_Wan::is_global_ipv6_addr(uint32_t* ipv6_addr)
+{
+ if(ipv6_addr == NULL)
+ {
+ IPACMERR("IPv6 address is empty.\n");
+ return false;
+ }
+ IPACMDBG("Get ipv6 address with first word 0x%08x.\n", ipv6_addr[0]);
+
+ uint32_t ipv6_link_local_prefix, ipv6_link_local_prefix_mask;
+ ipv6_link_local_prefix = 0xFE800000;
+ ipv6_link_local_prefix_mask = 0xFFC00000;
+ if((ipv6_addr[0] & ipv6_link_local_prefix_mask) == (ipv6_link_local_prefix & ipv6_link_local_prefix_mask))
+ {
+ IPACMDBG("This IPv6 address is link local.\n");
+ return false;
+ }
+ else
+ {
+ IPACMDBG("This IPv6 address is not link local.\n");
+ return true;
+ }
+}
+
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 397b67f..cfe3051 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -252,33 +252,37 @@
{
if(data->iptype == IPA_IP_v4 || data->iptype == IPA_IP_MAX)
{
- if(IPACM_Wan::backhaul_is_sta_mode == false)
- {
+ if(IPACM_Wan::backhaul_is_sta_mode == false)
+ {
ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v4);
}
- else
- {
- IPACM_Lan::handle_wan_up(IPA_IP_v4);
+ else
+ {
+ IPACM_Lan::handle_wan_up(IPA_IP_v4);
+ }
}
}
- }
if(IPACM_Wan::isWanUP_V6())
{
if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
{
- if(IPACM_Wan::backhaul_is_sta_mode == false)
- {
+ if(wlan_ap_index == 0) //install ipv6 prefix rule only once
+ {
+ 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);
IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v6);
}
- else
- {
- IPACM_Lan::handle_wan_up(IPA_IP_v6);
+ else
+ {
+ IPACM_Lan::handle_wan_up(IPA_IP_v6);
+ }
}
}
- }
IPACMDBG("posting IPA_HANDLE_WLAN_UP:Finished checking wan_up\n");
}
@@ -324,15 +328,19 @@
IPACMDBG("Backhaul is sta mode?%d\n", data_wan->is_sta);
if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
{
- if(data_wan->is_sta == false)
- {
+ if(wlan_ap_index == 0) //install ipv6 prefix rule only once
+ {
+ install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
+ }
+ if(data_wan->is_sta == false)
+ {
ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v6);
}
- else
- {
- IPACM_Lan::handle_wan_up(IPA_IP_v6);
- }
+ else
+ {
+ IPACM_Lan::handle_wan_up(IPA_IP_v6);
+ }
}
break;
@@ -1012,9 +1020,9 @@
else
{
#ifndef CT_OPT
- offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR);
+ offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR) + NUM_IPV6_PREFIX_FLT_RULE;
#else
- offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR);
+ offset = 2*(IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR) + NUM_IPV6_PREFIX_FLT_RULE;
#endif
}