blob: 2ee9f2cb56ba64af79a58425c3eb3859417d4b21 [file] [log] [blame]
/*
Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of The Linux Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*!
@file
IPACM_Wan.cpp
@brief
This file implements the WAN iface functionality.
@Author
Skylar Chang
*/
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <IPACM_Wan.h>
#include <IPACM_Xml.h>
#include <IPACM_Log.h>
#include "IPACM_EvtDispatcher.h"
#include <IPACM_IfaceManager.h>
#include "linux/rmnet_ipa_fd_ioctl.h"
#include "IPACM_Config.h"
#include "IPACM_Defs.h"
#include <IPACM_ConntrackListener.h>
#include "linux/ipa_qmi_service_v01.h"
#ifdef FEATURE_IPACM_HAL
#include "IPACM_OffloadManager.h"
#include <IPACM_Netlink.h>
#endif
bool IPACM_Wan::wan_up = false;
bool IPACM_Wan::wan_up_v6 = false;
uint8_t IPACM_Wan::xlat_mux_id = 0;
uint32_t IPACM_Wan::curr_wan_ip = 0;
int IPACM_Wan::num_v4_flt_rule = 0;
int IPACM_Wan::num_v6_flt_rule = 0;
int IPACM_Wan::ipa_pm_q6_check = 0;
struct ipa_flt_rule_add IPACM_Wan::flt_rule_v4[IPA_MAX_FLT_RULE];
struct ipa_flt_rule_add IPACM_Wan::flt_rule_v6[IPA_MAX_FLT_RULE];
char IPACM_Wan::wan_up_dev_name[IF_NAME_LEN];
ipacm_wan_iface_type IPACM_Wan::backhaul_mode = Q6_WAN;
bool IPACM_Wan::is_ext_prop_set = false;
int IPACM_Wan::num_ipv4_modem_pdn = 0;
int IPACM_Wan::num_ipv6_modem_pdn = 0;
bool IPACM_Wan::embms_is_on = false;
bool IPACM_Wan::backhaul_is_wan_bridge = false;
bool IPACM_Wan::is_xlat = false;
ipacm_coalesce IPACM_Wan::coalesce_enable_info[IPA_MAX_NUM_SW_PDNS];
uint32_t IPACM_Wan::backhaul_ipv6_prefix[2];
#ifdef FEATURE_IPA_ANDROID
uint32_t IPACM_Wan::ipa_if_num_tether_v4_total = 0;
uint32_t IPACM_Wan::ipa_if_num_tether_v6_total = 0;
int IPACM_Wan::ipa_if_num_tether_v4[IPA_MAX_IFACE_ENTRIES];
int IPACM_Wan::ipa_if_num_tether_v6[IPA_MAX_IFACE_ENTRIES];
#endif
uint16_t IPACM_Wan::mtu_default_wan_v4 = DEFAULT_MTU_SIZE;
uint16_t IPACM_Wan::mtu_default_wan_v6 = DEFAULT_MTU_SIZE;
IPACM_Wan::IPACM_Wan(int iface_index,
ipacm_wan_iface_type is_sta_mode,
uint8_t *mac_addr) : IPACM_Iface(iface_index)
{
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;
mac_addr = NULL;
if(iface_query != NULL)
{
wan_route_rule_v4_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
wan_route_rule_v6_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
wan_route_rule_v6_hdl_a5 = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
IPACMDBG_H("IPACM->IPACM_Wan(%d) constructor: Tx:%d\n", ipa_if_num, iface_query->num_tx_props);
}
wan_v4_addr_set = false;
wan_v4_addr_gw_set = false;
wan_v6_addr_gw_set = false;
active_v4 = false;
active_v6 = false;
header_set_v4 = false;
header_set_v6 = false;
header_partial_default_wan_v4 = false;
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));
memset(wan_v6_addr_gw, 0, sizeof(wan_v6_addr_gw));
ext_prop = NULL;
is_ipv6_frag_firewall_flt_rule_installed = false;
ipv6_frag_firewall_flt_rule_hdl = 0;
mtu_v4 = DEFAULT_MTU_SIZE;
mtu_v4_set = false;
mtu_v6 = DEFAULT_MTU_SIZE;
mtu_v6_set = false;
num_wan_client = 0;
header_name_count = 0;
memset(invalid_mac, 0, sizeof(invalid_mac));
is_xlat_local = false;
hdr_hdl_dummy_v6 = 0;
hdr_proc_hdl_dummy_v6 = 0;
is_default_gateway = false;
m_fd_ipa = 0;
wan_client_len = 0;
m_is_sta_mode = is_sta_mode;
#ifdef IPA_MTU_EVENT_MAX
/* Query WAN MTU to handle IPACM restart scenarios. */
if(is_sta_mode == Q6_WAN)
{
int fd_wwan_ioctl;
ipa_mtu_info *mtu_info = (ipa_mtu_info *)malloc(sizeof(ipa_mtu_info));
if (mtu_info)
{
memset(mtu_info, 0, sizeof(ipa_mtu_info));
memcpy(mtu_info->if_name, dev_name, IPA_IFACE_NAME_LEN);
fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
if(fd_wwan_ioctl < 0)
{
IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
}
else
{
IPACMDBG_H("send WAN_IOC_GET_WAN_MTU for %s\n", mtu_info->if_name);
if(ioctl(fd_wwan_ioctl, WAN_IOC_GET_WAN_MTU, mtu_info))
{
IPACMERR("Failed to send WAN_IOC_GET_WAN_MTU\n ");
}
else
{
/* Updated MTU values.*/
if (mtu_info->mtu_v4)
{
mtu_v4 = mtu_info->mtu_v4;
mtu_v4_set = true;
IPACMDBG_H("Updated v4 mtu=[%d] for (%s)\n",
mtu_v4, mtu_info->if_name);
}
if (mtu_info->mtu_v6)
{
mtu_v6 = mtu_info->mtu_v6;
mtu_v6_set = true;
IPACMDBG_H("Updated v6 mtu=[%d] for (%s)\n",
mtu_v6, mtu_info->if_name);
}
}
close(fd_wwan_ioctl);
}
free(mtu_info);
}
}
#endif
if(iface_query != NULL)
{
IPACMDBG_H("index:%d constructor: Tx properties:%d\n", iface_index, iface_query->num_tx_props);
if(is_sta_mode == Q6_WAN)
{
query_ext_prop();
if ((iface_query->num_ext_props == 1) && ((ext_prop != NULL) && ext_prop->ext[0].ip == IPA_IP_MAX))
{
/* only has one ext properties with IP_MAX type, will be the mhi-modem */
IPACMDBG_H("One extended property for iface %s, replace %d to Q6_MHI_WAN\n", dev_name, is_sta_mode);
m_is_sta_mode = Q6_MHI_WAN;
}
else
{
IPACMDBG_H("The new WAN interface is modem.\n");
m_is_sta_mode = is_sta_mode;
is_default_gateway = false;
}
}
else
{
m_is_sta_mode = is_sta_mode;
IPACMDBG_H("The new WAN interface is WLAN STA.\n");
}
wan_client_len = (sizeof(ipa_wan_client)) + (iface_query->num_tx_props * sizeof(wan_client_rt_hdl));
wan_client = (ipa_wan_client *)calloc(IPA_MAX_NUM_WAN_CLIENTS, wan_client_len);
if (wan_client == NULL)
{
IPACMERR("unable to allocate memory\n");
return;
}
}
else
{
IPACMDBG_H("iface_query is empty.\n");
return;
}
m_fd_ipa = open(IPA_DEVICE_NAME, O_RDWR);
if(0 == m_fd_ipa)
{
IPACMERR("Failed to open %s\n",IPA_DEVICE_NAME);
}
if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == EMBMS_IF)
{
IPACMDBG(" IPACM->IPACM_Wan_eMBMS(%d)\n", ipa_if_num);
embms_is_on = true;
install_wan_filtering_rule(false);
if(IPACM_Iface::ipacmcfg->GetIPAVer() >= IPA_HW_None && IPACM_Iface::ipacmcfg->GetIPAVer() < IPA_HW_v4_0)
{
/* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
if(tx_prop != NULL)
{
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);
}
}
}
else
{
IPACMDBG(" IPACM->IPACM_Wan(%d)\n", ipa_if_num);
}
return;
}
IPACM_Wan::~IPACM_Wan()
{
IPACM_EvtDispatcher::deregistr(this);
IPACM_IfaceManager::deregistr(this);
return;
}
/* handle new_address event */
int IPACM_Wan::handle_addr_evt(ipacm_event_data_addr *data)
{
struct ipa_ioc_add_rt_rule *rt_rule = NULL;
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;
bool result;
const int NUM_RULES = 1;
uint32_t num_ipv6_addr;
int res = IPACM_SUCCESS,len;
#ifdef FEATURE_IPACM_HAL
IPACM_OffloadManager* OffloadMng;
#endif
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;
}
/* Update the IP Type. */
config_ip_type(data->iptype);
if (data->iptype == IPA_IP_v6)
{
for(num_ipv6_addr=0;num_ipv6_addr<num_dft_rt_v6;num_ipv6_addr++)
{
if((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
(ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
(ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
(ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
{
IPACMDBG_H("find matched ipv6 address, index:%d \n", num_ipv6_addr);
return IPACM_SUCCESS;
break;
}
}
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));
if (!rt_rule)
{
IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
return IPACM_FAILURE;
}
rt_rule->commit = 1;
rt_rule->num_rules = NUM_RULES;
rt_rule->ip = data->iptype;
/* setup RT rule for v6_lan table*/
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
rt_rule_entry = &rt_rule->rules[0];
rt_rule_entry->at_rear = false;
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];
rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[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;
ipv6_addr[num_dft_rt_v6][0] = data->ipv6_addr[0];
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 (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = false;
if(m_is_sta_mode == Q6_WAN)
{
strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
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;
/* legacy default v4 rt-rule */
#ifdef IPA_RT_SUPPORT_COAL
rt_rule_entry->rule.coalesce = false;
#endif
/* legacy default v6 rt-rule */
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[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
/* setup same rule for v6_wan table*/
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
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[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv6 wan iface rt-rule hdl=0x%x hdl=0x%x, entry: %d %d\n",
dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6],
dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1],
MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6,
MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1);
/* RSC TCP rule*/
rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
rt_rule_entry->rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_TCP;
#ifdef IPA_RT_SUPPORT_COAL
if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
rt_rule_entry->rule.coalesce = true;
else
rt_rule_entry->rule.coalesce = false;
#endif
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("rsc tcp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail;
}
dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv6 wan iface rsc tcp rt-rule hdll=0x%x\n enable(%d), entry %d", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6],
IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable,
2*MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6);
/* RSB UDP rule*/
rt_rule_entry->rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_UDP;
#ifdef IPA_RT_SUPPORT_COAL
if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable)
rt_rule_entry->rule.coalesce = true;
else
rt_rule_entry->rule.coalesce = false;
#endif
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("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail;
}
dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv6 wan iface rsb udp rt-rule hdll=0x%x\n enable(%d) entry %d", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1],
IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable,
2*MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1);
}
else
{
rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
/* legacy default v6 rt-rule */
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[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
/* setup same rule for v6_wan table*/
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
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[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv6 wan iface rt-rule hdl=0x%x hdl=0x%x, entry: %d %d\n",
dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6],
dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1],
MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6,
MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1);
}
/* add default filtering rules when wan-iface get global v6-prefix */
if (num_dft_rt_v6 == 1)
{
if(m_is_sta_mode == Q6_WAN)
{
modem_ipv6_pdn_index = num_ipv6_modem_pdn;
num_ipv6_modem_pdn++;
IPACMDBG_H("Now the number of modem ipv6 pdn is %d.\n", num_ipv6_modem_pdn);
init_fl_rule_ex(data->iptype);
}
else if(m_is_sta_mode == Q6_MHI_WAN)
{
IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING for ip-family %d \n", dev_name, IPA_IP_v6);
IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, IPA_IP_v6);
}
else
{
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;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(flt_rule, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(flt_rule);
}
#else
result = m_filtering.AddFilteringRule(flt_rule);
#endif
if (result == false)
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
free(flt_rule);
res = IPACM_FAILURE;
goto fail;
}
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++;
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
{
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 Coalese v4 RT rule */
if (m_is_sta_mode == Q6_WAN) {
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[0], IPA_IP_v4) == false)
{
IPACMERR("Routing old RSC TCP RT rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[1], IPA_IP_v4) == false)
{
IPACMERR("Routing old RSB UDP RT rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
}
/* 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));
if (!rt_rule)
{
IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
return IPACM_FAILURE;
}
rt_rule->commit = 1;
rt_rule->num_rules = NUM_RULES;
rt_rule->ip = data->iptype;
rt_rule_entry = &rt_rule->rules[0];
rt_rule_entry->at_rear = false;
rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
/* still need setup v4 default routing rule to A5*/
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_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 (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = false;
if(m_is_sta_mode == Q6_WAN)
{
/* query qmap header*/
strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(m_header.GetHeaderHandle(&hdr) == false)
{
IPACMERR("Failed to get QMAP header.\n");
res = IPACM_FAILURE;
goto fail;
}
rt_rule_entry->rule.hdr_hdl = hdr.hdl;
rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
/* legacy default v4 rt-rule */
#ifdef IPA_RT_SUPPORT_COAL
rt_rule_entry->rule.coalesce = false;
#endif
/* legacy default v4 rt-rule */
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 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
/* RSC TCP rule*/
rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
rt_rule_entry->rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_TCP;
#ifdef IPA_RT_SUPPORT_COAL
if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
rt_rule_entry->rule.coalesce = true;
else
rt_rule_entry->rule.coalesce = false;
#endif
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("rsc tcp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail;
}
dft_coalesce_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv4 wan iface rsc tcp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[0],
IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable);
/* RSB UDP rule*/
rt_rule_entry->rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_UDP;
#ifdef IPA_RT_SUPPORT_COAL
if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable)
rt_rule_entry->rule.coalesce = true;
else
rt_rule_entry->rule.coalesce = false;
#endif
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("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail;
}
dft_coalesce_rt_rule_hdl[1] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv4 wan iface rsb udp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[1],
IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable);
}
else
{
rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
/* legacy default v4 rt-rule */
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 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
}
/* initial multicast/broadcast/fragment filter rule */
/* only do one time */
if(!wan_v4_addr_set)
{
/* 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 if(m_is_sta_mode == Q6_MHI_WAN)
{
IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING for ip-family %d \n", dev_name, IPA_IP_v4);
IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, IPA_IP_v4);
}
else
{
init_fl_rule(data->iptype);
}
}
wan_v4_addr = data->ipv4_addr;
wan_v4_addr_set = true;
if (m_is_sta_mode == Q6_WAN)
curr_wan_ip = data->ipv4_addr;
IPACMDBG_H("Receved wan ipv4-addr:0x%x\n",wan_v4_addr);
}
#ifdef FEATURE_IPACM_HAL
/* check if having pending set_upstream cache*/
OffloadMng = IPACM_OffloadManager::GetInstance();
if (OffloadMng == NULL) {
IPACMERR("failed to get IPACM_OffloadManager instance !\n");
} else {
IPACMDBG_H(" check iface %s if having set_upstream cache events\n", dev_name);
OffloadMng->search_framwork_cache(dev_name);
}
#endif
IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
fail:
if (rt_rule != NULL)
{
free(rt_rule);
}
return res;
}
/* handle new_address event */
int IPACM_Wan::handle_addr_evt_mhi_q6(ipacm_event_data_addr *data)
{
uint32_t num_ipv6_addr;
int res = IPACM_SUCCESS;
struct ipa_ioc_add_rt_rule *rt_rule = NULL;
struct ipa_rt_rule_add *rt_rule_entry;
struct ipa_ioc_get_hdr hdr;
const int NUM_RULES = 1;
#ifdef FEATURE_IPACM_HAL
IPACM_OffloadManager* OffloadMng;
#endif
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;
}
/* Update the IP Type. */
config_ip_type(data->iptype);
if (data->iptype == IPA_IP_v6)
{
for(num_ipv6_addr=0;num_ipv6_addr<num_dft_rt_v6;num_ipv6_addr++)
{
if((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
(ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
(ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
(ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
{
IPACMDBG_H("find matched ipv6 address, index:%d \n", num_ipv6_addr);
return IPACM_SUCCESS;
break;
}
}
ipv6_addr[num_dft_rt_v6][0] = data->ipv6_addr[0];
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];
/* 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++;
if (num_dft_rt_v6 == 1)
{
/* Add Natting iface to IPACM_Config if there is Rx/Tx property */
if (rx_prop != NULL || tx_prop != NULL)
{
IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING for ip-family %d \n", dev_name, IPA_IP_v6);
IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, IPA_IP_v6);
}
/* setup v6-wan-tbl */
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));
if (!rt_rule)
{
IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
return IPACM_FAILURE;
}
rt_rule->commit = 1;
rt_rule->num_rules = NUM_RULES;
rt_rule->ip = data->iptype;
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
rt_rule_entry = &rt_rule->rules[0];
strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(m_header.GetHeaderHandle(&hdr) == false)
{
IPACMERR("Failed to get QMAP header.\n");
free(rt_rule);
return IPACM_FAILURE;
}
rt_rule_entry->rule.hdr_hdl = hdr.hdl;
rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
rt_rule_entry->at_rear = false;
rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
/* still need setup v4 default routing rule to A5*/
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];
rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[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;
ipv6_addr[0][0] = data->ipv6_addr[0];
ipv6_addr[0][1] = data->ipv6_addr[1];
ipv6_addr[0][2] = data->ipv6_addr[2];
ipv6_addr[0][3] = data->ipv6_addr[3];
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = false;
if (false == m_routing.AddRoutingRule(rt_rule))
{
IPACMERR("Routing rule addition failed!\n");
free(rt_rule);
return IPACM_FAILURE;
}
else if (rt_rule_entry->status)
{
IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
free(rt_rule);
return rt_rule_entry->status;
}
dft_rt_rule_hdl[1] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv6 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[1]);
}
}
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");
return IPACM_FAILURE;
}
}
}
/* only do one time */
if(!wan_v4_addr_set)
{
/* Add Natting iface to IPACM_Config if there is Rx/Tx property */
if (rx_prop != NULL || tx_prop != NULL)
{
IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING for ip-family %d \n", dev_name, IPA_IP_v4);
IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, IPA_IP_v4);
}
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));
if (!rt_rule)
{
IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
return IPACM_FAILURE;
}
rt_rule->commit = 1;
rt_rule->num_rules = NUM_RULES;
rt_rule->ip = data->iptype;
rt_rule_entry = &rt_rule->rules[0];
strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(m_header.GetHeaderHandle(&hdr) == false)
{
IPACMERR("Failed to get QMAP header.\n");
free(rt_rule);
return IPACM_FAILURE;
}
rt_rule_entry->rule.hdr_hdl = hdr.hdl;
rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
rt_rule_entry->at_rear = false;
rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
/* still need setup v4 default routing rule to A5*/
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_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 (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = false;
if (false == m_routing.AddRoutingRule(rt_rule))
{
IPACMERR("Routing rule addition failed!\n");
free(rt_rule);
return IPACM_FAILURE;
}
else if (rt_rule_entry->status)
{
IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
free(rt_rule);
return rt_rule_entry->status;
}
dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv4 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
}
wan_v4_addr = data->ipv4_addr;
wan_v4_addr_set = true;
IPACMDBG_H("Receved wan ipv4-addr:0x%x\n",wan_v4_addr);
free(rt_rule);
}
#ifdef FEATURE_IPACM_HAL
/* check if having pending set_upstream cache*/
OffloadMng = IPACM_OffloadManager::GetInstance();
if (OffloadMng == NULL) {
IPACMERR("failed to get IPACM_OffloadManager instance !\n");
} else {
IPACMDBG_H(" check iface %s if having set_upstream cache events\n", dev_name);
OffloadMng->search_framwork_cache(dev_name);
}
#endif
IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
return res;
}
void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param)
{
int ipa_interface_index;
switch (event)
{
case IPA_WLAN_LINK_DOWN_EVENT:
{
if(m_is_sta_mode == WLAN_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)
{
IPACMDBG_H("Received IPA_WLAN_LINK_DOWN_EVENT\n");
handle_down_evt();
/* reset the STA-iface category to unknown */
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat = UNKNOWN_IF;
IPACMDBG_H("IPA_WAN_STA (%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;
case IPA_WAN_XLAT_CONNECT_EVENT:
{
IPACMDBG_H("Recieved IPA_WAN_XLAT_CONNECT_EVENT\n");
ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
if ((ipa_interface_index == ipa_if_num) && (m_is_sta_mode == Q6_WAN))
{
is_xlat_local = true;
IPACMDBG_H("WAN-LTE (%s) link up, iface: %d is_xlat_local: %d\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,data->if_index, is_xlat_local);
}
break;
}
case IPA_CFG_CHANGE_EVENT:
{
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(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");
backhaul_is_wan_bridge = true;
}
else if(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");
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);
/* posting link-up event for cradle use-case */
ipacm_cmd_q_data evt_data;
memset(&evt_data, 0, sizeof(evt_data));
ipacm_event_data_fid *data_fid = NULL;
data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for IPA_USB_LINK_UP_EVENT data_fid\n");
return;
}
if(IPACM_Iface::ipa_get_if_index(dev_name, &(data_fid->if_index)))
{
IPACMERR("Error while getting interface index for %s device", dev_name);
}
evt_data.event = IPA_USB_LINK_UP_EVENT;
evt_data.evt_data = data_fid;
IPACMDBG_H("Posting event:%d\n", evt_data.event);
IPACM_EvtDispatcher::PostEvt(&evt_data);
/* delete previous instance */
handle_down_evt();
IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
delete this;
return;
}
}
break;
case IPA_COALESCE_NOTICE:
{
if (m_is_sta_mode == Q6_WAN)
{
IPACMDBG_H("Received IPA_COALESCE_NOTICE (wan_mode:%d)\n", m_is_sta_mode);
handle_coalesce_evt();
}
}
break;
case IPA_LINK_DOWN_EVENT:
{
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);
IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
delete this;
return;
}
else if ((m_is_sta_mode == ECM_WAN) || (m_is_sta_mode == Q6_MHI_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;
case IPA_ADDR_ADD_EVENT:
{
ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
ipa_interface_index = iface_ipa_index_query(data->if_index);
if ( (data->iptype == IPA_IP_v4 && data->ipv4_addr == 0) ||
(data->iptype == IPA_IP_v6 &&
data->ipv6_addr[0] == 0 && data->ipv6_addr[1] == 0 &&
data->ipv6_addr[2] == 0 && data->ipv6_addr[3] == 0) )
{
IPACMDBG_H("Invalid address, ignore IPA_ADDR_ADD_EVENT event\n");
return;
}
if (ipa_interface_index == ipa_if_num)
{
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 == IPA_IP_v4)
|| ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
{
if (m_is_sta_mode == Q6_MHI_WAN)
{
IPACMDBG_H("Got handle_addr_evt_mhi_q6 ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
handle_addr_evt_mhi_q6(data);
}
else
{
IPACMDBG_H("Got handle_addr_evt ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
handle_addr_evt(data);
}
/* checking if SW-RT_enable */
if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true &&
m_is_sta_mode != Q6_WAN)
{
/* handle software routing enable event*/
IPACMDBG_H("IPA_SW_ROUTING_ENABLE for iface: %s \n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
if(m_is_sta_mode == Q6_MHI_WAN)
{
handle_software_routing_enable(true);
}
else
{
handle_software_routing_enable(false);
}
}
}
}
}
break;
case IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT:
{
ipacm_event_data_iptype *data = (ipacm_event_data_iptype *)param;
ipa_interface_index = iface_ipa_index_query(data->if_index);
#ifndef FEATURE_IPACM_HAL
/* add the check see if tether_iface is valid or not */
if (iface_ipa_index_query(data->if_index_tether) == INVALID_IFACE)
{
IPACMERR("UPSTREAM_ROUTE_ADD tether_if(%d), not valid ignore\n", INVALID_IFACE);
return;
}
#endif
if (ipa_interface_index == ipa_if_num)
{
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) && (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX))
{
if (active_v4 == false)
{
#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
IPACMDBG_H("adding routing table(upstream), dev (%s) ip-type(%d) default gw (%x)\n", dev_name,data->iptype, wan_v4_addr_gw);
wan_v4_addr_gw = data->ipv4_addr_gw;
wan_v4_addr_gw_set = true;
/* Check & construct STA header */
handle_sta_header_add_evt();
#else
IPACMDBG_H("adding routing table(upstream), dev (%s) ip-type(%d)\n", dev_name,data->iptype);
#endif
if (active_v4 == false)
{
handle_route_add_evt(data->iptype);
}
}
#ifdef FEATURE_IPA_ANDROID
#ifndef FEATURE_IPACM_HAL
/* Fixed CR 2438491 for HAL-android platform trgets.
Need to revisit for non-hal-android-platform targets if issue could be reproduced there as well */
/* using ipa_if_index, not netdev_index */
post_wan_up_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
#endif
#endif
}
else if ((data->iptype == IPA_IP_v6) && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
{
if(ipv6_prefix[0] == 0 && ipv6_prefix[1] == 0)
{
IPACMDBG_H("IPv6 default route comes earlier than global IP, ignore.\n");
return;
}
if (active_v6 == false)
{
IPACMDBG_H("\n get default v6 route (dst:00.00.00.00) upstream\n");
#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
IPACMDBG_H(" IPV6 gateway: %08x:%08x:%08x:%08x \n",
data->ipv6_addr_gw[0], data->ipv6_addr_gw[1], data->ipv6_addr_gw[2], data->ipv6_addr_gw[3]);
wan_v6_addr_gw[0] = data->ipv6_addr_gw[0];
wan_v6_addr_gw[1] = data->ipv6_addr_gw[1];
wan_v6_addr_gw[2] = data->ipv6_addr_gw[2];
wan_v6_addr_gw[3] = data->ipv6_addr_gw[3];
wan_v6_addr_gw_set = true;
/* Check & construct STA header */
handle_sta_header_add_evt();
#endif
if (active_v6 == false)
{
handle_route_add_evt(data->iptype);
}
}
}
#ifdef FEATURE_IPA_ANDROID
#ifndef FEATURE_IPACM_HAL
/* using ipa_if_index, not netdev_index */
post_wan_up_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
#endif
#endif
}
else /* double check if current default iface is not itself */
{
if ((data->iptype == IPA_IP_v4) && (active_v4 == true))
{
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;
if(m_is_sta_mode == Q6_WAN)
{
del_wan_firewall_rule(IPA_IP_v4);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v4);
}
else if(m_is_sta_mode == Q6_MHI_WAN)
{
/* only need cleanup rt-rule*/
handle_route_del_evt(IPA_IP_v4);
}
else
{
del_dft_firewall_rules(IPA_IP_v4);
handle_route_del_evt(IPA_IP_v4);
}
}
else if ((data->iptype == IPA_IP_v6) && (active_v6 == true))
{
IPACMDBG_H("Received v6 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 v6 route for old iface (%s)\n", dev_name);
if(m_is_sta_mode == Q6_WAN)
{
del_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v6);
}
else if(m_is_sta_mode == Q6_MHI_WAN)
{
/* only need cleanup rt-rule*/
handle_route_del_evt(IPA_IP_v6);
}
else
{
del_dft_firewall_rules(IPA_IP_v6);
handle_route_del_evt(IPA_IP_v6);
}
}
}
}
break;
case IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT:
{
ipacm_event_data_iptype *data = (ipacm_event_data_iptype *)param;
ipa_interface_index = iface_ipa_index_query(data->if_index);
#ifndef FEATURE_IPACM_HAL
/* add the check see if tether_iface is valid or not */
if (iface_ipa_index_query(data->if_index_tether) == INVALID_IFACE)
{
IPACMERR("UPSTREAM_ROUTE_DEL tether_if(%d), not valid ignore\n", INVALID_IFACE);
return;
}
#endif
if (ipa_interface_index == ipa_if_num)
{
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;
#ifdef FEATURE_IPA_ANDROID
#ifdef FEATURE_IPACM_HAL
post_wan_down_tether_evt(data->iptype, 0);
#else
/* using ipa_if_index, not netdev_index */
post_wan_down_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
/* no any ipv4 tether iface support*/
if(IPACM_Wan::ipa_if_num_tether_v4_total != 0)
{
IPACMDBG_H("still have tether ipv4 client on upsteam iface\n");
return;
}
#endif
#endif
if(m_is_sta_mode == Q6_WAN)
{
del_wan_firewall_rule(IPA_IP_v4);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v4);
}
else if(m_is_sta_mode == Q6_MHI_WAN)
{
/* only need cleanup rt-rule*/
del_dft_firewall_rules(IPA_IP_v4);
handle_route_del_evt(IPA_IP_v4);
}
else
{
del_dft_firewall_rules(IPA_IP_v4);
handle_route_del_evt(IPA_IP_v4);
}
}
else if ((data->iptype == IPA_IP_v6) && (active_v6 == true))
{
#ifdef FEATURE_IPA_ANDROID
#ifdef FEATURE_IPACM_HAL
post_wan_down_tether_evt(data->iptype, 0);
#else
/* using ipa_if_index, not netdev_index */
post_wan_down_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
/* no any ipv6 tether iface support*/
if(IPACM_Wan::ipa_if_num_tether_v6_total != 0)
{
IPACMDBG_H("still have tether ipv6 client on upsteam iface\n");
return;
}
#endif
#endif
if(m_is_sta_mode == Q6_WAN)
{
del_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v6);
}
else if(m_is_sta_mode == Q6_MHI_WAN)
{
/* only need cleanup rt-rule*/
del_dft_firewall_rules(IPA_IP_v6);
handle_route_del_evt(IPA_IP_v6);
}
else
{
del_dft_firewall_rules(IPA_IP_v6);
handle_route_del_evt(IPA_IP_v6);
}
}
}
}
break;
case IPA_NETWORK_STATS_UPDATE_EVENT:
{
ipa_get_apn_data_stats_resp_msg_v01 *data = (ipa_get_apn_data_stats_resp_msg_v01 *)param;
if (!data->apn_data_stats_list_valid)
{
IPACMERR("not valid APN\n");
return;
}
else
{
handle_network_stats_update(data);
}
}
break;
case IPA_ROUTE_ADD_EVENT:
{
ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
ipa_interface_index = iface_ipa_index_query(data->if_index);
if (ipa_interface_index == ipa_if_num)
{
IPACMDBG_H("Received IPA_ROUTE_ADD_EVENT\n");
IPACMDBG_H("ipv4 addr 0x%x\n", data->ipv4_addr);
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)
&& (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX))
{
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);
/* Add IPv6 routing table if XLAT is enabled */
if(is_xlat_local && (m_is_sta_mode == Q6_WAN) && (active_v6 == false))
{
IPACMDBG_H("XLAT enabled: adding IPv6 routing table dev (%s)\n", dev_name);
handle_route_add_evt(IPA_IP_v6);
}
}
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) && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
{
if(ipv6_prefix[0] == 0 && ipv6_prefix[1] == 0)
{
IPACMDBG_H("IPv6 default route comes earlier than global IP, ignore.\n");
return;
}
IPACMDBG_H("\n get default v6 route (dst:00.00.00.00)\n");
IPACMDBG_H(" IPV6 dst: %08x:%08x:%08x:%08x \n",
data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
IPACMDBG_H(" IPV6 gateway: %08x:%08x:%08x:%08x \n",
data->ipv6_addr_gw[0], data->ipv6_addr_gw[1], data->ipv6_addr_gw[2], data->ipv6_addr_gw[3]);
wan_v6_addr_gw[0] = data->ipv6_addr_gw[0];
wan_v6_addr_gw[1] = data->ipv6_addr_gw[1];
wan_v6_addr_gw[2] = data->ipv6_addr_gw[2];
wan_v6_addr_gw[3] = data->ipv6_addr_gw[3];
wan_v6_addr_gw_set = true;
/* Check & construct STA header */
handle_sta_header_add_evt();
handle_route_add_evt(data->iptype);
}
}
else /* double check if current default iface is not itself */
{
if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == true))
{
IPACMDBG_H("Received v4 IPA_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
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);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v4);
}
else
{
del_dft_firewall_rules(IPA_IP_v4);
handle_route_del_evt(IPA_IP_v4);
}
}
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("Received v6 IPA_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
IPACMDBG_H("need clean default v6 route for old iface (%s)\n", dev_name);
if(m_is_sta_mode == Q6_WAN)
{
del_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v6);
}
else
{
del_dft_firewall_rules(IPA_IP_v6);
handle_route_del_evt(IPA_IP_v6);
}
}
}
}
break;
case IPA_ROUTE_DEL_EVENT:
{
ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
ipa_interface_index = iface_ipa_index_query(data->if_index);
if (ipa_interface_index == ipa_if_num)
{
IPACMDBG_H("Received IPA_ROUTE_DEL_EVENT\n");
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);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v4);
if(is_xlat_local && active_v6 == true)
{
IPACMDBG_H("XLAT enabled: Delete IPv6 routing table dev (%s)\n", dev_name);
del_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v6);
}
}
else
{
del_dft_firewall_rules(IPA_IP_v4);
handle_route_del_evt(IPA_IP_v4);
}
}
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");
if(m_is_sta_mode == Q6_WAN)
{
del_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v6);
}
else
{
del_dft_firewall_rules(IPA_IP_v6);
handle_route_del_evt(IPA_IP_v6);
}
}
}
}
break;
case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
{
ipacm_event_data_all *data = (ipacm_event_data_all *)param;
ipa_interface_index = iface_ipa_index_query(data->if_index);
int index = 0;
bool renew = false;
if (ipa_interface_index == ipa_if_num)
{
IPACMDBG_H("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
if (m_is_sta_mode == WLAN_WAN)
{
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");
IPACMDBG_H("for its own ipv4 address\n");
return;
}
else if (data->iptype == IPA_IP_v6)
{
for (uint32_t num_ipv6_addr = 0; num_ipv6_addr < num_dft_rt_v6; num_ipv6_addr++)
{
if ((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
(ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
(ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
(ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
{
IPACMDBG_H("Ignore IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
IPACMDBG_H("for its own ipv6 address\n");
return;
}
}
}
}
IPACMDBG_H("wan-iface got client \n");
/* first construc WAN-client full header */
if(memcmp(data->mac_addr,
invalid_mac,
sizeof(data->mac_addr)) == 0)
{
IPACMDBG_H("Received invalid Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
data->mac_addr[0], data->mac_addr[1], data->mac_addr[2],
data->mac_addr[3], data->mac_addr[4], data->mac_addr[5]);
return;
}
/* check if same as GW_ip need replacing */
if( handle_gw_mac_renew(data, index) == IPACM_SUCCESS)
{
renew = true;
IPACMDBG_H("Renew is happening with client-index (%d)\n", index);
/* clinet renew procedure */
handle_wan_hdr_init(data->mac_addr, true, index);
}
else
{
IPACMDBG_H("Renew is no need!\n");
handle_wan_hdr_init(data->mac_addr);
}
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(renew);
return;
}
}
break;
case IPA_SW_ROUTING_ENABLE:
IPACMDBG_H("Received IPA_SW_ROUTING_ENABLE\n");
/* handle software routing enable event */
if(m_is_sta_mode == Q6_WAN)
{
install_wan_filtering_rule(true);
}
else if(m_is_sta_mode == Q6_MHI_WAN)
{
handle_software_routing_enable(true);
}
else
{
handle_software_routing_enable(false);
}
break;
case IPA_SW_ROUTING_DISABLE:
IPACMDBG_H("Received IPA_SW_ROUTING_DISABLE\n");
/* handle software routing disable event */
if(m_is_sta_mode == Q6_WAN)
{
/* send current DL rules to modem */
install_wan_filtering_rule(false);
softwarerouting_act = false;
}
else if(m_is_sta_mode == Q6_MHI_WAN)
{
handle_software_routing_disable(true);
}
else
{
handle_software_routing_disable(false);
}
break;
case IPA_FIREWALL_CHANGE_EVENT:
IPACMDBG_H("Received IPA_FIREWALL_CHANGE_EVENT\n");
if(m_is_sta_mode == Q6_WAN)
{
if(is_default_gateway == false)
{
IPACMDBG_H("Interface %s is not default gw, return.\n", dev_name);
return;
}
if(ip_type == IPA_IP_v4)
{
del_wan_firewall_rule(IPA_IP_v4);
config_wan_firewall_rule(IPA_IP_v4);
install_wan_filtering_rule(false);
}
else if(ip_type == IPA_IP_v6)
{
del_wan_firewall_rule(IPA_IP_v6);
config_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
}
else if(ip_type == IPA_IP_MAX)
{
del_wan_firewall_rule(IPA_IP_v4);
config_wan_firewall_rule(IPA_IP_v4);
del_wan_firewall_rule(IPA_IP_v6);
config_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
}
else
{
IPACMERR("IP type is not expected.\n");
}
}
else
{
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);
}
}
break;
case IPA_WLAN_SWITCH_TO_SCC:
if(IPACM_Wan::backhaul_mode == WLAN_WAN)
{
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_mode == WLAN_WAN)
{
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;
#ifdef FEATURE_IPACM_HAL
/* WA for WLAN to clean up NAT instance during SSR */
case IPA_SSR_NOTICE:
case IPA_WLAN_FWR_SSR_BEFORE_SHUTDOWN_NOTICE:
{
IPACMDBG_H("Received IPA_SSR_NOTICE event.\n");
if(m_is_sta_mode == WLAN_WAN)
{
IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
}
}
break;
#endif
#ifdef IPA_MTU_EVENT_MAX
case IPA_MTU_SET:
{
ipacm_event_mtu_info *data = (ipacm_event_mtu_info *)param;
ipa_mtu_info *mtu_info = &(data->mtu_info);
ipa_interface_index = iface_ipa_index_query(data->if_index);
if (ipa_interface_index == ipa_if_num)
{
IPACMDBG_H("Received IPA_MTU_SET (Android) for interface (%d)\n",
ipa_interface_index);
if (mtu_info->ip_type == IPA_IP_v4 || mtu_info->ip_type == IPA_IP_MAX)
{
/* Update v4_mtu. */
mtu_v4 = mtu_info->mtu_v4;
mtu_v4_set = true;
if (active_v4)
{
/* upstream interface. update default MTU. */
mtu_default_wan_v4 = mtu_v4;
}
IPACMDBG_H("Updated v4 mtu=[%d] for (%s), upstream_mtu=[%d]\n",
mtu_v4, mtu_info->if_name, mtu_default_wan_v4);
}
if (mtu_info->ip_type == IPA_IP_v6 || mtu_info->ip_type == IPA_IP_MAX)
{
/* Update v4_mtu. */
mtu_v6 = mtu_info->mtu_v6;
mtu_v6_set = true;
if (active_v6)
{
/* upstream interface. update default MTU. */
mtu_default_wan_v6 = mtu_v6;
}
IPACMDBG_H("Updated v6 mtu=[%d] for (%s), upstream_mtu=[%d]\n",
mtu_v6, mtu_info->if_name, mtu_default_wan_v6);
}
if (active_v4 || active_v6)
{
ipacm_event_mtu_info *mtu_event;
ipacm_cmd_q_data evt_data;
mtu_event = (ipacm_event_mtu_info *)malloc(sizeof(*mtu_event));
if(mtu_event == NULL)
{
IPACMERR("Failed to allocate memory.\n");
return;
}
memcpy(&mtu_event->mtu_info, mtu_info, sizeof(ipa_mtu_info));
evt_data.event = IPA_MTU_UPDATE;
evt_data.evt_data = mtu_event;
/* finish command queue */
IPACMDBG_H("Posting IPA_MTU_UPDATE event\n");
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
}
}
break;
#endif
default:
break;
}
return;
}
/* wan default route/filter rule configuration */
int IPACM_Wan::handle_route_add_evt(ipa_ip_type iptype, bool add_only)
{
/* add default WAN route */
struct ipa_ioc_add_rt_rule *rt_rule = NULL;
struct ipa_rt_rule_add *rt_rule_entry;
uint32_t tx_index = 0;
const int NUM = 1;
ipacm_cmd_q_data evt_data;
struct ipa_ioc_get_hdr hdr;
bool result;
#ifdef WAN_IOC_NOTIFY_WAN_STATE //resolve compile issue on 4.9 kernel
struct wan_ioctl_notify_wan_state wan_state;
int fd_wwan_ioctl;
memset(&wan_state, 0, sizeof(wan_state));
#endif
IPACMDBG_H("ip-type:%d\n", iptype);
/* copy header from tx-property, see if partial or not */
/* assume all tx-property uses the same header name for v4 or v6*/
if(tx_prop == NULL)
{
IPACMDBG_H("No tx properties, ignore default route setting\n");
return IPACM_SUCCESS;
}
is_default_gateway = true;
IPACMDBG_H("Default route is added to iface %s.\n", dev_name);
if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == BRIDGE)
{
IPACM_Wan::backhaul_is_wan_bridge = true;
}
else
{
IPACM_Wan::backhaul_is_wan_bridge = false;
}
IPACMDBG_H("backhaul_is_wan_bridge ?: %d \n", IPACM_Wan::backhaul_is_wan_bridge);
/* query MTU size of the interface if MTU is not set via ioctl. */
if (!mtu_v4_set && !mtu_v6_set)
{
if(query_mtu_size())
{
IPACMERR("Failed to query mtu");
}
}
if (m_is_sta_mode ==Q6_WAN)
{
IPACM_Wan::backhaul_mode = m_is_sta_mode;
IPACMDBG_H("reset backhaul to LTE \n");
if (iface_query != NULL && iface_query->num_ext_props > 0)
{
if(ext_prop == NULL)
{
IPACMERR("Extended property is empty.\n");
return IPACM_FAILURE;
}
else
{
IPACM_Iface::ipacmcfg->SetQmapId(ext_prop->ext[0].mux_id);
IPACMDBG_H("Setting up QMAP ID %d.\n", ext_prop->ext[0].mux_id);
}
}
else
{
IPACMERR("iface_query is empty.\n");
return IPACM_FAILURE;
}
}
else if (m_is_sta_mode == Q6_MHI_WAN)
{
if (iface_query != NULL && iface_query->num_ext_props > 0)
{
/* treat Q6_MHI_WAN as STA mode also */
IPACMDBG_H("Q6-MHI ipv4/v6-header already constructed \n");
IPACM_Wan::backhaul_mode = m_is_sta_mode;
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, 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;
}
/* send ipv6 ICMP filtering rule */
if(iptype==IPA_IP_v6 && add_icmpv6_exception_rule())
{
IPACMERR("Failed to send ICMPv6 ex rule to modem.\n");
return IPACM_FAILURE;
}
/* send ipv4 TCP FIN filtering rule */
if(iptype==IPA_IP_v4 && add_tcp_fin_rst_exception_rule())
{
IPACMERR("Failed to send TCP FIN RST rule to modem.\n");
return IPACM_FAILURE;
}
}
else
{
IPACMERR("iface_query is empty.\n");
return IPACM_FAILURE;
}
}
else
{
IPACM_Wan::backhaul_mode = m_is_sta_mode;
if((iptype==IPA_IP_v4) && (header_set_v4 != true))
{
header_partial_default_wan_v4 = true;
IPACMDBG_H("STA ipv4-header haven't constructed \n");
return IPACM_SUCCESS;
}
else if((iptype==IPA_IP_v6) && (header_set_v6 != true))
{
header_partial_default_wan_v6 = true;
IPACMDBG_H("STA ipv6-header haven't constructed \n");
return IPACM_SUCCESS;
}
}
rt_rule = (struct ipa_ioc_add_rt_rule *)
calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
NUM * sizeof(struct ipa_rt_rule_add));
if (!rt_rule)
{
IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
return IPACM_FAILURE;
}
rt_rule->commit = 1;
rt_rule->num_rules = (uint8_t)NUM;
rt_rule->ip = iptype;
rt_rule_entry = &rt_rule->rules[0];
rt_rule_entry->at_rear = true;
if(m_is_sta_mode != Q6_WAN)
{
IPACMDBG_H(" WAN instance is in STA mode \n");
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;
}
/* use the STA-header handler */
if (iptype == IPA_IP_v4)
{
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name, sizeof(rt_rule->rt_tbl_name));
rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v4;
}
else
{
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v6;
}
IPACMDBG_H(" WAN table created %s \n", rt_rule->rt_tbl_name);
/* replace the hdr handle for q6_PCIE*/
if(m_is_sta_mode == Q6_MHI_WAN)
{
memset(&hdr, 0, sizeof(hdr));
strlcpy(hdr.name, tx_prop->tx[tx_index].hdr_name, sizeof(hdr.name));
hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(m_header.GetHeaderHandle(&hdr) == false)
{
IPACMERR("Failed to get QMAP header.\n");
free(rt_rule);
return IPACM_FAILURE;
}
rt_rule_entry->rule.hdr_hdl = hdr.hdl;
rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
}
else
{
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;
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;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = true;
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if((m_is_sta_mode == WLAN_WAN) && IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + UL_HW);
result = m_routing.AddRoutingRule_hw_index(rt_rule, IPACM_Iface::ipacmcfg->hw_counter_offset + UL_HW);
} else {
result = m_routing.AddRoutingRule(rt_rule);
}
#else
result = m_routing.AddRoutingRule(rt_rule);
#endif
if (result == false)
{
IPACMERR("Routing rule addition failed!\n");
free(rt_rule);
return IPACM_FAILURE;
}
wan_route_rule_v4_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("Got ipv4 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
wan_route_rule_v4_hdl[tx_index],
tx_index,
iptype);
}
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;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = true;
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if((m_is_sta_mode == WLAN_WAN) && IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + UL_HW);
result = m_routing.AddRoutingRule_hw_index(rt_rule, IPACM_Iface::ipacmcfg->hw_counter_offset + UL_HW);
} else {
result = m_routing.AddRoutingRule(rt_rule);
}
#else
result = m_routing.AddRoutingRule(rt_rule);
#endif
if (result == false)
{
IPACMERR("Routing rule addition failed!\n");
free(rt_rule);
return IPACM_FAILURE;
}
wan_route_rule_v6_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("Set ipv6 wan-route rule hdl for v6_lan_table:0x%x,tx:%d,ip-type: %d \n",
wan_route_rule_v6_hdl[tx_index],
tx_index,
iptype);
}
}
}
/* add a catch-all rule in wan dl routing table */
if (iptype == IPA_IP_v6 && m_is_sta_mode != Q6_MHI_WAN)
{
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
IPACMDBG_H(" WAN table created %s \n", rt_rule->rt_tbl_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));
strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(m_header.GetHeaderHandle(&hdr) == false)
{
IPACMERR("Failed to get QMAP header.\n");
free(rt_rule);
return IPACM_FAILURE;
}
rt_rule_entry->rule.hdr_hdl = hdr.hdl;
rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
}
else
{
/* create dummy ethernet header for v6 RX path */
IPACMDBG_H("Construct dummy ethernet_header\n");
if (add_dummy_rx_hdr())
{
IPACMERR("Construct dummy ethernet_header failed!\n");
free(rt_rule);
return IPACM_FAILURE;
}
rt_rule_entry->rule.hdr_proc_ctx_hdl = hdr_proc_hdl_dummy_v6;
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 (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = true;
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);
}
/* support delete only, not post wan_down event */
if (add_only)
{
IPACMDBG_H(" Only add default WAN routing rules (%d)\n", add_only);
if(rt_rule != NULL)
{
free(rt_rule);
}
return IPACM_SUCCESS;
}
ipacm_event_iface_up *wanup_data;
wanup_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
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));
/* handling filter rule construction */
if (iptype == IPA_IP_v4)
{
/* set mtu_default_wan to current default wan instance */
mtu_default_wan_v4 = mtu_v4;
IPACMDBG_H("replace the mtu_wan to %d\n", mtu_default_wan_v4);
IPACM_Wan::wan_up = true;
active_v4 = true;
memcpy(IPACM_Wan::wan_up_dev_name,
dev_name,
sizeof(IPACM_Wan::wan_up_dev_name));
if(m_is_sta_mode == Q6_WAN)
{
config_wan_firewall_rule(IPA_IP_v4);
install_wan_filtering_rule(false);
}
else
{
config_dft_firewall_rules(IPA_IP_v4);
}
memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
wanup_data->ipv4_addr = wan_v4_addr;
wanup_data->backhaul_type = m_is_sta_mode;
IPACMDBG_H("Posting IPA_HANDLE_WAN_UP with below information:\n");
IPACMDBG_H("if_name:%s, ipv4_address:0x%x, is sta mode:%d\n",
wanup_data->ifname, wanup_data->ipv4_addr, wanup_data->backhaul_type);
memset(&evt_data, 0, sizeof(evt_data));
/* set backhaul type as xlat */
IPACM_Wan::is_xlat = is_xlat_local;
/* send xlat configuration for installing uplink rules */
if(is_xlat_local && (m_is_sta_mode == Q6_WAN))
{
IPACM_Wan::xlat_mux_id = ext_prop->ext[0].mux_id;
wanup_data->xlat_mux_id = IPACM_Wan::xlat_mux_id;
IPACMDBG_H("Set xlat configuraiton with below information:\n");
IPACMDBG_H("xlat_enabled: %d set xlat_mux_id: %d \n",
is_xlat_local, IPACM_Wan::xlat_mux_id);
}
else /*temp put xlat = 0 for Q6_MHI_WAN*/
{
IPACM_Wan::xlat_mux_id = 0;
wanup_data->xlat_mux_id = 0;
if(m_is_sta_mode != WLAN_WAN) //both q6_wan/q6_mhi_wan
{
wanup_data->mux_id = ext_prop->ext[0].mux_id;
IPACMDBG_H("mux_id: %d\n", wanup_data->mux_id);
}
else
wanup_data->mux_id = 0;
IPACMDBG_H("No xlat configuration\n");
}
evt_data.event = IPA_HANDLE_WAN_UP;
evt_data.evt_data = (void *)wanup_data;
IPACM_EvtDispatcher::PostEvt(&evt_data);
#ifdef FEATURE_IPACM_HAL
post_wan_up_tether_evt(IPA_IP_v4, 0);
#endif
}
else
{
/* set mtu_default_wan to current default wan instance */
mtu_default_wan_v6 = mtu_v6;
IPACMDBG_H("replace the mtu_wan to %d\n", mtu_default_wan_v6);
memcpy(backhaul_ipv6_prefix, ipv6_prefix, sizeof(backhaul_ipv6_prefix));
IPACMDBG_H("Setup backhaul ipv6 prefix to be 0x%08x%08x.\n", backhaul_ipv6_prefix[0], backhaul_ipv6_prefix[1]);
IPACM_Wan::wan_up_v6 = true;
active_v6 = true;
memcpy(IPACM_Wan::wan_up_dev_name,
dev_name,
sizeof(IPACM_Wan::wan_up_dev_name));
if(m_is_sta_mode == Q6_WAN)
{
config_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
}
else
{
config_dft_firewall_rules(IPA_IP_v6);
}
memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
wanup_data->backhaul_type = m_is_sta_mode;
memcpy(wanup_data->ipv6_prefix, ipv6_prefix, sizeof(wanup_data->ipv6_prefix));
IPACMDBG_H("Posting IPA_HANDLE_WAN_UP_V6 with below information:\n");
IPACMDBG_H("if_name:%s, is sta mode: %d\n", wanup_data->ifname, wanup_data->backhaul_type);
IPACMDBG_H("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;
IPACM_EvtDispatcher::PostEvt(&evt_data);
#ifdef FEATURE_IPACM_HAL
post_wan_up_tether_evt(IPA_IP_v6, 0);
#endif
}
if(IPACM_Iface::ipacmcfg->GetIPAVer() >= IPA_HW_None && IPACM_Iface::ipacmcfg->GetIPAVer() < IPA_HW_v4_0)
{
/* 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);
}
#ifdef WAN_IOC_NOTIFY_WAN_STATE
else {
if ((m_is_sta_mode == Q6_WAN && ipa_pm_q6_check == 0 ) || (m_is_sta_mode == Q6_MHI_WAN))
{
fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
if(fd_wwan_ioctl < 0)
{
IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
free(rt_rule);
return false;
}
IPACMDBG_H("send WAN_IOC_NOTIFY_WAN_STATE up to IPA_PM\n");
wan_state.up = true;
#ifdef WAN_IOCTL_NOTIFY_WAN_INTF_NAME
strlcpy(wan_state.upstreamIface, dev_name, IFNAMSIZ);
#endif
if(ioctl(fd_wwan_ioctl, WAN_IOC_NOTIFY_WAN_STATE, &wan_state))
{
IPACMERR("Failed to send WAN_IOC_NOTIFY_WAN_STATE as up %d\n ", wan_state.up);
}
close(fd_wwan_ioctl);
}
ipa_pm_q6_check++;
IPACMDBG_H("update ipa_pm_q6_check to %d\n", ipa_pm_q6_check);
}
#endif
if(rt_rule != NULL)
{
free(rt_rule);
}
return IPACM_SUCCESS;
}
#ifdef FEATURE_IPA_ANDROID
/* wan default route/filter rule configuration */
int IPACM_Wan::post_wan_up_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether)
{
ipacm_cmd_q_data evt_data;
ipacm_event_iface_up_tehter *wanup_data;
wanup_data = (ipacm_event_iface_up_tehter *)malloc(sizeof(ipacm_event_iface_up_tehter));
if (wanup_data == NULL)
{
IPACMERR("Unable to allocate memory\n");
return IPACM_FAILURE;
}
memset(wanup_data, 0, sizeof(ipacm_event_iface_up_tehter));
wanup_data->if_index_tether = ipa_if_num_tether;
wanup_data->backhaul_type = m_is_sta_mode;
/* xlat mux-id*/
if(is_xlat_local && (m_is_sta_mode == Q6_WAN))
wanup_data->xlat_mux_id = ext_prop->ext[0].mux_id;
else
wanup_data->xlat_mux_id = 0;
IPACMDBG_H("Posting IPA_HANDLE_WAN_UP_TETHER with below information:\n");
IPACMDBG_H("tether_if_name:%s, is sta mode:%d xlat_mux_id: %d\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name, wanup_data->backhaul_type, wanup_data->xlat_mux_id);
memset(&evt_data, 0, sizeof(evt_data));
if (iptype == IPA_IP_v4)
{
evt_data.event = IPA_HANDLE_WAN_UP_TETHER;
#ifndef FEATURE_IPACM_HAL
/* Add support tether ifaces to its array*/
IPACM_Wan::ipa_if_num_tether_v4[IPACM_Wan::ipa_if_num_tether_v4_total] = ipa_if_num_tether;
IPACMDBG_H("adding tether iface(%s) ipa_if_num_tether_v4_total(%d) on wan_iface(%s)\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name,
IPACM_Wan::ipa_if_num_tether_v4_total,
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
IPACM_Wan::ipa_if_num_tether_v4_total++;
#endif
}
else
{
evt_data.event = IPA_HANDLE_WAN_UP_V6_TETHER;
memcpy(wanup_data->ipv6_prefix, ipv6_prefix, sizeof(wanup_data->ipv6_prefix));
#ifndef FEATURE_IPACM_HAL
/* Add support tether ifaces to its array*/
IPACM_Wan::ipa_if_num_tether_v6[IPACM_Wan::ipa_if_num_tether_v6_total] = ipa_if_num_tether;
IPACMDBG_H("adding tether iface(%s) ipa_if_num_tether_v6_total(%d) on wan_iface(%s)\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name,
IPACM_Wan::ipa_if_num_tether_v6_total,
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
IPACM_Wan::ipa_if_num_tether_v6_total++;
#endif
}
evt_data.evt_data = (void *)wanup_data;
IPACM_EvtDispatcher::PostEvt(&evt_data);
return IPACM_SUCCESS;
}
/* wan default route/filter rule configuration */
int IPACM_Wan::post_wan_down_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether)
{
ipacm_cmd_q_data evt_data;
ipacm_event_iface_up_tehter *wandown_data;
wandown_data = (ipacm_event_iface_up_tehter *)malloc(sizeof(ipacm_event_iface_up_tehter));
if (wandown_data == NULL)
{
IPACMERR("Unable to allocate memory\n");
return IPACM_FAILURE;
}
memset(wandown_data, 0, sizeof(ipacm_event_iface_up_tehter));
wandown_data->if_index_tether = ipa_if_num_tether;
wandown_data->backhaul_type = m_is_sta_mode;
IPACMDBG_H("Posting IPA_HANDLE_WAN_DOWN_TETHER with below information:\n");
IPACMDBG_H("tether_if_name:%s, is sta mode:%d\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name, wandown_data->backhaul_type);
memset(&evt_data, 0, sizeof(evt_data));
if (iptype == IPA_IP_v4)
{
#ifndef FEATURE_IPACM_HAL
if(delete_tether_iface(iptype, ipa_if_num_tether))
{
IPACMDBG_H("Not finding the tethered client on ipv4.\n");
free(wandown_data);
return IPACM_SUCCESS;
}
#endif
evt_data.event = IPA_HANDLE_WAN_DOWN_TETHER;
}
else
{
#ifndef FEATURE_IPACM_HAL
if(delete_tether_iface(iptype, ipa_if_num_tether))
{
IPACMDBG_H("Not finding the tethered client on ipv6.\n");
free(wandown_data);
return IPACM_SUCCESS;
}
#endif
evt_data.event = IPA_HANDLE_WAN_DOWN_V6_TETHER;
}
evt_data.evt_data = (void *)wandown_data;
IPACM_EvtDispatcher::PostEvt(&evt_data);
return IPACM_SUCCESS;
}
#endif
/* construct complete ethernet header */
int IPACM_Wan::handle_sta_header_add_evt(bool renew)
{
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;
}
/* checking if the ipv4 same as default route */
if(wan_v4_addr_gw_set)
{
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)
{
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);
/* store external_ap's MAC */
memcpy(ext_router_mac_addr, get_client_memptr(wan_client, index)->mac, sizeof(ext_router_mac_addr));
}
else
{
IPACMERR(" wan-client got ipv4 however didn't construct complete ipv4 header \n");
return IPACM_FAILURE;
}
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 v4 default routes are setup before constructing full header */
if(header_partial_default_wan_v4 == true)
{
handle_route_add_evt(IPA_IP_v4, renew);
}
/* checking if the ipv6 same as default route */
if(wan_v6_addr_gw_set)
{
index = get_wan_client_index_ipv6(wan_v6_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)->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);
/* store external_ap's MAC */
memcpy(ext_router_mac_addr, get_client_memptr(wan_client, index)->mac, sizeof(ext_router_mac_addr));
}
else
{
IPACMERR(" wan-client got ipv6 however didn't construct complete ipv4 header \n");
return IPACM_FAILURE;
}
if(get_client_memptr(wan_client, index)->ipv4_header_set)
{
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
{
IPACMERR(" wan-client got ipv4 however didn't construct complete ipv4 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 v6 default routes are setup before constructing full header */
if(header_partial_default_wan_v6 == true)
{
handle_route_add_evt(IPA_IP_v6, renew);
}
return res;
}
/* For checking attribute mask field in firewall rules for IPv6 only */
bool IPACM_Wan::check_dft_firewall_rules_attr_mask(IPACM_firewall_conf_t *firewall_config)
{
uint32_t attrib_mask = 0ul;
attrib_mask = IPA_FLT_SRC_PORT_RANGE |
IPA_FLT_DST_PORT_RANGE |
IPA_FLT_TYPE |
IPA_FLT_CODE |
IPA_FLT_SPI |
IPA_FLT_SRC_PORT |
IPA_FLT_DST_PORT;
for (int i = 0; i < firewall_config->num_extd_firewall_entries; i++)
{
if (firewall_config->extd_firewall_entries[i].ip_vsn == 6)
{
if (firewall_config->extd_firewall_entries[i].attrib.attrib_mask & attrib_mask)
{
IPACMDBG_H("IHL based attribute mask is found: install IPv6 frag firewall rule \n");
return true;
}
}
}
IPACMDBG_H("IHL based attribute mask is not found: no IPv6 frag firewall rule \n");
return false;
}
/* for STA mode: add firewall rules */
int IPACM_Wan::config_dft_firewall_rules(ipa_ip_type iptype)
{
struct ipa_flt_rule_add flt_rule_entry;
int i, rule_v4 = 0, rule_v6 = 0, len;
bool result;
IPACMDBG_H("ip-family: %d; \n", iptype);
if (rx_prop == NULL)
{
IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
/* default firewall is disable and the rule action is drop */
memset(&firewall_config, 0, sizeof(firewall_config));
strlcpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
if(m_is_sta_mode != Q6_MHI_WAN)
{
IPACMDBG_H("Firewall XML file is %s \n", firewall_config.firewall_config_file);
if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
{
IPACMDBG_H("QCMAP Firewall XML read OK \n");
/* find the number of v4/v6 firewall rules */
for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
{
if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
{
rule_v4++;
}
else
{
rule_v6++;
}
}
IPACMDBG_H("firewall rule v4:%d v6:%d total:%d\n", rule_v4, rule_v6, firewall_config.num_extd_firewall_entries);
}
else
{
IPACMERR("QCMAP Firewall XML read failed, no that file, use default configuration \n");
}
}
else
{
IPACMDBG_H("in Q6_MHI_WAN mode, skip firewall, use default configuration \n");
}
/* construct ipa_ioc_add_flt_rule with N firewall rules */
ipa_ioc_add_flt_rule *m_pFilteringTable = NULL;
len = sizeof(struct ipa_ioc_add_flt_rule) + 1 * sizeof(struct ipa_flt_rule_add);
m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
if (!m_pFilteringTable)
{
IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
return IPACM_FAILURE;
}
if(iptype == IPA_IP_v6 &&
firewall_config.firewall_enable == true &&
check_dft_firewall_rules_attr_mask(&firewall_config))
{
m_pFilteringTable->commit = 1;
m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
m_pFilteringTable->global = false;
m_pFilteringTable->ip = IPA_IP_v6;
m_pFilteringTable->num_rules = (uint8_t)1;
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
{
flt_rule_entry.at_rear = false;
flt_rule_entry.rule.hashable = 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(struct ipa_rule_attrib));
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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;
is_ipv6_frag_firewall_flt_rule_installed = true;
IPACMDBG_H("Installed IPv6 frag firewall rule, handle %d.\n", ipv6_frag_firewall_flt_rule_hdl);
}
}
if (iptype == IPA_IP_v4)
{
if (rule_v4 == 0)
{
memset(m_pFilteringTable, 0, len);
m_pFilteringTable->commit = 1;
m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
m_pFilteringTable->global = false;
m_pFilteringTable->ip = IPA_IP_v4;
m_pFilteringTable->num_rules = (uint8_t)1;
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
{
IPACMERR("m_routing.GetRoutingTable(rt_tbl_lan_v4) Failed.\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
/* firewall disable, all traffic are allowed */
if(firewall_config.firewall_enable == 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
{
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;
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;
}
}
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
{
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.hashable = true;
}
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,
sizeof(struct ipa_rule_attrib));
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
/* disble meta-data filtering */
if(m_is_sta_mode == Q6_MHI_WAN)
{
flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
IPACMDBG_H("disable meta-data filtering 0x%x\n", flt_rule_entry.rule.attrib.attrib_mask);
}
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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);
}
/* copy filter hdls */
dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
}
else
{
memset(m_pFilteringTable, 0, len);
m_pFilteringTable->commit = 1;
m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
m_pFilteringTable->global = false;
m_pFilteringTable->ip = IPA_IP_v4;
m_pFilteringTable->num_rules = (uint8_t)1;
IPACMDBG_H("Retreiving Routing handle for routing table name:%s\n",
IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
{
IPACMERR("m_routing.GetRoutingTable(&rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
free(m_pFilteringTable);
return IPACM_FAILURE;
}
IPACMDBG_H("Routing handle for wan routing table:0x%x\n", IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl);
if(firewall_config.firewall_enable == true)
{
rule_v4 = 0;
for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
{
if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
{
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
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)
{
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;
}
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
memcpy(&flt_rule_entry.rule.attrib,
&firewall_config.extd_firewall_entries[i].attrib,
sizeof(struct ipa_rule_attrib));
IPACMDBG_H("rx property attrib mask: 0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
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;
/* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol
== IPACM_FIREWALL_IPPROTO_TCP_UDP)
{
/* insert TCP rule*/
flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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,
m_pFilteringTable->rules[rule_v4].status);
firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
num_firewall_v4++;
rule_v4++;
}
/* insert UDP rule*/
flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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,
m_pFilteringTable->rules[rule_v4].status);
firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
num_firewall_v4++;
rule_v4++;
}
}
else
{
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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,
m_pFilteringTable->rules[rule_v4].status);
firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
num_firewall_v4++;
rule_v4++;
}
}
}
} /* end of firewall ipv4 filter rule add for loop*/
}
/* configure default filter rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
/* firewall disable, all traffic are allowed */
if(firewall_config.firewall_enable == 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
{
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;
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;
}
}
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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,
sizeof(struct ipa_rule_attrib));
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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);
}
/* copy filter hdls */
dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
}
}
else
{
if (rule_v6 == 0)
{
memset(m_pFilteringTable, 0, len);
m_pFilteringTable->commit = 1;
m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
m_pFilteringTable->global = false;
m_pFilteringTable->ip = IPA_IP_v6;
m_pFilteringTable->num_rules = (uint8_t)1;
if(m_is_sta_mode != Q6_MHI_WAN)
{
/* Construct ICMP rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.retain_hdr = 1;
flt_rule_entry.rule.eq_attrib_type = 0;
flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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_ICMP6;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding Filtering rules, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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 */
dft_wan_fl_hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
/* End of construct ICMP rule */
}
else
{
IPACMDBG_H("in Q6_MHI_WAN mode, skip ICMPv6 flt rule \n");
}
/* v6 default route */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v6)) //rt_tbl_wan_v6 rt_tbl_v6
{
IPACMERR("m_routing.GetRoutingTable(rt_tbl_wan_v6) Failed.\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
/* firewall disable, all traffic are allowed */
if(firewall_config.firewall_enable == true)
{
flt_rule_entry.at_rear = true;
/* default action for v6 is PASS_TO_ROUTE 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_ROUTING;
}
}
else
{
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
}
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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_DST_ADDR;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
/* disble meta-data filtering */
if(m_is_sta_mode == Q6_MHI_WAN)
{
flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
IPACMDBG_H("disable meta-data filtering 0x%x\n", flt_rule_entry.rule.attrib.attrib_mask);
}
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding Filtering rules, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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 */
dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
}
else
{
memset(m_pFilteringTable, 0, len);
m_pFilteringTable->commit = 1;
m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
m_pFilteringTable->global = false;
m_pFilteringTable->ip = IPA_IP_v6;
m_pFilteringTable->num_rules = (uint8_t)1;
if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v6))
{
IPACMERR("m_routing.GetRoutingTable(rt_tbl_wan_v6) Failed.\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
if(firewall_config.firewall_enable == true)
{
rule_v6 = 0;
for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
{
if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
{
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
/* matched rules for v6 go PASS_TO_ROUTE */
if(firewall_config.rule_action_accept == true)
{
flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
}
else
{
flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
}
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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,
sizeof(struct ipa_rule_attrib));
flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
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;
/* check if the rule is define as TCP/UDP */
if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
{
/* insert TCP rule*/
flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding Filtering rules, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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;
num_firewall_v6++;
rule_v6++;
}
/* insert UDP rule*/
flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding Filtering rules, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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;
num_firewall_v6++;
rule_v6++;
}
}
else
{
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (false == result)
{
IPACMERR("Error Adding Filtering rules, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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;
num_firewall_v6++;
rule_v6++;
}
}
}
} /* end of firewall ipv6 filter rule add for loop*/
}
/* Construct ICMP rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.retain_hdr = 1;
flt_rule_entry.rule.eq_attrib_type = 0;
flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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_ICMP6;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (result == false)
{
IPACMERR("Error Adding Filtering rules, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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 */
dft_wan_fl_hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
/* End of construct ICMP rule */
/* setup default wan filter rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
/* firewall disable, all traffic are allowed */
if(firewall_config.firewall_enable == true)
{
flt_rule_entry.at_rear = true;
/* default action for v6 is PASS_TO_ROUTE 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_ROUTING;
}
}
else
{
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
}
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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_DST_ADDR;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
/* use index hw-counter */
if(IPACM_Iface::ipacmcfg->hw_fnr_stats_support)
{
IPACMDBG_H("hw-index-enable %d, counter %d\n", IPACM_Iface::ipacmcfg->hw_fnr_stats_support, IPACM_Iface::ipacmcfg->hw_counter_offset + DL_ALL);
result = m_filtering.AddFilteringRule_hw_index(m_pFilteringTable, IPACM_Iface::ipacmcfg->hw_counter_offset+ DL_ALL);
} else {
result = m_filtering.AddFilteringRule(m_pFilteringTable);
}
#else
result = m_filtering.AddFilteringRule(m_pFilteringTable);
#endif
if (result == false)
{
IPACMERR("Error Adding Filtering rules, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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*/
dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
}
}
if(m_pFilteringTable != NULL)
{
free(m_pFilteringTable);
}
return IPACM_SUCCESS;
}
/* configure the initial firewall filter rules */
int IPACM_Wan::config_dft_firewall_rules_ex(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
{
struct ipa_flt_rule_add flt_rule_entry;
int i;
int num_rules = 0, original_num_rules = 0;
ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
ipa_ioc_generate_flt_eq flt_eq;
int pos = rule_offset;
IPACMDBG_H("ip-family: %d; \n", iptype);
if (rx_prop == NULL)
{
IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if(rules == NULL || rule_offset < 0)
{
IPACMERR("No filtering table is available.\n");
return IPACM_FAILURE;
}
/* default firewall is disable and the rule action is drop */
memset(&firewall_config, 0, sizeof(firewall_config));
strlcpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
IPACMDBG_H("Firewall XML file is %s \n", firewall_config.firewall_config_file);
if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
{
IPACMDBG_H("QCMAP Firewall XML read OK \n");
}
else
{
IPACMERR("QCMAP Firewall XML read failed, no that file, use default configuration \n");
}
/* add IPv6 frag rule when firewall is enabled*/
if(iptype == IPA_IP_v6 &&
firewall_config.firewall_enable == true &&
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;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
{
flt_rule_entry.at_rear = false;
flt_rule_entry.rule.hashable = false;
}
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);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
return IPACM_FAILURE;
}
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
IPACMDBG_H("IPv6 frag flt rule uses routing table index %d\n", rt_tbl_idx.idx);
flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
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_FRAGMENT;
change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
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_v6;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
pos++;
IPACM_Wan::num_v6_flt_rule++;
}
if (iptype == IPA_IP_v4)
{
original_num_rules = IPACM_Wan::num_v4_flt_rule;
if(firewall_config.firewall_enable == true)
{
for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
{
if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
{
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
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;
/* 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_ROUTING;
}
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
rt_tbl_idx.ip = iptype;
if(flt_rule_entry.rule.action == IPA_PASS_TO_ROUTING)
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
}
else /*pass to dst nat*/
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, IPA_RESOURCE_NAME_MAX);
}
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
return IPACM_FAILURE;
}
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
memcpy(&flt_rule_entry.rule.attrib,
&firewall_config.extd_firewall_entries[i].attrib,
sizeof(struct ipa_rule_attrib));
flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
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;
change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
/* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol == IPACM_FIREWALL_IPPROTO_TCP_UDP)
{
/* insert TCP rule*/
flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
pos++;
num_firewall_v4++;
IPACM_Wan::num_v4_flt_rule++;
/* insert UDP rule*/
flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
pos++;
num_firewall_v4++;
IPACM_Wan::num_v4_flt_rule++;
}
else
{
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
pos++;
num_firewall_v4++;
IPACM_Wan::num_v4_flt_rule++;
}
}
} /* end of firewall ipv4 filter rule add for loop*/
}
/* configure default filter rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
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;
/* firewall disable, all traffic are allowed */
if(firewall_config.firewall_enable == 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_ROUTING;
}
else
{
flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
}
}
else
{
if(isWan_Bridge_Mode())
{
IPACMDBG_H("ODU is in bridge mode. \n");
flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
}
else
{
flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
}
}
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
rt_tbl_idx.ip = iptype;
if(flt_rule_entry.rule.action == IPA_PASS_TO_ROUTING)
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
}
else /*pass to dst nat*/
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, IPA_RESOURCE_NAME_MAX);
}
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
return IPACM_FAILURE;
}
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
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_DST_ADDR;
flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
pos++;
num_firewall_v4++;
IPACM_Wan::num_v4_flt_rule++;
num_rules = IPACM_Wan::num_v4_flt_rule - original_num_rules - 1;
}
else
{
original_num_rules = IPACM_Wan::num_v6_flt_rule;
if(firewall_config.firewall_enable == true)
{
for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
{
if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
{
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
rt_tbl_idx.ip = iptype;
/* matched rules for v6 go PASS_TO_ROUTE */
if(firewall_config.rule_action_accept == true)
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
}
else
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
}
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
return IPACM_FAILURE;
}
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
memcpy(&flt_rule_entry.rule.attrib,
&firewall_config.extd_firewall_entries[i].attrib,
sizeof(struct ipa_rule_attrib));
flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
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;
change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
/* check if the rule is define as TCP/UDP */
if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
{
/* insert TCP rule*/
flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
pos++;
num_firewall_v6++;
IPACM_Wan::num_v6_flt_rule++;
/* insert UDP rule*/
flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
pos++;
num_firewall_v6++;
IPACM_Wan::num_v6_flt_rule++;
}
else
{
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
pos++;
num_firewall_v6++;
IPACM_Wan::num_v6_flt_rule++;
}
}
} /* end of firewall ipv6 filter rule add for loop*/
}
/* setup default wan filter rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
rt_tbl_idx.ip = iptype;
/* firewall disable, all traffic are allowed */
if(firewall_config.firewall_enable == true)
{
/* default action for v6 is PASS_TO_ROUTE unless user set to exception*/
if(firewall_config.rule_action_accept == true)
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
}
else
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
}
}
else
{
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
}
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
return IPACM_FAILURE;
}
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[1].attrib,
sizeof(struct ipa_rule_attrib));
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
pos++;
num_firewall_v6++;
IPACM_Wan::num_v6_flt_rule++;
num_rules = IPACM_Wan::num_v6_flt_rule - original_num_rules - 1;
}
IPACMDBG_H("Constructed %d firewall rules for ip type %d\n", num_rules, iptype);
return IPACM_SUCCESS;
}
int IPACM_Wan::init_fl_rule_ex(ipa_ip_type iptype)
{
int res = IPACM_SUCCESS;
/* ADD corresponding ipa_rm_resource_name of RX-endpoint before adding all IPV4V6 FT-rules */
IPACMDBG_H(" dun add producer dependency from %s with registered rx-prop\n", dev_name);
if(iptype == IPA_IP_v4)
{
if(modem_ipv4_pdn_index == 0) /* install ipv4 default modem DL filtering rules only once */
{
/* reset the num_v4_flt_rule*/
IPACM_Wan::num_v4_flt_rule = 0;
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 */
{
/* 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
{
IPACMERR("IP type is not expected.\n");
res = IPACM_FAILURE;
goto fail;
}
install_wan_filtering_rule(false);
/* Add Natting iface to IPACM_Config if there is Rx/Tx property */
if (rx_prop != NULL || tx_prop != NULL)
{
IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name, iptype);
}
fail:
return res;
}
int IPACM_Wan::add_icmp_alg_rules(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
{
int res = IPACM_SUCCESS, i, original_num_rules = 0, num_rules = 0;
struct ipa_flt_rule_add flt_rule_entry;
IPACM_Config* ipacm_config = IPACM_Iface::ipacmcfg;
ipa_ioc_generate_flt_eq flt_eq;
ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
if(rules == NULL || rule_offset < 0)
{
IPACMERR("No filtering table is available.\n");
return IPACM_FAILURE;
}
if(iptype == IPA_IP_v4)
{
original_num_rules = IPACM_Wan::num_v4_flt_rule;
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
rt_tbl_idx.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("WAN DL routing table %s has index %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, rt_tbl_idx.idx);
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
/* Configuring ICMP filtering rule */
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
/* Multiple PDNs may exist so keep 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;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACM_Wan::num_v4_flt_rule++;
/* Configure ALG filtering rules */
/* maintain meta data 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_SRC_PORT;
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
for(i = 0; i < ipacm_config->ipa_num_alg_ports; i++)
{
flt_rule_entry.rule.attrib.src_port = ipacm_config->alg_table[i].port;
flt_rule_entry.rule.attrib.u.v4.protocol = ipacm_config->alg_table[i].protocol;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset + 1 + i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACM_Wan::num_v4_flt_rule++;
}
/* maintain meta data 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_DST_PORT;
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
for(i = 0; i < ipacm_config->ipa_num_alg_ports; i++)
{
flt_rule_entry.rule.attrib.dst_port = ipacm_config->alg_table[i].port;
flt_rule_entry.rule.attrib.u.v4.protocol = ipacm_config->alg_table[i].protocol;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset + ipacm_config->ipa_num_alg_ports + 1 + i]),
&flt_rule_entry,
sizeof(struct ipa_flt_rule_add));
IPACM_Wan::num_v4_flt_rule++;
}
num_rules = IPACM_Wan::num_v4_flt_rule - original_num_rules;
}
else /* IPv6 case */
{
original_num_rules = IPACM_Wan::num_v6_flt_rule;
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
rt_tbl_idx.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("WAN DL routing table %s has index %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, rt_tbl_idx.idx);
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
/* Configuring ICMP filtering rule */
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[1].attrib,
sizeof(flt_rule_entry.rule.attrib));
/* Multiple PDNs may exist so keep 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;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACM_Wan::num_v6_flt_rule++;
num_rules = IPACM_Wan::num_v6_flt_rule - original_num_rules;
}
fail:
IPACMDBG_H("Constructed %d ICMP/ALG rules for ip type %d\n", num_rules, iptype);
return res;
}
int IPACM_Wan::query_ext_prop()
{
int fd, ret = IPACM_SUCCESS;
uint32_t cnt;
if (iface_query->num_ext_props > 0)
{
fd = open(IPA_DEVICE_NAME, O_RDWR);
IPACMDBG_H("iface query-property \n");
if (0 == fd)
{
IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
return IPACM_FAILURE;
}
ext_prop = (struct ipa_ioc_query_intf_ext_props *)
calloc(1, sizeof(struct ipa_ioc_query_intf_ext_props) +
iface_query->num_ext_props * sizeof(struct ipa_ioc_ext_intf_prop));
if(ext_prop == NULL)
{
IPACMERR("Unable to allocate memory.\n");
return IPACM_FAILURE;
}
memcpy(ext_prop->name, dev_name,
sizeof(dev_name));
ext_prop->num_ext_props = iface_query->num_ext_props;
IPACMDBG_H("Query extended property for iface %s\n", ext_prop->name);
ret = ioctl(fd, IPA_IOC_QUERY_INTF_EXT_PROPS, ext_prop);
if (ret < 0)
{
IPACMERR("ioctl IPA_IOC_QUERY_INTF_EXT_PROPS failed\n");
/* ext_prop memory will free when iface-down*/
free(ext_prop);
close(fd);
return ret;
}
IPACMDBG_H("Wan interface has %d tx props, %d rx props and %d ext props\n",
iface_query->num_tx_props, iface_query->num_rx_props, iface_query->num_ext_props);
for (cnt = 0; cnt < ext_prop->num_ext_props; cnt++)
{
if (!IPACM_Iface::ipacmcfg->isIPAv3Supported())
{
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 /* 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);
}
}
if(IPACM_Wan::is_ext_prop_set == false)
{
IPACM_Iface::ipacmcfg->SetExtProp(ext_prop);
IPACM_Wan::is_ext_prop_set = true;
}
close(fd);
}
return IPACM_SUCCESS;
}
int IPACM_Wan::config_wan_firewall_rule(ipa_ip_type iptype)
{
int res = IPACM_SUCCESS;
IPACMDBG_H("Configure WAN DL firewall rules.\n");
if(iptype == IPA_IP_v4)
{
IPACM_Wan::num_v4_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
if(IPACM_FAILURE == add_icmp_alg_rules(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4))
{
IPACMERR("Failed to add ICMP and ALG port filtering rules.\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Succeded in constructing ICMP/ALG rules for ip type %d\n", iptype);
if(IPACM_FAILURE == config_dft_firewall_rules_ex(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4))
{
IPACMERR("Failed to add firewall filtering rules.\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Succeded in constructing firewall rules for ip type %d\n", iptype);
}
else if(iptype == IPA_IP_v6)
{
IPACM_Wan::num_v6_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6;
if(IPACM_FAILURE == add_icmp_alg_rules(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6))
{
IPACMERR("Failed to add ICMP and ALG port filtering rules.\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Succeded in constructing ICMP/ALG rules for ip type %d\n", iptype);
if(IPACM_FAILURE == config_dft_firewall_rules_ex(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6))
{
IPACMERR("Failed to add firewall filtering rules.\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Succeded in constructing firewall rules for ip type %d\n", iptype);
}
else
{
IPACMERR("IP type is not expected.\n");
return IPACM_FAILURE;
}
fail:
return res;
}
int IPACM_Wan::add_dft_filtering_rule(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
{
struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
struct ipa_flt_rule_add flt_rule_entry;
struct ipa_ioc_generate_flt_eq flt_eq;
int res = IPACM_SUCCESS;
if(rules == NULL)
{
IPACMERR("No filtering table available.\n");
return IPACM_FAILURE;
}
if(rx_prop == NULL)
{
IPACMERR("No tx property.\n");
return IPACM_FAILURE;
}
if (iptype == IPA_IP_v4)
{
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
rt_tbl_idx.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
IPACMDBG_H("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
/* Configuring Multicast Filtering Rule */
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
/* remove meta data mask since we only install default flt rules once for all modem PDN*/
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.v4.dst_addr_mask = 0xF0000000;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000;
change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* Configuring Broadcast Filtering Rule */
flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF;
change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset + 1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACM_Wan::num_v4_flt_rule += IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
IPACMDBG_H("Constructed %d default filtering rules for ip type %d\n", IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4, iptype);
}
else /*insert rules for ipv6*/
{
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
rt_tbl_idx.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
/* Configuring Multicast Filtering Rule */
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
/* remove meta data mask since we only install default flt rules once for all modem PDN*/
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_mask[0] = 0xFF000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFF000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* Configuring fe80::/10 Link-Scoped Unicast Filtering Rule */
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFC00000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFE800000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset + 1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* Configuring fec0::/10 Reserved by IETF Filtering Rule */
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFC00000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFEC00000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset + 2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* Configuring fragment Filtering Rule */
flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_DST_ADDR);
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
memset(&flt_eq, 0, sizeof(flt_eq));
memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
flt_eq.ip = iptype;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(rules[rule_offset + 3]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef FEATURE_IPA_ANDROID
IPACM_Wan::num_v6_flt_rule += IPA_V2_NUM_MULTICAST_WAN_FILTER_RULE_IPV6;
IPACMDBG_H("Constructed %d default filtering rules for ip type %d\n", IPA_V2_NUM_MULTICAST_WAN_FILTER_RULE_IPV6, iptype);
#else
IPACM_Wan::num_v6_flt_rule += IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6;
IPACMDBG_H("Constructed %d default filtering rules for ip type %d\n",
IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6, iptype);
#endif
IPACM_Wan::num_v6_flt_rule += IPA_V2_NUM_FRAG_WAN_FILTER_RULE_IPV6;
IPACMDBG_H("Constructed %d default filtering rules for ip type %d\n",
IPA_V2_NUM_FRAG_WAN_FILTER_RULE_IPV6, iptype);
}
fail:
return res;
}
int IPACM_Wan::del_wan_firewall_rule(ipa_ip_type iptype)
{
if(iptype == IPA_IP_v4)
{
IPACM_Wan::num_v4_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
memset(&IPACM_Wan::flt_rule_v4[IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4], 0,
(IPA_MAX_FLT_RULE - IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4) * sizeof(struct ipa_flt_rule_add));
}
else if(iptype == IPA_IP_v6)
{
IPACM_Wan::num_v6_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6;
memset(&IPACM_Wan::flt_rule_v6[IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6], 0,
(IPA_MAX_FLT_RULE - IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6) * sizeof(struct ipa_flt_rule_add));
}
else
{
IPACMERR("IP type is not expected.\n");
return IPACM_FAILURE;
}
return IPACM_SUCCESS;
}
/*for STA mode: clean firewall filter rules */
int IPACM_Wan::del_dft_firewall_rules(ipa_ip_type iptype)
{
/* free v4 firewall filter rule */
if (rx_prop == NULL)
{
IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if ((iptype == IPA_IP_v4) && (active_v4 == true))
{
if (num_firewall_v4 > IPACM_MAX_FIREWALL_ENTRIES)
{
IPACMERR("the number of v4 firewall entries overflow, aborting...\n");
return IPACM_FAILURE;
}
if (num_firewall_v4 != 0)
{
if (m_filtering.DeleteFilteringHdls(firewall_hdl_v4,
IPA_IP_v4, num_firewall_v4) == false)
{
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
{
IPACMDBG_H("No ipv4 firewall rules, no need deleted\n");
}
if (m_filtering.DeleteFilteringHdls(dft_wan_fl_hdl,
IPA_IP_v4, 1) == false)
{
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;
}
/* free v6 firewall filter rule */
if ((iptype == IPA_IP_v6) && (active_v6 == true))
{
if (num_firewall_v6 > IPACM_MAX_FIREWALL_ENTRIES)
{
IPACMERR("the number of v6 firewall entries overflow, aborting...\n");
return IPACM_FAILURE;
}
if (num_firewall_v6 != 0)
{
if (m_filtering.DeleteFilteringHdls(firewall_hdl_v6,
IPA_IP_v6, num_firewall_v6) == false)
{
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
{
IPACMDBG_H("No ipv6 firewall rules, no need deleted\n");
}
if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[1],
IPA_IP_v6, 1) == false)
{
IPACMERR("Error Deleting Filtering rules, aborting...\n");
return IPACM_FAILURE;
}
if(m_is_sta_mode != Q6_MHI_WAN)
{
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);
}
else
{
IPACMDBG_H("in Q6_MHI_WAN mode, skip ICMPv6 flt rule deletion\n");
}
if (is_ipv6_frag_firewall_flt_rule_installed &&
check_dft_firewall_rules_attr_mask(&firewall_config))
{
if (m_filtering.DeleteFilteringHdls(&ipv6_frag_firewall_flt_rule_hdl, IPA_IP_v6, 1) == false)
{
IPACMERR("Error deleting IPv6 frag filtering rules.\n");
return IPACM_FAILURE;
}
is_ipv6_frag_firewall_flt_rule_installed = false;
IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
}
num_firewall_v6 = 0;
}
return IPACM_SUCCESS;
}
/* for STA mode: wan default route/filter rule delete */
int IPACM_Wan::handle_route_del_evt(ipa_ip_type iptype, bool delete_only)
{
uint32_t tx_index;
ipacm_cmd_q_data evt_data;
#ifdef WAN_IOC_NOTIFY_WAN_STATE
struct wan_ioctl_notify_wan_state wan_state;
int fd_wwan_ioctl;
memset(&wan_state, 0, sizeof(wan_state));
#endif
int ret = IPACM_SUCCESS;
IPACMDBG_H("got handle_route_del_evt for STA-mode with ip-family:%d \n", iptype);
if(tx_prop == NULL)
{
IPACMDBG_H("No tx properties, ignore delete default route setting\n");
return IPACM_SUCCESS;
}
is_default_gateway = false;
IPACMDBG_H("Default route is deleted to iface %s.\n", dev_name);
if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
((iptype == IPA_IP_v6) && (active_v6 == true)))
{
if (!delete_only)
{
if(IPACM_Iface::ipacmcfg->GetIPAVer() >= IPA_HW_None && IPACM_Iface::ipacmcfg->GetIPAVer() < IPA_HW_v4_0)
{
/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
IPACMDBG_H("dev %s delete 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->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
}
else
{
/* change wan_state for Q6_MHI */
#ifdef WAN_IOC_NOTIFY_WAN_STATE
IPACMDBG_H("ipa_pm_q6_check to %d\n", ipa_pm_q6_check);
if(ipa_pm_q6_check == 1 && m_is_sta_mode == Q6_MHI_WAN)
{
fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
if(fd_wwan_ioctl < 0)
{
IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
return false;
}
IPACMDBG_H("send WAN_IOC_NOTIFY_WAN_STATE down to IPA_PM\n");
if(ioctl(fd_wwan_ioctl, WAN_IOC_NOTIFY_WAN_STATE, &wan_state))
{
IPACMERR("Failed to send WAN_IOC_NOTIFY_WAN_STATE as up %d\n ", wan_state.up);
}
close(fd_wwan_ioctl);
}
if (ipa_pm_q6_check > 0)
ipa_pm_q6_check--;
else
IPACMERR(" ipa_pm_q6_check becomes negative !!!\n");
#endif
}
} // end of delete_only
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 deleted\n",
tx_index, tx_prop->tx[tx_index].ip,iptype);
continue;
}
if (iptype == IPA_IP_v4)
{
IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n", tx_index, tx_prop->tx[tx_index].ip,iptype);
if (m_routing.DeleteRoutingHdl(wan_route_rule_v4_hdl[tx_index], IPA_IP_v4) == false)
{
IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v4, wan_route_rule_v4_hdl[tx_index], tx_index);
return IPACM_FAILURE;
}
}
else
{
IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n", tx_index, tx_prop->tx[tx_index].ip,iptype);
if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl[tx_index], IPA_IP_v6) == false)
{
IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v6, wan_route_rule_v6_hdl[tx_index], tx_index);
return IPACM_FAILURE;
}
}
}
/* Delete the default wan route*/
if (iptype == IPA_IP_v6 && m_is_sta_mode != Q6_MHI_WAN)
{
IPACMDBG_H("ip-type %d: default v6 wan RT-rule deleted\n",iptype);
if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl_a5[0], IPA_IP_v6) == false)
{
IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed!\n",IPA_IP_v6,wan_route_rule_v6_hdl_a5[0]);
return IPACM_FAILURE;
}
}
/* support delete only, not post wan_down event */
if(delete_only)
{
IPACMDBG_H(" Only delete default WAN routing rules (%d)\n", delete_only);
return IPACM_SUCCESS;
}
ipacm_event_iface_up *wandown_data;
wandown_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
if (wandown_data == NULL)
{
IPACMERR("Unable to allocate memory\n");
return IPACM_FAILURE;
}
memset(wandown_data, 0, sizeof(ipacm_event_iface_up));
if (iptype == IPA_IP_v4)
{
wandown_data->ipv4_addr = wan_v4_addr;
wandown_data->backhaul_type = m_is_sta_mode;
evt_data.event = IPA_HANDLE_WAN_DOWN;
evt_data.evt_data = (void *)wandown_data;
/* Insert IPA_HANDLE_WAN_DOWN to command queue */
IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN for IPv4 (%d.%d.%d.%d) \n",
(unsigned char)(wandown_data->ipv4_addr),
(unsigned char)(wandown_data->ipv4_addr >> 8),
(unsigned char)(wandown_data->ipv4_addr >> 16),
(unsigned char)(wandown_data->ipv4_addr >> 24));
IPACM_EvtDispatcher::PostEvt(&evt_data);
IPACMDBG_H("setup wan_up/active_v4= false \n");
IPACM_Wan::wan_up = false;
active_v4 = false;
if(IPACM_Wan::wan_up_v6)
{
IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
}
else
{
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");
ret = IPACM_FAILURE;
}
/* Delete tcp_fin_rst rule */
if(delete_tcp_fin_rst_exception_rule())
{
IPACMERR("Failed to delete tcp_fin_rst rule \n");
ret = IPACM_FAILURE;
}
return ret;
}
else
{
wandown_data->backhaul_type = m_is_sta_mode;
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_H("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_H("setup wan_up_v6/active_v6= false \n");
IPACM_Wan::wan_up_v6 = false;
active_v6 = false;
if(IPACM_Wan::wan_up)
{
IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
}
else
{
memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
}
/* Delete MHI icmpv6 exception rule */
if(delete_icmpv6_exception_rule())
{
IPACMERR("Failed to delete icmpv6 rule \n");
return IPACM_FAILURE;
}
}
}
else
{
IPACMDBG_H(" The default WAN routing rules are deleted already \n");
}
return IPACM_SUCCESS;
}
int IPACM_Wan::handle_route_del_evt_ex(ipa_ip_type iptype)
{
ipacm_cmd_q_data evt_data;
#ifdef WAN_IOC_NOTIFY_WAN_STATE
struct wan_ioctl_notify_wan_state wan_state;
int fd_wwan_ioctl;
memset(&wan_state, 0, sizeof(wan_state));
#endif
IPACMDBG_H("got handle_route_del_evt_ex with ip-family:%d \n", iptype);
if(tx_prop == NULL)
{
IPACMDBG_H("No tx properties, ignore delete default route setting\n");
return IPACM_SUCCESS;
}
is_default_gateway = false;
IPACMDBG_H("Default route is deleted to iface %s.\n", dev_name);
if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
((iptype == IPA_IP_v6) && (active_v6 == true)))
{
if(IPACM_Iface::ipacmcfg->GetIPAVer() >= IPA_HW_None && IPACM_Iface::ipacmcfg->GetIPAVer() < IPA_HW_v4_0)
{
/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
IPACMDBG_H("dev %s delete 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->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
}
#ifdef WAN_IOC_NOTIFY_WAN_STATE
else {
IPACMDBG_H("ipa_pm_q6_check to %d\n", ipa_pm_q6_check);
if(ipa_pm_q6_check == 1)
{
fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
if(fd_wwan_ioctl < 0)
{
IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
return false;
}
IPACMDBG_H("send WAN_IOC_NOTIFY_WAN_STATE down to IPA_PM\n");
#ifdef WAN_IOCTL_NOTIFY_WAN_INTF_NAME
strlcpy(wan_state.upstreamIface, dev_name, IFNAMSIZ);
#endif
if(ioctl(fd_wwan_ioctl, WAN_IOC_NOTIFY_WAN_STATE, &wan_state))
{
IPACMERR("Failed to send WAN_IOC_NOTIFY_WAN_STATE as up %d\n ", wan_state.up);
}
close(fd_wwan_ioctl);
}
if (ipa_pm_q6_check > 0)
ipa_pm_q6_check--;
else
IPACMERR(" ipa_pm_q6_check becomes negative !!!\n");
}
#endif
/* Delete the default route*/
if (iptype == IPA_IP_v6)
{
IPACMDBG_H("ip-type %d: default v6 wan RT-rule deleted\n",iptype);
if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl_a5[0], IPA_IP_v6) == false)
{
IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed!\n",IPA_IP_v6,wan_route_rule_v6_hdl_a5[0]);
return IPACM_FAILURE;
}
}
ipacm_event_iface_up *wandown_data;
wandown_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
if (wandown_data == NULL)
{
IPACMERR("Unable to allocate memory\n");
return IPACM_FAILURE;
}
memset(wandown_data, 0, sizeof(ipacm_event_iface_up));
if (iptype == IPA_IP_v4)
{
wandown_data->ipv4_addr = wan_v4_addr;
wandown_data->backhaul_type = m_is_sta_mode;
evt_data.event = IPA_HANDLE_WAN_DOWN;
evt_data.evt_data = (void *)wandown_data;
/* Insert IPA_HANDLE_WAN_DOWN to command queue */
IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN for IPv4 with address: 0x%x\n", wan_v4_addr);
IPACM_EvtDispatcher::PostEvt(&evt_data);
IPACMDBG_H("setup wan_up/active_v4= false \n");
IPACM_Wan::wan_up = false;
active_v4 = false;
if(IPACM_Wan::wan_up_v6)
{
IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
}
else
{
memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
}
}
else
{
wandown_data->backhaul_type = m_is_sta_mode;
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_H("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_H("setup wan_up_v6/active_v6= false \n");
IPACM_Wan::wan_up_v6 = false;
active_v6 = false;
if(IPACM_Wan::wan_up)
{
IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
}
else
{
memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
}
}
}
else
{
IPACMDBG_H(" The default WAN routing rules are deleted already \n");
}
return IPACM_SUCCESS;
}
/* configure the initial embms filter rules */
int IPACM_Wan::config_dft_embms_rules(ipa_ioc_add_flt_rule *pFilteringTable_v4, ipa_ioc_add_flt_rule *pFilteringTable_v6)
{
struct ipa_flt_rule_add flt_rule_entry;
struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
struct ipa_ioc_generate_flt_eq flt_eq;
if (rx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if(pFilteringTable_v4 == NULL || pFilteringTable_v6 == NULL)
{
IPACMERR("Either v4 or v6 filtering table is empty.\n");
return IPACM_FAILURE;
}
/* set up ipv4 odu rule*/
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
/* get eMBMS ODU tbl index*/
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v4.name, IPA_RESOURCE_NAME_MAX);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
rt_tbl_idx.ip = IPA_IP_v4;
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
return IPACM_FAILURE;
}
IPACMDBG_H("Odu routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.at_rear = false;
flt_rule_entry.rule.retain_hdr = 0;
flt_rule_entry.rule.to_uc = 0;
flt_rule_entry.rule.eq_attrib_type = 1;
flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
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_DST_ADDR;
flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
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;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(pFilteringTable_v4->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* construc v6 rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
/* get eMBMS ODU tbl*/
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v6.name, IPA_RESOURCE_NAME_MAX);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
rt_tbl_idx.ip = IPA_IP_v6;
if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
{
IPACMERR("Failed to get routing table index from name\n");
return IPACM_FAILURE;
}
IPACMDBG_H("Odu routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.at_rear = false;
flt_rule_entry.rule.retain_hdr = 0;
flt_rule_entry.rule.to_uc = 0;
flt_rule_entry.rule.eq_attrib_type = 1;
flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
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_DST_ADDR;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
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_v6;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
return IPACM_FAILURE;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(pFilteringTable_v6->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
return IPACM_SUCCESS;
}
/*for STA mode: handle wan-iface down event */
int IPACM_Wan::handle_down_evt()
{
int res = IPACM_SUCCESS;
uint32_t i, tether_total;
int ipa_if_num_tether_tmp[IPA_MAX_IFACE_ENTRIES];
tether_total = 0;
memset(ipa_if_num_tether_tmp, 0, IPA_MAX_IFACE_ENTRIES);
IPACMDBG_H(" wan handle_down_evt \n");
if(IPACM_Iface::ipacmcfg->GetIPAVer() >= IPA_HW_None && IPACM_Iface::ipacmcfg->GetIPAVer() < IPA_HW_v4_0)
{
/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
IPACMDBG_H("dev %s delete producer dependency\n", dev_name);
if (tx_prop != NULL)
{
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->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
}
}
/* no iface address up, directly close iface*/
if (ip_type == IPACM_IP_NULL)
{
goto fail;
}
/* make sure default routing rules and firewall rules are deleted*/
if (active_v4)
{
if (rx_prop != NULL)
{
del_dft_firewall_rules(IPA_IP_v4);
}
handle_route_del_evt(IPA_IP_v4);
IPACMDBG_H("Delete default v4 routing rules\n");
#ifdef FEATURE_IPA_ANDROID
/* posting wan_down_tether for lan clients */
#ifdef FEATURE_IPACM_HAL
IPACMDBG_H("Posting IPA_WAN_DOWN_TETHER_EVENT for IPV4\n");
post_wan_down_tether_evt(IPA_IP_v4, 0);
#else
for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
{
ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v4[i];
}
tether_total = IPACM_Wan::ipa_if_num_tether_v4_total;
for (i=0; i < tether_total; i++)
{
post_wan_down_tether_evt(IPA_IP_v4, ipa_if_num_tether_tmp[i]);
IPACMDBG_H("post_wan_down_tether_v4 iface(%d: %s)\n",
i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
}
#endif
#endif
}
if (active_v6)
{
if (rx_prop != NULL)
{
del_dft_firewall_rules(IPA_IP_v6);
}
handle_route_del_evt(IPA_IP_v6);
IPACMDBG_H("Delete default v6 routing rules\n");
#ifdef FEATURE_IPA_ANDROID
/* posting wan_down_tether for lan clients */
#ifdef FEATURE_IPACM_HAL
IPACMDBG_H("Posting IPA_WAN_DOWN_TETHER_EVENT for IPV6\n");
post_wan_down_tether_evt(IPA_IP_v6, 0);
#else
for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
{
ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v6[i];
}
tether_total = IPACM_Wan::ipa_if_num_tether_v6_total;
for (i=0; i < tether_total; i++)
{
post_wan_down_tether_evt(IPA_IP_v6, ipa_if_num_tether_tmp[i]);
IPACMDBG_H("post_wan_down_tether_v6 iface(%d: %s)\n",
i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
}
#endif
#endif
}
/* Delete default v4 RT rule */
if (ip_type != IPA_IP_v6 && wan_v4_addr_set)
{
/* no need delete v4 RSC routing rules */
IPACMDBG_H("Delete default v4 routing rules\n");
if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
{
IPACMERR("Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
}
/* delete default v6 RT rule */
if (ip_type != IPA_IP_v4)
{
IPACMDBG_H("Delete default v6 routing rules\n");
/* May have multiple ipv6 iface-routing rules*/
for (i = 0; i < 2*num_dft_rt_v6; i++)
{
if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
{
IPACMERR("Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
}
IPACMDBG_H("finished delete default v6 RT rules\n ");
}
/* check software routing fl rule hdl */
if (softwarerouting_act == true)
{
if(m_is_sta_mode == Q6_MHI_WAN)
{
handle_software_routing_disable(true);
}
else
{
handle_software_routing_disable(false);
}
}
if(m_is_sta_mode != Q6_MHI_WAN)
{
/* clean wan-client header, routing rules */
IPACMDBG_H("left %d wan clients need to be deleted \n ", num_wan_client);
for (i = 0; i < num_wan_client; i++)
{
/* Del NAT rules before ipv4 RT rules are delete */
if(get_client_memptr(wan_client, i)->ipv4_set == true)
{
IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wan_client, i)->v4_addr);
CtList->HandleSTAClientDelEvt(get_client_memptr(wan_client, i)->v4_addr);
}
if (delete_wan_rtrules(i, IPA_IP_v4))
{
IPACMERR("unbale to delete wan-client v4 route rules for index %d\n", i);
res = IPACM_FAILURE;
goto fail;
}
if (delete_wan_rtrules(i, IPA_IP_v6))
{
IPACMERR("unbale to delete ecm-client v6 route rules for index %d\n", i);
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Delete %d client header\n", num_wan_client);
if(get_client_memptr(wan_client, i)->ipv4_header_set == true)
{
if (m_header.DeleteHeaderHdl(get_client_memptr(wan_client, i)->hdr_hdl_v4)
== false)
{
res = IPACM_FAILURE;
goto fail;
}
}
if(get_client_memptr(wan_client, i)->ipv6_header_set == true)
{
if (m_header.DeleteHeaderHdl(get_client_memptr(wan_client, i)->hdr_hdl_v6)
== false)
{
res = IPACM_FAILURE;
goto fail;
}
}
} /* end of for loop */
/* free the edm clients cache */
IPACMDBG_H("Free wan clients cache\n");
/* free dft ipv4 filter rule handlers if any */
if (ip_type != IPA_IP_v6 && rx_prop != NULL)
{
if (dft_v4fl_rule_hdl[0] != 0)
{
if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
IPA_IP_v4,
IPV4_DEFAULT_FILTERTING_RULES) == false)
{
IPACMERR("Error Delete Filtering rules, aborting...\n");
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 ");
}
}
/* free dft ipv6 filter rule handlers if any */
if (ip_type != IPA_IP_v4 && rx_prop != NULL)
{
if (dft_v6fl_rule_hdl[0] != 0)
{
if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
IPA_IP_v6,
IPV6_DEFAULT_FILTERTING_RULES) == false)
{
IPACMERR("ErrorDeleting Filtering rule, aborting...\n");
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)
{
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;
}
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 ");
}
if(hdr_proc_hdl_dummy_v6)
{
if(m_header.DeleteHeaderProcCtx(hdr_proc_hdl_dummy_v6) == false)
{
IPACMERR("Failed to delete hdr_proc_hdl_dummy_v6\n");
res = IPACM_FAILURE;
goto fail;
}
}
if(hdr_hdl_dummy_v6)
{
if (m_header.DeleteHeaderHdl(hdr_hdl_dummy_v6) == false)
{
IPACMERR("Failed to delete hdr_hdl_dummy_v6\n");
res = IPACM_FAILURE;
goto fail;
}
}
}
fail:
if (tx_prop != NULL)
{
free(tx_prop);
}
if (rx_prop != NULL)
{
free(rx_prop);
}
if (iface_query != NULL)
{
free(iface_query);
}
if (wan_route_rule_v4_hdl != NULL)
{
free(wan_route_rule_v4_hdl);
}
if (wan_route_rule_v6_hdl != NULL)
{
free(wan_route_rule_v6_hdl);
}
if (wan_route_rule_v6_hdl_a5 != NULL)
{
free(wan_route_rule_v6_hdl_a5);
}
if (wan_client != NULL)
{
free(wan_client);
}
close(m_fd_ipa);
return res;
}
int IPACM_Wan::handle_down_evt_ex()
{
int res = IPACM_SUCCESS;
uint32_t i;
#ifndef FEATURE_IPACM_HAL
uint32_t tether_total;
int ipa_if_num_tether_tmp[IPA_MAX_IFACE_ENTRIES];
#endif
IPACMDBG_H(" wan handle_down_evt \n");
/* free ODU filter rule handlers */
if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == EMBMS_IF)
{
embms_is_on = false;
if(IPACM_Iface::ipacmcfg->GetIPAVer() >= IPA_HW_None && IPACM_Iface::ipacmcfg->GetIPAVer() < IPA_HW_v4_0)
{
/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
IPACMDBG_H("dev %s delete producer dependency\n", dev_name);
if (tx_prop != NULL)
{
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->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
}
}
if (rx_prop != NULL)
{
install_wan_filtering_rule(false);
IPACMDBG("finished delete embms filtering rule\n ");
}
goto fail;
}
/* no iface address up, directly close iface*/
if (ip_type == IPACM_IP_NULL)
{
goto fail;
}
#ifndef IPA_MTU_EVENT_MAX
/* reset the mtu size */
mtu_v4 = DEFAULT_MTU_SIZE;
mtu_v4_set = false;
mtu_v6 = DEFAULT_MTU_SIZE;
mtu_v6_set = false;
#endif
if(ip_type == IPA_IP_v4)
{
num_ipv4_modem_pdn--;
IPACMDBG_H("Now the number of ipv4 modem pdn is %d.\n", num_ipv4_modem_pdn);
/* only when default gw goes down we post WAN_DOWN event*/
if(is_default_gateway == true)
{
IPACM_Wan::wan_up = false;
del_wan_firewall_rule(IPA_IP_v4);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v4);
#ifdef FEATURE_IPA_ANDROID
/* posting wan_down_tether for all lan clients */
#ifdef FEATURE_IPACM_HAL
post_wan_down_tether_evt(IPA_IP_v4, 0);
#else
for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
{
ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v4[i];
}
tether_total = IPACM_Wan::ipa_if_num_tether_v4_total;
for (i=0; i < tether_total; i++)
{
post_wan_down_tether_evt(IPA_IP_v4, ipa_if_num_tether_tmp[i]);
IPACMDBG_H("post_wan_down_tether_v4 iface(%d: %s)\n",
i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
}
#endif
#endif
if(IPACM_Wan::wan_up_v6)
{
IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
}
else
{
memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
}
}
/* only when the last ipv4 modem interface goes down, delete ipv4 default flt rules*/
if(num_ipv4_modem_pdn == 0)
{
IPACMDBG_H("Now the number of modem ipv4 interface is 0, delete default flt rules.\n");
IPACM_Wan::num_v4_flt_rule = 0;
memset(IPACM_Wan::flt_rule_v4, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
install_wan_filtering_rule(false);
}
IPACMDBG_H("Delete default v4 coalesce routing rules\n");
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[0], IPA_IP_v4) == false)
{
IPACMERR("Routing rule RSC TCP deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[1], IPA_IP_v4) == false)
{
IPACMERR("Routing rule RSB UDP deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
{
IPACMERR("Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
}
else if(ip_type == IPA_IP_v6)
{
if (num_dft_rt_v6 > 1)
num_ipv6_modem_pdn--;
IPACMDBG_H("Now the number of ipv6 modem pdn is %d.\n", num_ipv6_modem_pdn);
/* only when default gw goes down we post WAN_DOWN event*/
if(is_default_gateway == true)
{
IPACM_Wan::wan_up_v6 = false;
del_wan_firewall_rule(IPA_IP_v6);
install_wan_filtering_rule(false);
handle_route_del_evt_ex(IPA_IP_v6);
#ifdef FEATURE_IPA_ANDROID
/* posting wan_down_tether for all lan clients */
#ifdef FEATURE_IPACM_HAL
post_wan_down_tether_evt(IPA_IP_v6, 0);
#else
for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
{
ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v6[i];
}
tether_total = IPACM_Wan::ipa_if_num_tether_v6_total;
for (i=0; i < tether_total; i++)
{
post_wan_down_tether_evt(IPA_IP_v6, ipa_if_num_tether_tmp[i]);
IPACMDBG_H("post_wan_down_tether_v6 iface(%d: %s)\n",
i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
}
#endif
#endif
if(IPACM_Wan::wan_up)
{
IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
}
else
{
memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
}
}
/* only when the last ipv6 modem interface goes down, delete ipv6 default flt rules*/
if(num_ipv6_modem_pdn == 0)
{
IPACMDBG_H("Now the number of modem ipv6 interface is 0, delete default flt rules.\n");
IPACM_Wan::num_v6_flt_rule = 0;
memset(IPACM_Wan::flt_rule_v6, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
install_wan_filtering_rule(false);
}
for (i = 0; i < 2*num_dft_rt_v6; i++)
{
/* delete v6 colasce rules */
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
{
IPACMERR("Colasce Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
{
IPACMERR("Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
}
}
else
{
num_ipv4_modem_pdn--;
IPACMDBG_H("Now the number of ipv4 modem pdn is %d.\n", num_ipv4_modem_pdn);
if (num_dft_rt_v6 > 1)
num_ipv6_modem_pdn--;
IPACMDBG_H("Now the number of ipv6 modem pdn is %d.\n", num_ipv6_modem_pdn);
/* only when default gw goes down we post WAN_DOWN event*/
if(is_default_gateway == true)
{
IPACM_Wan::wan_up = false;
del_wan_firewall_rule(IPA_IP_v4);
handle_route_del_evt_ex(IPA_IP_v4);
#ifdef FEATURE_IPA_ANDROID
/* posting wan_down_tether for all lan clients */
#ifdef FEATURE_IPACM_HAL
IPACMDBG_H("Posting IPA_WAN_DOWN_TETHER_EVENT for IPV4\n");
post_wan_down_tether_evt(IPA_IP_v4, 0);
#else
for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
{
ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v4[i];
}
tether_total = IPACM_Wan::ipa_if_num_tether_v4_total;
for (i=0; i < tether_total; i++)
{
post_wan_down_tether_evt(IPA_IP_v4, ipa_if_num_tether_tmp[i]);
IPACMDBG_H("post_wan_down_tether_v4 iface(%d: %s)\n",
i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
}
#endif
#endif
IPACM_Wan::wan_up_v6 = false;
del_wan_firewall_rule(IPA_IP_v6);
handle_route_del_evt_ex(IPA_IP_v6);
#ifdef FEATURE_IPA_ANDROID
/* posting wan_down_tether for all lan clients */
#ifdef FEATURE_IPACM_HAL
IPACMDBG_H("Posting IPA_WAN_DOWN_TETHER_EVENT for IPV6\n");
post_wan_down_tether_evt(IPA_IP_v6, 0);
#else
for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
{
ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v6[i];
}
tether_total = IPACM_Wan::ipa_if_num_tether_v6_total;
for (i=0; i < tether_total; i++)
{
post_wan_down_tether_evt(IPA_IP_v6, ipa_if_num_tether_tmp[i]);
IPACMDBG_H("post_wan_down_tether_v6 iface(%d: %s)\n",
i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
}
#endif
#endif
memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
install_wan_filtering_rule(false);
}
/* only when the last ipv4 modem interface goes down, delete ipv4 default flt rules*/
if(num_ipv4_modem_pdn == 0)
{
IPACMDBG_H("Now the number of modem ipv4 interface is 0, delete default flt rules.\n");
IPACM_Wan::num_v4_flt_rule = 0;
memset(IPACM_Wan::flt_rule_v4, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
install_wan_filtering_rule(false);
}
/* only when the last ipv6 modem interface goes down, delete ipv6 default flt rules*/
if(num_ipv6_modem_pdn == 0)
{
IPACMDBG_H("Now the number of modem ipv6 interface is 0, delete default flt rules.\n");
IPACM_Wan::num_v6_flt_rule = 0;
memset(IPACM_Wan::flt_rule_v6, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
install_wan_filtering_rule(false);
}
IPACMDBG_H("Delete default v4 coalesce routing rules\n");
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[0], IPA_IP_v4) == false)
{
IPACMERR("Routing rule RSC TCP deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[1], IPA_IP_v4) == false)
{
IPACMERR("Routing rule RSB UDP deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
{
IPACMERR("Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
for (i = 0; i < 2*num_dft_rt_v6; i++)
{
/* delete v6 colasce rules */
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
{
IPACMERR("Colasce Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
{
IPACMERR("Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
}
}
// /* check software routing fl rule hdl */
// if (softwarerouting_act == true)
// {
// handle_software_routing_disable();
// }
fail:
if (tx_prop != NULL)
{
free(tx_prop);
}
if (rx_prop != NULL)
{
free(rx_prop);
}
if (ext_prop != NULL)
{
free(ext_prop);
}
if (iface_query != NULL)
{
free(iface_query);
}
if (wan_route_rule_v4_hdl != NULL)
{
free(wan_route_rule_v4_hdl);
}
if (wan_route_rule_v6_hdl != NULL)
{
free(wan_route_rule_v6_hdl);
}
if (wan_route_rule_v6_hdl_a5 != NULL)
{
free(wan_route_rule_v6_hdl_a5);
}
if (wan_client != NULL)
{
free(wan_client);
}
close(m_fd_ipa);
return res;
}
int IPACM_Wan::install_wan_filtering_rule(bool is_sw_routing)
{
int len, res = IPACM_SUCCESS;
uint8_t mux_id;
ipa_ioc_add_flt_rule *pFilteringTable_v4 = NULL;
ipa_ioc_add_flt_rule *pFilteringTable_v6 = NULL;
mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
if(rx_prop == NULL)
{
IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if (is_sw_routing == true ||
IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true)
{
/* contruct SW-RT rules to Q6*/
struct ipa_flt_rule_add flt_rule_entry;
struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
ipa_ioc_generate_flt_eq flt_eq;
IPACMDBG("\n");
if (softwarerouting_act == true)
{
IPACMDBG("already setup software_routing rule for (%s)iface ip-family %d\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
return IPACM_SUCCESS;
}
len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
if (pFilteringTable_v4 == NULL)
{
IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
return IPACM_FAILURE;
}
memset(pFilteringTable_v4, 0, len);
IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is 1\n");
pFilteringTable_v4->commit = 1;
pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
pFilteringTable_v4->global = false;
pFilteringTable_v4->ip = IPA_IP_v4;
pFilteringTable_v4->num_rules = (uint8_t)1;
/* Configuring Software-Routing Filtering Rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
rt_tbl_idx.ip = IPA_IP_v4;
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");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
flt_rule_entry.rule.retain_hdr = 0;
flt_rule_entry.rule.to_uc = 0;
flt_rule_entry.rule.eq_attrib_type = 1;
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;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(pFilteringTable_v4->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
if (pFilteringTable_v6 == NULL)
{
IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
free(pFilteringTable_v4);
return IPACM_FAILURE;
}
memset(pFilteringTable_v6, 0, len);
IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is 1\n");
pFilteringTable_v6->commit = 1;
pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
pFilteringTable_v6->global = false;
pFilteringTable_v6->ip = IPA_IP_v6;
pFilteringTable_v6->num_rules = (uint8_t)1;
/* Configuring Software-Routing Filtering Rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
rt_tbl_idx.ip = IPA_IP_v6;
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");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
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_ROUTING;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
flt_rule_entry.rule.retain_hdr = 0;
flt_rule_entry.rule.to_uc = 0;
flt_rule_entry.rule.eq_attrib_type = 1;
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_v6;
if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
{
IPACMERR("Failed to get eq_attrib\n");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
memcpy(&(pFilteringTable_v6->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
softwarerouting_act = true;
/* end of contruct SW-RT rules to Q6*/
}
else
{
if(embms_is_on == false)
{
if(IPACM_Wan::num_v4_flt_rule > 0)
{
len = sizeof(struct ipa_ioc_add_flt_rule) + IPACM_Wan::num_v4_flt_rule * sizeof(struct ipa_flt_rule_add);
pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is %d\n", IPACM_Wan::num_v4_flt_rule);
if (pFilteringTable_v4 == NULL)
{
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;
pFilteringTable_v4->ip = IPA_IP_v4;
pFilteringTable_v4->num_rules = (uint8_t)IPACM_Wan::num_v4_flt_rule;
memcpy(pFilteringTable_v4->rules, IPACM_Wan::flt_rule_v4, IPACM_Wan::num_v4_flt_rule * sizeof(ipa_flt_rule_add));
}
if(IPACM_Wan::num_v6_flt_rule > 0)
{
len = sizeof(struct ipa_ioc_add_flt_rule) + IPACM_Wan::num_v6_flt_rule * sizeof(struct ipa_flt_rule_add);
pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is %d\n", IPACM_Wan::num_v6_flt_rule);
if (pFilteringTable_v6 == NULL)
{
IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
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;
pFilteringTable_v6->ip = IPA_IP_v6;
pFilteringTable_v6->num_rules = (uint8_t)IPACM_Wan::num_v6_flt_rule;
memcpy(pFilteringTable_v6->rules, IPACM_Wan::flt_rule_v6, IPACM_Wan::num_v6_flt_rule * sizeof(ipa_flt_rule_add));
}
}
else //embms is on, always add 1 embms rule on top of WAN DL flt table
{
/* allocate ipv4 filtering table */
len = sizeof(struct ipa_ioc_add_flt_rule) + (1 + IPACM_Wan::num_v4_flt_rule) * sizeof(struct ipa_flt_rule_add);
pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is %d\n", IPACM_Wan::num_v4_flt_rule + 1);
if (pFilteringTable_v4 == NULL)
{
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;
pFilteringTable_v4->ip = IPA_IP_v4;
pFilteringTable_v4->num_rules = (uint8_t)IPACM_Wan::num_v4_flt_rule + 1;
/* allocate ipv6 filtering table */
len = sizeof(struct ipa_ioc_add_flt_rule) + (1 + IPACM_Wan::num_v6_flt_rule) * sizeof(struct ipa_flt_rule_add);
pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is %d\n", IPACM_Wan::num_v6_flt_rule + 1);
if (pFilteringTable_v6 == NULL)
{
IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
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;
pFilteringTable_v6->ip = IPA_IP_v6;
pFilteringTable_v6->num_rules = (uint8_t)IPACM_Wan::num_v6_flt_rule + 1;
config_dft_embms_rules(pFilteringTable_v4, pFilteringTable_v6);
if(IPACM_Wan::num_v4_flt_rule > 0)
{
memcpy(&(pFilteringTable_v4->rules[1]), IPACM_Wan::flt_rule_v4, IPACM_Wan::num_v4_flt_rule * sizeof(ipa_flt_rule_add));
}
if(IPACM_Wan::num_v6_flt_rule > 0)
{
memcpy(&(pFilteringTable_v6->rules[1]), IPACM_Wan::flt_rule_v6, IPACM_Wan::num_v6_flt_rule * sizeof(ipa_flt_rule_add));
}
}
}
if(false == m_filtering.AddWanDLFilteringRule(pFilteringTable_v4, pFilteringTable_v6, mux_id))
{
IPACMERR("Failed to install WAN DL filtering table.\n");
res = IPACM_FAILURE;
goto fail;
}
fail:
if(pFilteringTable_v4 != NULL)
{
free(pFilteringTable_v4);
}
if(pFilteringTable_v6 != NULL)
{
free(pFilteringTable_v6);
}
return res;
}
/* handle STA WAN-client */
/* handle WAN client initial, construct full headers (tx property) */
int IPACM_Wan::handle_wan_hdr_init(uint8_t *mac_addr, bool replaced, int entry)
{
#define WAN_IFACE_INDEX_LEN 2
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;
uint32_t cnt;
int clnt_indx;
IPACMDBG_H("WAN client number: %d\n", num_wan_client);
if(!replaced)
{
clnt_indx = get_wan_client_index(mac_addr);
if (clnt_indx != IPACM_INVALID_INDEX)
{
IPACMERR("eth client is found/attached already with index %d \n", clnt_indx);
return IPACM_FAILURE;
}
/* add header to IPA */
if (num_wan_client >= IPA_MAX_NUM_WAN_CLIENTS)
{
IPACMERR("Reached maximum number(%d) of eth clients\n", IPA_MAX_NUM_WAN_CLIENTS);
return IPACM_FAILURE;
}
memcpy(get_client_memptr(wan_client, num_wan_client)->mac,
mac_addr,
sizeof(get_client_memptr(wan_client, num_wan_client)->mac));
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]);
IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
get_client_memptr(wan_client, num_wan_client)->mac[0],
get_client_memptr(wan_client, num_wan_client)->mac[1],
get_client_memptr(wan_client, num_wan_client)->mac[2],
get_client_memptr(wan_client, num_wan_client)->mac[3],
get_client_memptr(wan_client, num_wan_client)->mac[4],
get_client_memptr(wan_client, num_wan_client)->mac[5]);
}
/* add header to IPA */
if(tx_prop != NULL)
{
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)
{
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)
{
IPACMDBG_H("Got partial v4-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 in tx:%d\n", sCopyHeader.name,cnt);
if (m_header.CopyHeader(&sCopyHeader) == false)
{
PERROR("ioctl copy header failed");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
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 */
IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n",
sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
/* only copy 6 bytes mac-address */
if(sCopyHeader.is_eth2_ofst_valid == false)
{
memcpy(&pHeaderDescriptor->hdr[0].hdr[0],
mac_addr, IPA_MAC_ADDR_SIZE);
}
else
{
memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
mac_addr, IPA_MAC_ADDR_SIZE);
}
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));
pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
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 (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
res = IPACM_FAILURE;
goto fail;
}
snprintf(index,sizeof(index), "%d", header_name_count);
if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
{
IPACMERR(" header name construction failed exceed length (%zu)\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;
}
if (!replaced)
{
get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
IPACMDBG_H("eth-client(%d) v4 full header name:%s header handle:(0x%x)\n",
num_wan_client,
pHeaderDescriptor->hdr[0].name,
get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v4);
get_client_memptr(wan_client, num_wan_client)->ipv4_header_set=true;
} else
{
get_client_memptr(wan_client, entry)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
IPACMDBG_H("replaced eth-client(%d) v4 full header name:%s header handle:(0x%x)\n",
entry,
pHeaderDescriptor->hdr[0].name,
get_client_memptr(wan_client, entry)->hdr_hdl_v4);
get_client_memptr(wan_client, entry)->ipv4_header_set=true;
}
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 in tx:%d\n", sCopyHeader.name,cnt);
if (m_header.CopyHeader(&sCopyHeader) == false)
{
PERROR("ioctl copy header failed");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
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 */
if(sCopyHeader.is_eth2_ofst_valid == false)
{
memcpy(&pHeaderDescriptor->hdr[0].hdr[0],
mac_addr, IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
}
else
{
memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
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));
pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
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 (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
res = IPACM_FAILURE;
goto fail;
}
snprintf(index,sizeof(index), "%d", header_name_count);
if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
{
IPACMERR(" header name construction failed exceed length (%zu)\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;
}
if (!replaced)
{
get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
IPACMDBG_H("eth-client(%d) v6 full header name:%s header handle:(0x%x)\n",
num_wan_client,
pHeaderDescriptor->hdr[0].name,
get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v6);
get_client_memptr(wan_client, num_wan_client)->ipv6_header_set=true;
}
else
{
get_client_memptr(wan_client, entry)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
IPACMDBG_H("replaced eth-client(%d) v6 full header name:%s header handle:(0x%x)\n",
entry,
pHeaderDescriptor->hdr[0].name,
get_client_memptr(wan_client, entry)->hdr_hdl_v6);
get_client_memptr(wan_client, entry)->ipv6_header_set=true;
}
break;
}
}
/* initialize wifi client*/
if (!replaced)
{
get_client_memptr(wan_client, num_wan_client)->route_rule_set_v4 = false;
get_client_memptr(wan_client, num_wan_client)->route_rule_set_v6 = 0;
get_client_memptr(wan_client, num_wan_client)->ipv4_set = false;
get_client_memptr(wan_client, num_wan_client)->ipv6_set = 0;
num_wan_client++;
}
else
{
get_client_memptr(wan_client, entry)->route_rule_set_v4 = false;
get_client_memptr(wan_client, entry)->route_rule_set_v6 = 0;
get_client_memptr(wan_client, entry)->ipv4_set = false;
get_client_memptr(wan_client, entry)->ipv6_set = 0;
}
header_name_count++; //keep increasing header_name_count
res = IPACM_SUCCESS;
IPACMDBG_H("eth client number: %d\n", num_wan_client);
}
else
{
return res;
}
fail:
free(pHeaderDescriptor);
return res;
}
/*handle eth client */
int IPACM_Wan::handle_wan_client_ipaddr(ipacm_event_data_all *data)
{
int clnt_indx;
int v6_num;
IPACMDBG_H("number of wan clients: %d\n", num_wan_client);
IPACMDBG_H(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
data->mac_addr[0],
data->mac_addr[1],
data->mac_addr[2],
data->mac_addr[3],
data->mac_addr[4],
data->mac_addr[5]);
clnt_indx = get_wan_client_index(data->mac_addr);
if (clnt_indx == IPACM_INVALID_INDEX)
{
IPACMERR("wan client not found/attached \n");
return IPACM_FAILURE;
}
IPACMDBG_H("Ip-type received %d\n", data->iptype);
if (data->iptype == IPA_IP_v4)
{
IPACMDBG_H("ipv4 address: 0x%x\n", data->ipv4_addr);
if (data->ipv4_addr != 0) /* not 0.0.0.0 */
{
if (get_client_memptr(wan_client, clnt_indx)->ipv4_set == false)
{
get_client_memptr(wan_client, clnt_indx)->v4_addr = data->ipv4_addr;
get_client_memptr(wan_client, clnt_indx)->ipv4_set = true;
/* Add NAT rules after ipv4 RT rules are set */
CtList->HandleSTAClientAddEvt(data->ipv4_addr);
}
else
{
/* check if client got new IPv4 address*/
if(data->ipv4_addr == get_client_memptr(wan_client, clnt_indx)->v4_addr)
{
IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
return IPACM_FAILURE;
}
else
{
IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
/* Del NAT rules before ipv4 RT rules are delete */
CtList->HandleSTAClientDelEvt(get_client_memptr(wan_client, clnt_indx)->v4_addr);
delete_wan_rtrules(clnt_indx,IPA_IP_v4);
get_client_memptr(wan_client, clnt_indx)->route_rule_set_v4 = false;
get_client_memptr(wan_client, clnt_indx)->v4_addr = data->ipv4_addr;
/* Add NAT rules after ipv4 RT rules are set */
CtList->HandleSTAClientAddEvt(data->ipv4_addr);
}
}
}
else
{
IPACMDBG_H("Invalid client IPv4 address \n");
return IPACM_FAILURE;
}
}
else
{
if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
(data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] != 0)) /* check if all 0 not valid ipv6 address */
{
IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
if(get_client_memptr(wan_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
{
for(v6_num=0;v6_num < get_client_memptr(wan_client, clnt_indx)->ipv6_set;v6_num++)
{
if( data->ipv6_addr[0] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][0] &&
data->ipv6_addr[1] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][1] &&
data->ipv6_addr[2]== get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][2] &&
data->ipv6_addr[3] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][3])
{
IPACMDBG_H("Already see this ipv6 addr for client:%d\n", clnt_indx);
return IPACM_FAILURE; /* not setup the RT rules*/
}
}
/* not see this ipv6 before for wifi client*/
get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][1] = data->ipv6_addr[1];
get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][2] = data->ipv6_addr[2];
get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][3] = data->ipv6_addr[3];
get_client_memptr(wan_client, clnt_indx)->ipv6_set++;
}
else
{
IPACMDBG_H("Already got 3 ipv6 addr for client:%d\n", clnt_indx);
return IPACM_FAILURE; /* not setup the RT rules*/
}
}
else
{
IPACMDBG_H("Invalid IPV6 address\n");
return IPACM_FAILURE;
}
}
return IPACM_SUCCESS;
}
/*handle wan client routing rule*/
int IPACM_Wan::handle_wan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
{
struct ipa_ioc_add_rt_rule *rt_rule;
struct ipa_rt_rule_add *rt_rule_entry;
uint32_t tx_index;
int wan_index,v6_num;
const int NUM = 1;
if(tx_prop == NULL)
{
IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
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]);
wan_index = get_wan_client_index(mac_addr);
if (wan_index == IPACM_INVALID_INDEX)
{
IPACMDBG_H("wan client not found/attached \n");
return IPACM_SUCCESS;
}
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);
} 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);
}
/* 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)
|| (iptype == IPA_IP_v6
&& get_client_memptr(wan_client, wan_index)->route_rule_set_v6 < get_client_memptr(wan_client, wan_index)->ipv6_set
))
{
if(IPACM_Iface::ipacmcfg->GetIPAVer() >= IPA_HW_None && IPACM_Iface::ipacmcfg->GetIPAVer() < IPA_HW_v4_0)
{
/* 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));
if (rt_rule == NULL)
{
PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
return IPACM_FAILURE;
}
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;
}
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(%d): v4 header handle:(0x%x)\n",
wan_index,
get_client_memptr(wan_client, wan_index)->hdr_hdl_v4);
strlcpy(rt_rule->rt_tbl_name,
IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name,
sizeof(rt_rule->rt_tbl_name));
rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
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 (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = true;
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(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 {
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 */
strlcpy(rt_rule->rt_tbl_name,
IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
sizeof(rt_rule->rt_tbl_name));
rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
/* Uplink going to wan clients should go to 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;
}
memset(&rt_rule_entry->rule.attrib, 0, 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 (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = true;
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[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*/
strlcpy(rt_rule->rt_tbl_name,
IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
sizeof(rt_rule->rt_tbl_name));
rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
/* Downlink traffic from Wan clients, should go exception */
rt_rule_entry->rule.dst = iface_query->excp_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 = 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;
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(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);
}
}
} /* end of for loop */
free(rt_rule);
if (iptype == IPA_IP_v4)
{
get_client_memptr(wan_client, wan_index)->route_rule_set_v4 = true;
}
else
{
get_client_memptr(wan_client, wan_index)->route_rule_set_v6 = get_client_memptr(wan_client, wan_index)->ipv6_set;
}
}
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->rule.hdr_hdl = hdr_hdl_sta_v4;
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->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)
{
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("isSCCMode: %d\n",isSCCMode);
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;
}
/*handle eth client */
int IPACM_Wan::handle_network_stats_update(ipa_get_apn_data_stats_resp_msg_v01 *data)
{
FILE *fp = NULL;
for (uint32_t apn_index =0; apn_index < data->apn_data_stats_list_len; apn_index++)
{
if(data->apn_data_stats_list[apn_index].mux_id == ext_prop->ext[0].mux_id)
{
IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_NETWORK_STATS, MUX ID %d TX (P%llu/B%llu) RX (P%llu/B%llu)\n",
data->apn_data_stats_list[apn_index].mux_id,
(long long)data->apn_data_stats_list[apn_index].num_ul_packets,
(long long)data->apn_data_stats_list[apn_index].num_ul_bytes,
(long long)data->apn_data_stats_list[apn_index].num_dl_packets,
(long long)data->apn_data_stats_list[apn_index].num_dl_bytes);
fp = fopen(IPA_NETWORK_STATS_FILE_NAME, "w");
if ( fp == NULL )
{
IPACMERR("Failed to write pipe stats to %s, error is %d - %s\n",
IPA_NETWORK_STATS_FILE_NAME, errno, strerror(errno));
return IPACM_FAILURE;
}
fprintf(fp, NETWORK_STATS,
dev_name,
(long long)data->apn_data_stats_list[apn_index].num_ul_packets,
(long long)data->apn_data_stats_list[apn_index].num_ul_bytes,
(long long)data->apn_data_stats_list[apn_index].num_dl_packets,
(long long)data->apn_data_stats_list[apn_index].num_dl_bytes);
fclose(fp);
break;
};
}
return IPACM_SUCCESS;
}
int IPACM_Wan::add_dummy_rx_hdr()
{
#define IFACE_INDEX_LEN 2
char index[IFACE_INDEX_LEN];
struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
int len = 0;
struct ipa_ioc_copy_hdr sCopyHeader;
struct ipa_hdr_add *ipv6_hdr;
struct ethhdr *eth_ipv6;
struct ipa_ioc_add_hdr_proc_ctx* pHeaderProcTable = NULL;
uint32_t cnt;
/* get netdev-mac */
if(tx_prop != NULL)
{
/* 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 in tx:%d\n", sCopyHeader.name,cnt);
if (m_header.CopyHeader(&sCopyHeader) == false)
{
PERROR("ioctl copy header failed");
return IPACM_FAILURE;
}
IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
{
IPACMERR("header oversize\n");
return IPACM_FAILURE;
}
else
{
/* copy client mac_addr to partial header */
IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n",
sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
/* only copy 6 bytes mac-address */
if(sCopyHeader.is_eth2_ofst_valid == false)
{
memcpy(netdev_mac, &sCopyHeader.hdr[0+IPA_MAC_ADDR_SIZE],
sizeof(netdev_mac));
}
else
{
memcpy(netdev_mac, &sCopyHeader.hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
sizeof(netdev_mac));
}
}
break;
}
}
}
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)
{
IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
return IPACM_FAILURE;
}
ipv6_hdr = &pHeaderDescriptor->hdr[0];
/* copy ethernet type to header */
eth_ipv6 = (struct ethhdr *) (ipv6_hdr->hdr +2);
memcpy(eth_ipv6->h_dest, netdev_mac, ETH_ALEN);
memcpy(eth_ipv6->h_source, ext_router_mac_addr, ETH_ALEN);
eth_ipv6->h_proto = htons(ETH_P_IPV6);
pHeaderDescriptor->commit = true;
pHeaderDescriptor->num_hdrs = 1;
memset(ipv6_hdr->name, 0,
sizeof(pHeaderDescriptor->hdr[0].name));
snprintf(index,sizeof(index), "%d", ipa_if_num);
strlcpy(ipv6_hdr->name, index, sizeof(ipv6_hdr->name));
ipv6_hdr->name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if (strlcat(ipv6_hdr->name, IPA_DUMMY_ETH_HDR_NAME_v6, sizeof(ipv6_hdr->name)) > IPA_RESOURCE_NAME_MAX)
{
IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(ipv6_hdr->name));
return IPACM_FAILURE;
}
ipv6_hdr->hdr_len = ETH_HLEN + 2;
ipv6_hdr->hdr_hdl = -1;
ipv6_hdr->is_partial = 0;
ipv6_hdr->status = -1;
ipv6_hdr->type = IPA_HDR_L2_ETHERNET_II;
if (m_header.AddHeader(pHeaderDescriptor) == false ||
ipv6_hdr->status != 0)
{
IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", ipv6_hdr->status);
return IPACM_FAILURE;
}
hdr_hdl_dummy_v6 = ipv6_hdr->hdr_hdl;
IPACMDBG_H("dummy v6 full header name:%s header handle:(0x%x)\n",
ipv6_hdr->name,
hdr_hdl_dummy_v6);
/* add dummy hdr_proc_hdl */
len = sizeof(struct ipa_ioc_add_hdr_proc_ctx) + sizeof(struct ipa_hdr_proc_ctx_add);
pHeaderProcTable = (ipa_ioc_add_hdr_proc_ctx*)malloc(len);
if(pHeaderProcTable == NULL)
{
IPACMERR("Cannot allocate header processing table.\n");
return IPACM_FAILURE;
}
memset(pHeaderProcTable, 0, len);
pHeaderProcTable->commit = 1;
pHeaderProcTable->num_proc_ctxs = 1;
pHeaderProcTable->proc_ctx[0].hdr_hdl = hdr_hdl_dummy_v6;
if (m_header.AddHeaderProcCtx(pHeaderProcTable) == false)
{
IPACMERR("Adding dummy hhdr_proc_hdl failed with status: %d\n", pHeaderProcTable->proc_ctx[0].status);
return IPACM_FAILURE;
}
else
{
hdr_proc_hdl_dummy_v6 = pHeaderProcTable->proc_ctx[0].proc_ctx_hdl;
IPACMDBG_H("dummy hhdr_proc_hdl is added successfully. (0x%x)\n", hdr_proc_hdl_dummy_v6);
}
return IPACM_SUCCESS;
}
int IPACM_Wan::handle_coalesce_evt()
{
struct ipa_ioc_add_rt_rule *rt_rule = NULL;
struct ipa_rt_rule_add *rt_rule_entry;
const int NUM_RULES = 1;
int res = IPACM_SUCCESS;
struct ipa_ioc_get_hdr hdr;
uint32_t i;
if(wan_v4_addr_set)
{
/* Delete default RSC v4 RT rule */
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[0], IPA_IP_v4) == false)
{
IPACMERR("Routing old RSC TCP RT rule deletion failed!\n");
return IPACM_FAILURE;
}
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[1], IPA_IP_v4) == false)
{
IPACMERR("Routing old RSB UDP RT rule deletion failed!\n");
return IPACM_FAILURE;
}
/* 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");
return IPACM_FAILURE;
}
/* apply the new coalesce configuration */
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));
if (!rt_rule)
{
IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
return IPACM_FAILURE;
}
rt_rule->commit = 1;
rt_rule->num_rules = NUM_RULES;
rt_rule->ip = IPA_IP_v4;
rt_rule_entry = &rt_rule->rules[0];
rt_rule_entry->at_rear = false;
rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
/* still need setup v4 default routing rule to APPs*/
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name));
rt_rule_entry->rule.attrib.u.v4.dst_addr = wan_v4_addr;
rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = false;
/* query qmap header*/
memset(&hdr, 0, sizeof(hdr));
strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
if(m_header.GetHeaderHandle(&hdr) == false)
{
IPACMERR("Failed to get QMAP header.\n");
res = IPACM_FAILURE;
goto fail;
}
rt_rule_entry->rule.hdr_hdl = hdr.hdl;
rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
/* default v4 rt-rule */
#ifdef IPA_RT_SUPPORT_COAL
rt_rule_entry->rule.coalesce = false;
#endif
/* default v4 rt-rule */
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 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
/* RSC TCP rule*/
rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
rt_rule_entry->rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_TCP;
#ifdef IPA_RT_SUPPORT_COAL
if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
rt_rule_entry->rule.coalesce = true;
else
rt_rule_entry->rule.coalesce = false;
#endif
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("rsc tcp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail;
}
dft_coalesce_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv4 wan iface rsc tcp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[0],
IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable);
/* RSB UDP rule*/
rt_rule_entry->rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_UDP;
#ifdef IPA_RT_SUPPORT_COAL
if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
rt_rule_entry->rule.coalesce = true;
else
rt_rule_entry->rule.coalesce = false;
#endif
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("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail;
}
dft_coalesce_rt_rule_hdl[1] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv4 wan iface rsb udp rt-rule hdll=0x%x enable(%d)\n", dft_coalesce_rt_rule_hdl[1],
IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable);
fail:
free(rt_rule);
}
/* v6 */
if (num_dft_rt_v6 !=0)
{
for (i = 0; i < 2*num_dft_rt_v6; i++)
{
/* delete v6 colasce rules */
if (m_routing.DeleteRoutingHdl(dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
{
IPACMERR("Colasce Routing rule deletion failed!\n");
return IPACM_FAILURE;
}
/* delete v6 default rules */
if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
{
IPACMERR("Routing rule deletion failed!\n");
return IPACM_FAILURE;
}
}
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));
if (!rt_rule)
{
IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
return IPACM_FAILURE;
}
rt_rule->commit = 1;
rt_rule->num_rules = NUM_RULES;
rt_rule->ip = IPA_IP_v6;
for (i = 0; i < num_dft_rt_v6; i++)
{
/* setup same rule for v6_wan table */
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
rt_rule_entry = &rt_rule->rules[0];
rt_rule_entry->at_rear = false;
rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = ipv6_addr[i][0];
rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = ipv6_addr[i][1];
rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = ipv6_addr[i][2];
rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = ipv6_addr[i][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 (IPACM_Iface::ipacmcfg->isIPAv3Supported())
rt_rule_entry->rule.hashable = false;
strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
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;
/* legacy default v4 rt-rule */
#ifdef IPA_RT_SUPPORT_COAL
rt_rule_entry->rule.coalesce = false;
#endif
/* legacy default v6 rt-rule */
if (false == m_routing.AddRoutingRule(rt_rule))
{
IPACMERR("Routing rule addition failed!\n");
res = IPACM_FAILURE;
goto fail2;
}
else if (rt_rule_entry->status)
{
IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail2;
}
dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*i] = rt_rule_entry->rt_rule_hdl;
/* setup same rule for v6_lan table*/
strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
if (false == m_routing.AddRoutingRule(rt_rule))
{
IPACMERR("Routing rule addition failed!\n");
res = IPACM_FAILURE;
goto fail2;
}
else if (rt_rule_entry->status)
{
IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail2;
}
dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv6 wan iface rt-rule hdl=0x%x hdl=0x%x, entry: %d %d\n",
dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*i],
dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1],
MAX_DEFAULT_v4_ROUTE_RULES + 2*i,
MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1);
/* RSC TCP rule*/
rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
rt_rule_entry->rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_TCP;
#ifdef IPA_RT_SUPPORT_COAL
if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable)
rt_rule_entry->rule.coalesce = true;
else
rt_rule_entry->rule.coalesce = false;
#endif
if (false == m_routing.AddRoutingRule(rt_rule))
{
IPACMERR("Routing rule addition failed!\n");
res = IPACM_FAILURE;
goto fail2;
}
else if (rt_rule_entry->status)
{
IPACMERR("rsc tcp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail2;
}
dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv6 wan iface rsc tcp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i],
IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_tcp_enable);
/* RSB UDP rule*/
rt_rule_entry->rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_UDP;
#ifdef IPA_RT_SUPPORT_COAL
if (IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable)
rt_rule_entry->rule.coalesce = true;
else
rt_rule_entry->rule.coalesce = false;
#endif
if (false == m_routing.AddRoutingRule(rt_rule))
{
IPACMERR("Routing rule addition failed!\n");
res = IPACM_FAILURE;
goto fail2;
}
else if (rt_rule_entry->status)
{
IPACMERR("rsb udp rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail2;
}
dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1] = rt_rule_entry->rt_rule_hdl;
IPACMDBG_H("ipv6 wan iface rsb udp rt-rule hdll=0x%x\n enable(%d)", dft_coalesce_rt_rule_hdl[2*MAX_DEFAULT_v4_ROUTE_RULES + 2*i+1],
IPACM_Wan::coalesce_enable_info[ext_prop->ext[0].mux_id].coalesce_udp_enable);
}
fail2:
free(rt_rule);
}
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;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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 res = IPACM_SUCCESS;
int len;
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;
}
int IPACM_Wan::add_icmpv6_exception_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 icmpv6 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_v6;
pFilteringTable->num_rules = (uint8_t)1;
/* Configuring ICMPv6 Filtering Rule */
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;
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.hashable = true;
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_NEXT_HDR;
flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
/* 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_v6;
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");
res = IPACM_FAILURE;
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 */
icmpv6_exception_hdl = pFilteringTable->rules[0].flt_rule_hdl;
fail:
close(fd);
if(pFilteringTable != NULL)
{
free(pFilteringTable);
}
return res;
}
int IPACM_Wan::delete_icmpv6_exception_rule()
{
int len, res = IPACM_SUCCESS;
ipa_ioc_del_flt_rule *pFilteringTable = NULL;
struct ipa_flt_rule_del flt_rule_entry;
IPACMDBG_H("deleting MHI icmpv6 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 IPACM_FAILURE;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ip = IPA_IP_v6;
pFilteringTable->num_hdls = (uint8_t)1;
if (icmpv6_exception_hdl == 0)
{
IPACMERR("invalid icmpv6_exception_hdl.\n");
res = IPACM_FAILURE;
goto fail;
}
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_del));
flt_rule_entry.hdl = icmpv6_exception_hdl;
memcpy(&(pFilteringTable->hdl[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_del));
if(false == m_filtering.DelOffloadFilteringRule(pFilteringTable))
{
IPACMERR("Failed to delete MHI icmpv6 rule.\n");
res = IPACM_FAILURE;
goto fail;
}
icmpv6_exception_hdl = 0;
fail:
if(pFilteringTable != NULL)
{
free(pFilteringTable);
}
return res;
}
int IPACM_Wan::add_tcp_fin_rst_exception_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 TCP FIN RST rule\n");
len = sizeof(struct ipa_ioc_add_flt_rule) + (2 * 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)2;
/* Configuring TCP FIN RST Filtering Rule */
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;
/*
* need this since fin is last packet in an ongoing TCP connection
* so it will always match the previous hash and take MHIP path
*/
flt_rule_entry.rule.hashable = false;
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_PROTOCOL;
flt_rule_entry.rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_TCP;
/* 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");
res = IPACM_FAILURE;
goto fail;
}
memcpy(&flt_rule_entry.rule.eq_attrib,
&flt_eq.eq_attrib,
sizeof(flt_rule_entry.rule.eq_attrib));
/* set the bit mask to use MEQ32_IHL offset */
if (IPACM_Iface::ipacmcfg->isIPAv3Supported())
flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<7);
else
flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
/* add offset to compare TCP flags */
flt_rule_entry.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
/* add TCP FIN RULE */
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* add TCP RST rule*/
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
memcpy(&(pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* add rules */
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 */
tcp_fin_hdl = pFilteringTable->rules[0].flt_rule_hdl;
tcp_rst_hdl = pFilteringTable->rules[1].flt_rule_hdl;
fail:
close(fd);
if(pFilteringTable != NULL)
{
free(pFilteringTable);
}
return res;
}
int IPACM_Wan::delete_tcp_fin_rst_exception_rule()
{
int len, res = IPACM_SUCCESS;
ipa_ioc_del_flt_rule *pFilteringTable = NULL;
struct ipa_flt_rule_del flt_rule_entry;
IPACMDBG_H("deleting MHI TCP FIN RST rule \n");
len = sizeof(struct ipa_ioc_del_flt_rule) + (2 * 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 IPACM_FAILURE;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ip = IPA_IP_v4;
pFilteringTable->num_hdls = (uint8_t)2;
if (tcp_fin_hdl == 0 || tcp_rst_hdl == 0)
{
IPACMERR("invalid tcp_fin_rst_hdl.\n");
res = IPACM_FAILURE;
goto fail;
}
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_del));
flt_rule_entry.hdl = tcp_fin_hdl;
memcpy(&(pFilteringTable->hdl[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_del));
flt_rule_entry.hdl = tcp_rst_hdl;
memcpy(&(pFilteringTable->hdl[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_del));
if(false == m_filtering.DelOffloadFilteringRule(pFilteringTable))
{
IPACMERR("Failed to delete MHI TCP FIN RST rule.\n");
res = IPACM_FAILURE;
goto fail;
}
tcp_fin_hdl = 0;
tcp_rst_hdl = 0;
fail:
if(pFilteringTable != NULL)
{
free(pFilteringTable);
}
return res;
}
int IPACM_Wan::query_mtu_size()
{
int fd;
struct ifreq if_mtu;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if ( fd < 0 ) {
IPACMERR("ipacm: socket open failed [%d]\n", fd);
return IPACM_FAILURE;
}
strlcpy(if_mtu.ifr_name, dev_name, IFNAMSIZ);
IPACMDBG_H("device name: %s\n", dev_name);
if_mtu.ifr_name[IFNAMSIZ - 1] = '\0';
if ( ioctl(fd, SIOCGIFMTU, &if_mtu) < 0 ) {
IPACMERR("ioctl failed to get mtu\n");
close(fd);
return IPACM_FAILURE;
}
IPACMDBG_H("mtu=[%d]\n", if_mtu.ifr_mtu);
if (if_mtu.ifr_mtu <= DEFAULT_MTU_SIZE) {
mtu_v4 = mtu_v6 = if_mtu.ifr_mtu;
}else {
mtu_v4 = mtu_v6 = DEFAULT_MTU_SIZE;
}
IPACMDBG_H("Updated mtu=[%d] for (%s)\n", mtu_v4, dev_name);
close(fd);
return IPACM_SUCCESS;
}
/* construct complete ethernet header */
int IPACM_Wan::handle_gw_mac_renew(ipacm_event_data_all *data, int index_client)
{
int index = IPACM_INVALID_INDEX;
/* checking if client has same ipv4, v6 will put future work */
if (data->iptype == IPA_IP_v4)
{
index = get_wan_client_index_ipv4(data->ipv4_addr);
if (index != IPACM_INVALID_INDEX)
{
IPACMDBG_H("Matched client index: %d\n", index);
IPACMDBG_H("Client MAC in cache %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]);
/* check mac same or not */
if ((data->mac_addr[0] == get_client_memptr(wan_client, index)->mac[0]) &&
(data->mac_addr[1] == get_client_memptr(wan_client, index)->mac[1]) &&
(data->mac_addr[2] == get_client_memptr(wan_client, index)->mac[2]) &&
(data->mac_addr[3] == get_client_memptr(wan_client, index)->mac[3]) &&
(data->mac_addr[4] == get_client_memptr(wan_client, index)->mac[4]) &&
(data->mac_addr[5] == get_client_memptr(wan_client, index)->mac[5]))
{
IPACMDBG_H(" No need client (%d) mac renew with IPv4 (0x%x)\n", index, data->ipv4_addr);
return IPACM_FAILURE;
}
else
{
IPACMDBG_H(" client %d need mac renew with IPv4 (0x%x)\n", index, data->ipv4_addr);
/* Del NAT rules before ipv4 RT rules are delete */
if(get_client_memptr(wan_client, index)->ipv4_set == true)
{
IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wan_client, index)->v4_addr);
CtList->HandleSTAClientDelEvt(get_client_memptr(wan_client, index)->v4_addr);
}
/* clean up STA header / routing rule */
if (data->ipv4_addr == wan_v4_addr_gw && active_v4)
{
handle_route_del_evt(IPA_IP_v4, true);
IPACMDBG_H("Delete default v4 routing rules\n");
hdr_hdl_sta_v4 = 0;
header_set_v4 = false;
header_partial_default_wan_v4 = true;
if (active_v6)
{
handle_route_del_evt(IPA_IP_v6, true);
IPACMDBG_H("Delete default v6 routing rules\n");
header_partial_default_wan_v6 = true;
}
hdr_hdl_sta_v6 = 0;
header_set_v6 = false;
}
/* clean up client header routing rule entry */
if(delete_wan_rtrules(index, IPA_IP_v4))
{
IPACMERR("unbale to delete wan-client v4 route rules for index %d\n", index);
return IPACM_FAILURE;
}
get_client_memptr(wan_client, index)->route_rule_set_v4 = false;
get_client_memptr(wan_client, index)->ipv4_set = false;
IPACMDBG_H("Delete client %d header\n", index);
if(get_client_memptr(wan_client, index)->ipv4_header_set == true)
{
if (m_header.DeleteHeaderHdl(get_client_memptr(wan_client, index)->hdr_hdl_v4) == false)
{
IPACMERR("unable to delete client v4 header for index %d\n", index);
return IPACM_FAILURE;
}
get_client_memptr(wan_client, index)->ipv4_header_set = false;
}
if(delete_wan_rtrules(index, IPA_IP_v6))
{
IPACMERR("unbale to delete wan-client v6 route rules for index %d\n", index);
return IPACM_FAILURE;
}
get_client_memptr(wan_client, index)->route_rule_set_v6 = 0;
get_client_memptr(wan_client, index)->ipv6_set = 0;
if(get_client_memptr(wan_client, index)->ipv6_header_set == true)
{
if (m_header.DeleteHeaderHdl(get_client_memptr(wan_client, index)->hdr_hdl_v6) == false)
{
IPACMERR("unable to delete client v6 header for index %d\n", index);
return IPACM_FAILURE;
}
get_client_memptr(wan_client, index)->ipv6_header_set = false;
}
/* replacing the old mac to new_mac on same entry */
get_client_memptr(wan_client, index)->mac[0] = data->mac_addr[0];
get_client_memptr(wan_client, index)->mac[1] = data->mac_addr[1];
get_client_memptr(wan_client, index)->mac[2] = data->mac_addr[2];
get_client_memptr(wan_client, index)->mac[3] = data->mac_addr[3];
get_client_memptr(wan_client, index)->mac[4] = data->mac_addr[4];
get_client_memptr(wan_client, index)->mac[5] = data->mac_addr[5];
index_client = index;
return IPACM_SUCCESS;
}
}
}
return IPACM_FAILURE;
}