blob: e0fe7b08c0805b0863948deb91c298e7f262b53d [file] [log] [blame]
/*
Copyright (c) 2013, 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_Lan.cpp
@brief
This file implements the LAN iface functionality.
@Author
Skylar Chang
*/
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "IPACM_Netlink.h"
#include "IPACM_Lan.h"
#include "IPACM_Wan.h"
#include "IPACM_IfaceManager.h"
#include "linux/rmnet_ipa_fd_ioctl.h"
#include "linux/ipa_qmi_service_v01.h"
#include "linux/msm_ipa.h"
IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index)
{
num_eth_client = 0;
header_name_count = 0;
Nat_App = NatApp::GetInstance();
if (Nat_App == NULL)
{
IPACMERR("unable to get Nat App instance \n");
return;
}
/* support eth multiple clients */
if(iface_query != NULL)
{
eth_client_len = (sizeof(ipa_eth_client)) + (iface_query->num_tx_props * sizeof(eth_client_rt_hdl));
eth_client = (ipa_eth_client *)calloc(IPA_MAX_NUM_ETH_CLIENTS, eth_client_len);
if (eth_client == NULL)
{
IPACMERR("unable to allocate memory\n");
return;
}
IPACMDBG(" IPACM->IPACM_Lan(%d) constructor: Tx:%d Rx:%d\n", ipa_if_num,
iface_query->num_tx_props, iface_query->num_rx_props);
}
num_wan_ul_fl_rule_v4 = 0;
num_wan_ul_fl_rule_v6 = 0;
memset(wan_ul_fl_rule_hdl_v4, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
memset(wan_ul_fl_rule_hdl_v6, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
memset(lan2lan_flt_rule_hdl_v4, 0, MAX_OFFLOAD_PAIR * sizeof(lan2lan_flt_rule_hdl));
num_lan2lan_flt_rule_v4 = 0;
memset(lan2lan_flt_rule_hdl_v6, 0, MAX_OFFLOAD_PAIR * sizeof(lan2lan_flt_rule_hdl));
num_lan2lan_flt_rule_v6 = 0;
memset(lan2lan_hdr_hdl_v4, 0, MAX_OFFLOAD_PAIR*sizeof(lan2lan_hdr_hdl));
memset(lan2lan_hdr_hdl_v6, 0, MAX_OFFLOAD_PAIR*sizeof(lan2lan_hdr_hdl));
is_active = true;
memset(tcp_ctl_flt_rule_hdl_v4, 0, NUM_TCP_CTL_FLT_RULE*sizeof(uint32_t));
memset(tcp_ctl_flt_rule_hdl_v6, 0, NUM_TCP_CTL_FLT_RULE*sizeof(uint32_t));
is_mode_switch = false;
if_ipv4_subnet =0;
memset(private_fl_rule_hdl, 0, IPA_MAX_PRIVATE_SUBNET_ENTRIES * sizeof(uint32_t));
return;
}
IPACM_Lan::~IPACM_Lan()
{
IPACM_EvtDispatcher::deregistr(this);
IPACM_IfaceManager::deregistr(this);
return;
}
/* LAN-iface's callback function */
void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param)
{
if(is_active == false && event != IPA_LAN_DELETE_SELF)
{
IPACMDBG("The interface is no longer active, return.\n");
return;
}
int ipa_interface_index;
ipacm_ext_prop* ext_prop;
ipacm_event_iface_up* data_wan;
switch (event)
{
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)
{
IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
handle_down_evt();
IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
return;
}
}
break;
case IPA_CFG_CHANGE_EVENT:
{
if ( IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat != ipa_if_cate)
{
IPACMDBG("Received IPA_CFG_CHANGE_EVENT and category changed\n");
/* delete previous instance */
handle_down_evt();
IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
is_mode_switch = true; // need post internal usb-link up event
return;
}
}
break;
case IPA_PRIVATE_SUBNET_CHANGE_EVENT:
{
ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
/* internel event: data->if_index is ipa_if_index */
if (data->if_index == ipa_if_num)
{
IPACMDBG("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from itself posting, ignore\n");
return;
}
else
{
IPACMDBG("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from other LAN iface \n");
#ifdef FEATURE_IPA_ANDROID
handle_private_subnet_android(IPA_IP_v4);
#endif
IPACMDBG(" delete old private subnet rules, use new sets \n");
return;
}
}
break;
case IPA_LAN_DELETE_SELF:
{
ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
if(data->if_index == ipa_if_num)
{
IPACMDBG("Received IPA_LAN_DELETE_SELF event.\n");
IPACMDBG("ipa_LAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
/* posting link-up event for cradle use-case */
if(is_mode_switch)
{
IPACMDBG("Posting IPA_USB_LINK_UP_EVENT event for (%s)\n", dev_name);
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("Posting event:%d\n", evt_data.event);
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
delete this;
}
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("Invalid address, ignore IPA_ADDR_ADD_EVENT event\n");
return;
}
if (ipa_interface_index == ipa_if_num)
{
IPACMDBG("Received IPA_ADDR_ADD_EVENT\n");
/* check v4 not setup before, v6 can have 2 iface ip */
if( ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX))
|| ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
{
IPACMDBG("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
if(handle_addr_evt(data) == IPACM_FAILURE)
{
return;
}
#ifdef FEATURE_IPA_ANDROID
add_dummy_private_subnet_flt_rule(data->iptype);
handle_private_subnet_android(data->iptype);
#else
handle_private_subnet(data->iptype);
#endif
if (IPACM_Wan::isWanUP())
{
if(data->iptype == IPA_IP_v4 || data->iptype == IPA_IP_MAX)
{
if(IPACM_Wan::backhaul_is_sta_mode == false)
{
ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
handle_wan_up_ex(ext_prop, IPA_IP_v4);
}
else
{
handle_wan_up(IPA_IP_v4);
}
}
}
if(IPACM_Wan::isWanUP_V6())
{
if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
{
if(IPACM_Wan::backhaul_is_sta_mode == false)
{
ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
handle_wan_up_ex(ext_prop, IPA_IP_v6);
}
else
{
handle_wan_up(IPA_IP_v6);
}
}
}
/* Post event to NAT */
if (data->iptype == IPA_IP_v4)
{
ipacm_cmd_q_data evt_data;
ipacm_event_iface_up *info;
info = (ipacm_event_iface_up *)
malloc(sizeof(ipacm_event_iface_up));
if (info == NULL)
{
IPACMERR("Unable to allocate memory\n");
return;
}
memcpy(info->ifname, dev_name, IF_NAME_LEN);
info->ipv4_addr = data->ipv4_addr;
info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
evt_data.event = IPA_HANDLE_LAN_UP;
evt_data.evt_data = (void *)info;
/* Insert IPA_HANDLE_LAN_UP to command queue */
IPACMDBG("posting IPA_HANDLE_LAN_UP for IPv4 with below information\n");
IPACMDBG("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
info->ipv4_addr, info->addr_mask);
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
IPACMDBG("Finish handling IPA_ADDR_ADD_EVENT for ip-family(%d)\n", data->iptype);
}
}
}
break;
case IPA_HANDLE_WAN_UP:
IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
data_wan = (ipacm_event_iface_up*)param;
if(data_wan == NULL)
{
IPACMERR("No event data is found.\n");
return;
}
IPACMDBG("Backhaul is sta mode?%d\n", data_wan->is_sta);
if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
{
if(data_wan->is_sta == false)
{
ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
handle_wan_up_ex(ext_prop, IPA_IP_v4);
}
else
{
handle_wan_up(IPA_IP_v4);
}
}
break;
case IPA_HANDLE_WAN_UP_V6:
IPACMDBG("Received IPA_HANDLE_WAN_UP_V6 event\n");
data_wan = (ipacm_event_iface_up*)param;
if(data_wan == NULL)
{
IPACMERR("No event data is found.\n");
return;
}
IPACMDBG("Backhaul is sta mode?%d\n", data_wan->is_sta);
if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
{
if(data_wan->is_sta == false)
{
ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
handle_wan_up_ex(ext_prop, IPA_IP_v6);
}
else
{
handle_wan_up(IPA_IP_v6);
}
}
break;
case IPA_HANDLE_WAN_DOWN:
IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
data_wan = (ipacm_event_iface_up*)param;
if(data_wan == NULL)
{
IPACMERR("No event data is found.\n");
return;
}
IPACMDBG("Backhaul is sta mode?%d\n", data_wan->is_sta);
handle_wan_down(data_wan->is_sta);
break;
case IPA_HANDLE_WAN_DOWN_V6:
IPACMDBG("Received IPA_HANDLE_WAN_DOWN_V6 event\n");
data_wan = (ipacm_event_iface_up*)param;
if(data_wan == NULL)
{
IPACMERR("No event data is found.\n");
return;
}
IPACMDBG("Backhaul is sta mode?%d\n", data_wan->is_sta);
handle_wan_down_v6(data_wan->is_sta);
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);
IPACMDBG("check iface %s category: %d\n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat);
if (ipa_interface_index == ipa_if_num)
{
IPACMDBG("ETH iface got client \n");
/* first construc ETH full header */
handle_eth_hdr_init(data->mac_addr);
handle_lan2lan_client_active(data, IPA_LAN_CLIENT_ACTIVE);
IPACMDBG("construct ETH header and route rules \n");
/* Associate with IP and construct RT-rule */
if (handle_eth_client_ipaddr(data) == IPACM_FAILURE)
{
return;
}
handle_eth_client_route_rule(data->mac_addr, data->iptype);
return;
}
}
break;
case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
{
ipacm_event_data_all *data = (ipacm_event_data_all *)param;
ipa_interface_index = iface_ipa_index_query(data->if_index);
IPACMDBG("check iface %s category: %d\n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat);
if (ipa_interface_index == ipa_if_num)
{
IPACMDBG("ETH iface delete client \n");
handle_eth_client_down_evt(data->mac_addr);
handle_lan2lan_client_active(data, IPA_LAN_CLIENT_INACTIVE);
return;
}
}
break;
case IPA_SW_ROUTING_ENABLE:
IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
/* handle software routing enable event*/
handle_software_routing_enable();
break;
case IPA_SW_ROUTING_DISABLE:
IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
/* handle software routing disable event*/
handle_software_routing_disable();
break;
default:
break;
}
return;
}
/* delete filter rule for wan_down event for IPv4*/
int IPACM_Lan::handle_wan_down(bool is_sta_mode)
{
ipa_fltr_installed_notif_req_msg_v01 flt_index;
int fd;
fd = open(IPA_DEVICE_NAME, O_RDWR);
if (0 == fd)
{
IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
return IPACM_FAILURE;
}
#ifdef CT_OPT
flt_rule_count_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR
+ NUM_TCP_CTL_FLT_RULE + IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
#else
flt_rule_count_v4 = IPV4_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR
+ IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
#endif
#ifdef FEATURE_IPA_ANDROID
flt_rule_count_v4 = flt_rule_count_v4 - IPACM_Iface::ipacmcfg->ipa_num_private_subnet + IPA_MAX_PRIVATE_SUBNET_ENTRIES;
#endif
if(is_sta_mode == false)
{
if (num_wan_ul_fl_rule_v4 > MAX_WAN_UL_FILTER_RULES)
{
IPACMERR("number of wan_ul_fl_rule_v4 > MAX_WAN_UL_FILTER_RULES, aborting...\n");
close(fd);
return IPACM_FAILURE;
}
if (m_filtering.DeleteFilteringHdls(wan_ul_fl_rule_hdl_v4,
IPA_IP_v4, num_wan_ul_fl_rule_v4) == false)
{
IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
close(fd);
return IPACM_FAILURE;
}
memset(wan_ul_fl_rule_hdl_v4, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
num_wan_ul_fl_rule_v4 = 0;
memset(&flt_index, 0, sizeof(flt_index));
flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
flt_index.filter_index_list_len = 0;
flt_index.embedded_pipe_index_valid = 1;
flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
flt_index.retain_header_valid = 1;
flt_index.retain_header = 0;
flt_index.embedded_call_mux_id_valid = 1;
flt_index.embedded_call_mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
{
IPACMERR("Error sending filtering rule index, aborting...\n");
close(fd);
return IPACM_FAILURE;
}
}
else
{
if (m_filtering.DeleteFilteringHdls(&lan_wan_fl_rule_hdl[0], IPA_IP_v4, 1) == false)
{
IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
close(fd);
return IPACM_FAILURE;
}
}
close(fd);
return IPACM_SUCCESS;
}
/* handle new_address event*/
int IPACM_Lan::handle_addr_evt(ipacm_event_data_addr *data)
{
struct ipa_ioc_add_rt_rule *rt_rule;
struct ipa_rt_rule_add *rt_rule_entry;
const int NUM_RULES = 1;
int num_ipv6_addr;
int res = IPACM_SUCCESS;
IPACMDBG("set route/filter rule ip-type: %d \n", data->iptype);
/* Add private subnet*/
#ifdef FEATURE_IPA_ANDROID
if (data->iptype == IPA_IP_v4)
{
// IPACMDBG("Origin IPACM private subnet_addr as: 0x%x \n", data->ipv4_addr);
IPACMDBG("current IPACM private subnet_addr number(%d)\n", IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
if_ipv4_subnet = (data->ipv4_addr >> 8) << 8;
IPACMDBG(" Add IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
if(IPACM_Iface::ipacmcfg->AddPrivateSubnet(if_ipv4_subnet, ipa_if_num) == false)
{
IPACMERR(" can't Add IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
}
}
#endif /* defined(FEATURE_IPA_ANDROID)*/
if (data->iptype == 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];
rt_rule_entry->at_rear = false;
rt_rule_entry->rule.dst = iface_query->excp_pipe; //go to A5
rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
if (false == m_routing.AddRoutingRule(rt_rule))
{
IPACMERR("Routing rule addition failed!\n");
res = IPACM_FAILURE;
goto fail;
}
else if (rt_rule_entry->status)
{
IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
res = rt_rule_entry->status;
goto fail;
}
dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
IPACMDBG("ipv4 iface rt-rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
/* initial multicast/broadcast/fragment filter rule */
#ifdef CT_OPT
install_tcp_ctl_flt_rule(IPA_IP_v4);
#endif
add_dummy_lan2lan_flt_rule(data->iptype);
init_fl_rule(data->iptype);
}
else
{
/* check if see that v6-addr already or not*/
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]))
{
return IPACM_FAILURE;
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;
strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
rt_rule_entry = &rt_rule->rules[0];
rt_rule_entry->at_rear = false;
rt_rule_entry->rule.dst = iface_query->excp_pipe; //go to A5
rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
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 (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*/
strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.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("ipv6 wan iface rt-rule hdl=0x%x hdl=0x%x, num_dft_rt_v6: %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],num_dft_rt_v6);
if (num_dft_rt_v6 == 0)
{
#ifdef CT_OPT
install_tcp_ctl_flt_rule(IPA_IP_v6);
#endif
add_dummy_lan2lan_flt_rule(data->iptype);
/* initial multicast/broadcast/fragment filter rule */
init_fl_rule(data->iptype);
}
num_dft_rt_v6++;
IPACMDBG("number of default route rules %d\n", num_dft_rt_v6);
}
IPACMDBG("finish route/filter rule ip-type: %d, res(%d)\n", data->iptype, res);
fail:
free(rt_rule);
return res;
}
/* configure private subnet filter rules*/
int IPACM_Lan::handle_private_subnet(ipa_ip_type iptype)
{
struct ipa_flt_rule_add flt_rule_entry;
int i;
ipa_ioc_add_flt_rule *m_pFilteringTable;
IPACMDBG("lan->handle_private_subnet(); set route/filter rule \n");
if (rx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if (iptype == IPA_IP_v4)
{
m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
calloc(1,
sizeof(struct ipa_ioc_add_flt_rule) +
(IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
);
if (!m_pFilteringTable)
{
PERROR("Error Locate ipa_flt_rule_add memory...\n");
return IPACM_FAILURE;
}
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)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
{
IPACMERR("LAN m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
free(m_pFilteringTable);
return IPACM_FAILURE;
}
/* Make LAN-traffic always go A5, use default IPA-RT table */
if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4))
{
IPACMERR("LAN m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_default_v4);
free(m_pFilteringTable);
return IPACM_FAILURE;
}
for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
{
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.retain_hdr = 1;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
/* Support priave subnet feature including guest-AP can't talk to primary AP etc */
flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
IPACMDBG(" private filter rule use table: %s\n",IPACM_Iface::ipacmcfg->rt_tbl_default_v4.name);
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
IPACMDBG("Loop %d 5\n", i);
}
if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
{
IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
flt_rule_count_v4 += IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
/* copy filter rule hdls */
for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
{
private_fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
}
free(m_pFilteringTable);
}
else
{
IPACMDBG("No private subnet rules for ipv6 iface %s\n", dev_name);
}
return IPACM_SUCCESS;
}
/* for STA mode wan up: configure filter rule for wan_up event*/
int IPACM_Lan::handle_wan_up(ipa_ip_type ip_type)
{
struct ipa_flt_rule_add flt_rule_entry;
int len = 0;
ipa_ioc_add_flt_rule *m_pFilteringTable;
IPACMDBG("set WAN interface as default filter rule\n");
if (rx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if(ip_type == IPA_IP_v4)
{
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 == NULL)
{
PERROR("Error Locate ipa_flt_rule_add memory...\n");
return IPACM_FAILURE;
}
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("Retrieving routing hanle for table: %s\n",
IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
{
IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
free(m_pFilteringTable);
return IPACM_FAILURE;
}
IPACMDBG("Routing hanle for table: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl);
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
flt_rule_entry.at_rear = true;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x0;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x0;
memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
{
IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
else
{
IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
m_pFilteringTable->rules[0].flt_rule_hdl,
m_pFilteringTable->rules[0].status);
}
/* copy filter hdls */
lan_wan_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
free(m_pFilteringTable);
}
else if(ip_type == IPA_IP_v6)
{
/* add default v6 filter rule */
m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
calloc(1, sizeof(struct ipa_ioc_add_flt_rule) +
1 * sizeof(struct ipa_flt_rule_add));
if (!m_pFilteringTable)
{
PERROR("Error Locate ipa_flt_rule_add memory...\n");
return IPACM_FAILURE;
}
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_v6))
{
IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_v6);
free(m_pFilteringTable);
return IPACM_FAILURE;
}
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.action = IPA_PASS_TO_ROUTING;
flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.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));
if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
free(m_pFilteringTable);
return IPACM_FAILURE;
}
else
{
IPACMDBG("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_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES] = m_pFilteringTable->rules[0].flt_rule_hdl;
free(m_pFilteringTable);
}
return IPACM_SUCCESS;
}
int IPACM_Lan::handle_wan_up_ex(ipacm_ext_prop* ext_prop, ipa_ip_type iptype)
{
int fd, ret = IPACM_SUCCESS, cnt;
IPACM_Config* ipacm_config = IPACM_Iface::ipacmcfg;
struct ipa_ioc_write_qmapid mux;
if(rx_prop != NULL)
{
/* give mud ID to IPA-driver for WLAN/LAN pkts */
fd = open(IPA_DEVICE_NAME, O_RDWR);
if (0 == fd)
{
IPACMDBG("Failed opening %s.\n", IPA_DEVICE_NAME);
return IPACM_FAILURE;
}
mux.qmap_id = ipacm_config->GetQmapId();
for(cnt=0; cnt<rx_prop->num_rx_props; cnt++)
{
mux.client = rx_prop->rx[cnt].src_pipe;
ret = ioctl(fd, IPA_IOC_WRITE_QMAPID, &mux);
if (ret)
{
IPACMERR("Failed to write mux id %d\n", mux.qmap_id);
close(fd);
return IPACM_FAILURE;
}
}
close(fd);
}
/* check only add static UL filter rule once */
if ((num_dft_rt_v6 ==1 && iptype ==IPA_IP_v6) ||
(iptype ==IPA_IP_v4))
{
IPACMDBG("num_dft_rt_v6 %d iptype %d\n", num_dft_rt_v6, iptype);
ret = handle_uplink_filter_rule(ext_prop, iptype);
}
return ret;
}
/* handle ETH client initial, construct full headers (tx property) */
int IPACM_Lan::handle_eth_hdr_init(uint8_t *mac_addr)
{
#define ETH_IFACE_INDEX_LEN 2
int res = IPACM_SUCCESS, len = 0;
char index[ETH_IFACE_INDEX_LEN];
struct ipa_ioc_copy_hdr sCopyHeader;
struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
uint32_t cnt;
int clnt_indx;
clnt_indx = get_eth_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_eth_client >= IPA_MAX_NUM_ETH_CLIENTS)
{
IPACMERR("Reached maximum number(%d) of eth clients\n", IPA_MAX_NUM_ETH_CLIENTS);
return IPACM_FAILURE;
}
IPACMDBG("ETH client number: %d\n", num_eth_client);
memcpy(get_client_memptr(eth_client, num_eth_client)->mac,
mac_addr,
sizeof(get_client_memptr(eth_client, num_eth_client)->mac));
IPACMDBG("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("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
get_client_memptr(eth_client, num_eth_client)->mac[0],
get_client_memptr(eth_client, num_eth_client)->mac[1],
get_client_memptr(eth_client, num_eth_client)->mac[2],
get_client_memptr(eth_client, num_eth_client)->mac[3],
get_client_memptr(eth_client, num_eth_client)->mac[4],
get_client_memptr(eth_client, num_eth_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("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("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("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
IPACMDBG("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)
{
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));
if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_ETH_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
{
IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
res = IPACM_FAILURE;
goto fail;
}
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 (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
res = IPACM_FAILURE;
goto fail;
}
pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
pHeaderDescriptor->hdr[0].hdr_hdl = -1;
pHeaderDescriptor->hdr[0].is_partial = 0;
pHeaderDescriptor->hdr[0].status = -1;
if (m_header.AddHeader(pHeaderDescriptor) == false ||
pHeaderDescriptor->hdr[0].status != 0)
{
IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
res = IPACM_FAILURE;
goto fail;
}
get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
IPACMDBG("eth-client(%d) v4 full header name:%s header handle:(0x%x)\n",
num_eth_client,
pHeaderDescriptor->hdr[0].name,
get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v4);
get_client_memptr(eth_client, num_eth_client)->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("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("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("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
IPACMDBG("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)
{
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));
if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_ETH_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
{
IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
res = IPACM_FAILURE;
goto fail;
}
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 (%d)\n", strlen(pHeaderDescriptor->hdr[0].name));
res = IPACM_FAILURE;
goto fail;
}
pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
pHeaderDescriptor->hdr[0].hdr_hdl = -1;
pHeaderDescriptor->hdr[0].is_partial = 0;
pHeaderDescriptor->hdr[0].status = -1;
if (m_header.AddHeader(pHeaderDescriptor) == false ||
pHeaderDescriptor->hdr[0].status != 0)
{
IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
res = IPACM_FAILURE;
goto fail;
}
get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
IPACMDBG("eth-client(%d) v6 full header name:%s header handle:(0x%x)\n",
num_eth_client,
pHeaderDescriptor->hdr[0].name,
get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v6);
get_client_memptr(eth_client, num_eth_client)->ipv6_header_set=true;
break;
}
}
}
/* initialize wifi client*/
get_client_memptr(eth_client, num_eth_client)->route_rule_set_v4 = false;
get_client_memptr(eth_client, num_eth_client)->route_rule_set_v6 = 0;
get_client_memptr(eth_client, num_eth_client)->ipv4_set = false;
get_client_memptr(eth_client, num_eth_client)->ipv6_set = 0;
num_eth_client++;
header_name_count++; //keep increasing header_name_count
res = IPACM_SUCCESS;
IPACMDBG("eth client number: %d\n", num_eth_client);
fail:
free(pHeaderDescriptor);
return res;
}
/*handle eth client */
int IPACM_Lan::handle_eth_client_ipaddr(ipacm_event_data_all *data)
{
int clnt_indx;
int v6_num;
IPACMDBG("number of eth clients: %d\n", num_eth_client);
IPACMDBG(" 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_eth_client_index(data->mac_addr);
if (clnt_indx == IPACM_INVALID_INDEX)
{
IPACMERR("eth client not found/attached \n");
return IPACM_FAILURE;
}
IPACMDBG("Ip-type received %d\n", data->iptype);
if (data->iptype == IPA_IP_v4)
{
IPACMDBG("ipv4 address: 0x%x\n", data->ipv4_addr);
if (data->ipv4_addr != 0) /* not 0.0.0.0 */
{
if (get_client_memptr(eth_client, clnt_indx)->ipv4_set == false)
{
get_client_memptr(eth_client, clnt_indx)->v4_addr = data->ipv4_addr;
get_client_memptr(eth_client, clnt_indx)->ipv4_set = true;
}
else
{
/* check if client got new IPv4 address*/
if(data->ipv4_addr == get_client_memptr(eth_client, clnt_indx)->v4_addr)
{
IPACMDBG("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
return IPACM_FAILURE;
}
else
{
IPACMDBG("ipv4 addr for client:%d is changed \n", clnt_indx);
delete_eth_rtrules(clnt_indx,IPA_IP_v4);
get_client_memptr(eth_client, clnt_indx)->route_rule_set_v4 = false;
get_client_memptr(eth_client, clnt_indx)->v4_addr = data->ipv4_addr;
}
}
}
else
{
IPACMDBG("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("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(eth_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
{
for(v6_num=0;v6_num < get_client_memptr(eth_client, clnt_indx)->ipv6_set;v6_num++)
{
if( data->ipv6_addr[0] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][0] &&
data->ipv6_addr[1] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][1] &&
data->ipv6_addr[2]== get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][2] &&
data->ipv6_addr[3] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][3])
{
IPACMDBG("Already see this ipv6 addr for client:%d\n", clnt_indx);
return IPACM_FAILURE; /* not setup the RT rules*/
break;
}
}
/* not see this ipv6 before for wifi client*/
get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][1] = data->ipv6_addr[1];
get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][2] = data->ipv6_addr[2];
get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][3] = data->ipv6_addr[3];
get_client_memptr(eth_client, clnt_indx)->ipv6_set++;
}
else
{
IPACMDBG("Already got 3 ipv6 addr for client:%d\n", clnt_indx);
return IPACM_FAILURE; /* not setup the RT rules*/
}
}
}
return IPACM_SUCCESS;
}
/*handle eth client routing rule*/
int IPACM_Lan::handle_eth_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 eth_index,v6_num;
const int NUM = 1;
if(tx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
IPACMDBG("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]);
eth_index = get_eth_client_index(mac_addr);
if (eth_index == IPACM_INVALID_INDEX)
{
IPACMDBG("eth client not found/attached \n");
return IPACM_SUCCESS;
}
if (iptype==IPA_IP_v4) {
IPACMDBG("eth client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", eth_index, iptype,
get_client_memptr(eth_client, eth_index)->ipv4_set,
get_client_memptr(eth_client, eth_index)->route_rule_set_v4);
} else {
IPACMDBG("eth client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", eth_index, iptype,
get_client_memptr(eth_client, eth_index)->ipv6_set,
get_client_memptr(eth_client, eth_index)->route_rule_set_v6);
}
/* Add default routing rules if not set yet */
if ((iptype == IPA_IP_v4
&& get_client_memptr(eth_client, eth_index)->route_rule_set_v4 == false
&& get_client_memptr(eth_client, eth_index)->ipv4_set == true)
|| (iptype == IPA_IP_v6
&& get_client_memptr(eth_client, eth_index)->route_rule_set_v6 < get_client_memptr(eth_client, eth_index)->ipv6_set
))
{
/* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
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("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("client index(%d):ipv4 address: 0x%x\n", eth_index,
get_client_memptr(eth_client, eth_index)->v4_addr);
IPACMDBG("client(%d): v4 header handle:(0x%x)\n",
eth_index,
get_client_memptr(eth_client, eth_index)->hdr_hdl_v4);
strncpy(rt_rule->rt_tbl_name,
IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
sizeof(rt_rule->rt_tbl_name));
rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
memcpy(&rt_rule_entry->rule.attrib,
&tx_prop->tx[tx_index].attrib,
sizeof(rt_rule_entry->rule.attrib));
rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
rt_rule_entry->rule.hdr_hdl = get_client_memptr(eth_client, eth_index)->hdr_hdl_v4;
rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(eth_client, eth_index)->v4_addr;
rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
if (false == m_routing.AddRoutingRule(rt_rule))
{
IPACMERR("Routing rule addition failed!\n");
free(rt_rule);
return IPACM_FAILURE;
}
/* copy ipv4 RT hdl */
get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4 =
rt_rule->rules[0].rt_rule_hdl;
IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4, iptype);
} else {
for(v6_num = get_client_memptr(eth_client, eth_index)->route_rule_set_v6;v6_num < get_client_memptr(eth_client, eth_index)->ipv6_set;v6_num++)
{
IPACMDBG("client(%d): v6 header handle:(0x%x)\n",
eth_index,
get_client_memptr(eth_client, eth_index)->hdr_hdl_v6);
/* v6 LAN_RT_TBL */
strncpy(rt_rule->rt_tbl_name,
IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
sizeof(rt_rule->rt_tbl_name));
/* Support QCMAP LAN traffic feature, send to A5 */
rt_rule_entry->rule.dst = iface_query->excp_pipe;
memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
rt_rule_entry->rule.hdr_hdl = 0;
rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][0];
rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][1];
rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][2];
rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(eth_client, eth_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(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[v6_num], iptype);
/*Copy same rule to v6 WAN RT TBL*/
strncpy(rt_rule->rt_tbl_name,
IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
sizeof(rt_rule->rt_tbl_name));
/* Downlink traffic from Wan iface, directly through IPA */
rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
memcpy(&rt_rule_entry->rule.attrib,
&tx_prop->tx[tx_index].attrib,
sizeof(rt_rule_entry->rule.attrib));
rt_rule_entry->rule.hdr_hdl = get_client_memptr(eth_client, eth_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(eth_client, eth_index)->v6_addr[v6_num][0];
rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][1];
rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][2];
rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(eth_client, eth_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(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[v6_num], iptype);
}
}
} /* end of for loop */
free(rt_rule);
if (iptype == IPA_IP_v4)
{
get_client_memptr(eth_client, eth_index)->route_rule_set_v4 = true;
}
else
{
get_client_memptr(eth_client, eth_index)->route_rule_set_v6 = get_client_memptr(eth_client, eth_index)->ipv6_set;
}
}
return IPACM_SUCCESS;
}
/*handle eth client del mode*/
int IPACM_Lan::handle_eth_client_down_evt(uint8_t *mac_addr)
{
int clt_indx;
uint32_t tx_index;
int num_eth_client_tmp = num_eth_client;
int num_v6;
IPACMDBG("total client: %d\n", num_eth_client_tmp);
clt_indx = get_eth_client_index(mac_addr);
if (clt_indx == IPACM_INVALID_INDEX)
{
IPACMDBG("eth client not attached\n");
return IPACM_SUCCESS;
}
/* First reset nat rules and then route rules */
if(get_client_memptr(eth_client, clt_indx)->ipv4_set == true)
{
IPACMDBG("Deleting Nat Rules\n");
Nat_App->UpdatePwrSaveIf(get_client_memptr(eth_client, clt_indx)->v4_addr);
}
if (delete_eth_rtrules(clt_indx, IPA_IP_v4))
{
IPACMERR("unbale to delete ecm-client v4 route rules\n");
return IPACM_FAILURE;
}
if (delete_eth_rtrules(clt_indx, IPA_IP_v6))
{
IPACMERR("unbale to delete ecm-client v6 route rules\n");
return IPACM_FAILURE;
}
/* Delete eth client header */
if(get_client_memptr(eth_client, clt_indx)->ipv4_header_set == true)
{
if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, clt_indx)->hdr_hdl_v4)
== false)
{
return IPACM_FAILURE;
}
get_client_memptr(eth_client, clt_indx)->ipv4_header_set = false;
}
if(get_client_memptr(eth_client, clt_indx)->ipv6_header_set == true)
{
if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, clt_indx)->hdr_hdl_v6)
== false)
{
return IPACM_FAILURE;
}
get_client_memptr(eth_client, clt_indx)->ipv6_header_set = false;
}
/* Reset ip_set to 0*/
get_client_memptr(eth_client, clt_indx)->ipv4_set = false;
get_client_memptr(eth_client, clt_indx)->ipv6_set = 0;
get_client_memptr(eth_client, clt_indx)->ipv4_header_set = false;
get_client_memptr(eth_client, clt_indx)->ipv6_header_set = false;
get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = false;
get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = 0;
for (; clt_indx < num_eth_client_tmp - 1; clt_indx++)
{
memcpy(get_client_memptr(eth_client, clt_indx)->mac,
get_client_memptr(eth_client, (clt_indx + 1))->mac,
sizeof(get_client_memptr(eth_client, clt_indx)->mac));
get_client_memptr(eth_client, clt_indx)->hdr_hdl_v4 = get_client_memptr(eth_client, (clt_indx + 1))->hdr_hdl_v4;
get_client_memptr(eth_client, clt_indx)->hdr_hdl_v6 = get_client_memptr(eth_client, (clt_indx + 1))->hdr_hdl_v6;
get_client_memptr(eth_client, clt_indx)->v4_addr = get_client_memptr(eth_client, (clt_indx + 1))->v4_addr;
get_client_memptr(eth_client, clt_indx)->ipv4_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv4_set;
get_client_memptr(eth_client, clt_indx)->ipv6_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv6_set;
get_client_memptr(eth_client, clt_indx)->ipv4_header_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv4_header_set;
get_client_memptr(eth_client, clt_indx)->ipv6_header_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv6_header_set;
get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = get_client_memptr(eth_client, (clt_indx + 1))->route_rule_set_v4;
get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = get_client_memptr(eth_client, (clt_indx + 1))->route_rule_set_v6;
for (num_v6=0;num_v6< get_client_memptr(eth_client, clt_indx)->ipv6_set;num_v6++)
{
get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][0] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][0];
get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][1] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][1];
get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][2] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][2];
get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][3] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][3];
}
for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
{
get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4 =
get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4;
for(num_v6=0;num_v6< get_client_memptr(eth_client, clt_indx)->route_rule_set_v6;num_v6++)
{
get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6] =
get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6];
get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6] =
get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6];
}
}
}
IPACMDBG(" %d eth client deleted successfully \n", num_eth_client);
num_eth_client = num_eth_client - 1;
IPACMDBG(" Number of eth client: %d\n", num_eth_client);
/* Del RM dependency */
if(num_eth_client == 0)
{
/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete all IPV4V6 RT-rule*/
IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
}
return IPACM_SUCCESS;
}
/*handle LAN iface down event*/
int IPACM_Lan::handle_down_evt()
{
int i;
int res = IPACM_SUCCESS;
/* no iface address up, directly close iface*/
if (ip_type == IPACM_IP_NULL)
{
goto fail;
}
IPACMDBG("lan handle_down_evt\n ");
if (ip_type != IPA_IP_v6)
{
if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
== false)
{
IPACMERR("Routing rule deletion failed!\n");
res = IPACM_FAILURE;
goto fail;
}
}
IPACMDBG("Finished delete default iface ipv4 rules \n ");
/* delete default v6 routing rule */
if (ip_type != IPA_IP_v4)
{
/* may have multiple ipv6 iface-RT 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("Finished delete default iface ipv6 rules \n ");
/* clean eth-client header, routing rules */
IPACMDBG("left %d eth clients need to be deleted \n ", num_eth_client);
for (i = 0; i < num_eth_client; i++)
{
delete_eth_rtrules(i, IPA_IP_v4);
delete_eth_rtrules(i, IPA_IP_v6);
IPACMDBG("Delete %d client header\n", num_eth_client);
if(get_client_memptr(eth_client, i)->ipv4_header_set == true)
{
if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, i)->hdr_hdl_v4)
== false)
{
res = IPACM_FAILURE;
goto fail;
}
}
if(get_client_memptr(eth_client, i)->ipv6_header_set == true)
{
if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, i)->hdr_hdl_v6)
== false)
{
res = IPACM_FAILURE;
goto fail;
}
}
} /* end of for loop */
/* free the edm clients cache */
IPACMDBG("Free ecm clients cache\n");
/* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete all IPV4V6 RT-rule */
IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
/* check software routing fl rule hdl */
if (softwarerouting_act == true && rx_prop != NULL)
{
handle_software_routing_disable();
}
/* delete default filter rules */
if (ip_type != IPA_IP_v6 && rx_prop != NULL)
{
if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES) == false)
{
IPACMERR("Error Deleting Filtering Rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
#ifdef CT_OPT
if (m_filtering.DeleteFilteringHdls(tcp_ctl_flt_rule_hdl_v4, IPA_IP_v4, NUM_TCP_CTL_FLT_RULE) == false)
{
IPACMERR("Error deleting default filtering Rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
#endif
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
if(m_filtering.DeleteFilteringHdls(&(lan2lan_flt_rule_hdl_v4[i].rule_hdl), IPA_IP_v4, 1) == false)
{
IPACMERR("Error deleting lan2lan IPv4 flt rules.\n");
res = IPACM_FAILURE;
goto fail;
}
}
IPACMDBG("Deleted lan2lan IPv4 flt rules.\n");
/* free private-subnet ipv4 filter rules */
if (IPACM_Iface::ipacmcfg->ipa_num_private_subnet > IPA_PRIV_SUBNET_FILTER_RULE_HANDLES)
{
IPACMERR(" the number of rules are bigger than array, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
#ifdef FEATURE_IPA_ANDROID
if(m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES) == false)
{
IPACMERR("Error deleting private subnet IPv4 flt rules.\n");
res = IPACM_FAILURE;
goto fail;
}
#else
if (m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
{
IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
#endif
}
IPACMDBG("Finished delete default iface ipv4 filtering rules \n ");
if (ip_type != IPA_IP_v4 && rx_prop != NULL)
{
if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
IPA_IP_v6,
(IPV6_DEFAULT_FILTERTING_RULES + IPV6_DEFAULT_LAN_FILTERTING_RULES)) == false)
{
IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
#ifdef CT_OPT
if (m_filtering.DeleteFilteringHdls(tcp_ctl_flt_rule_hdl_v6, IPA_IP_v6, NUM_TCP_CTL_FLT_RULE) == false)
{
IPACMERR("Error deleting default filtering Rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
#endif
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
if(m_filtering.DeleteFilteringHdls(&(lan2lan_flt_rule_hdl_v6[i].rule_hdl), IPA_IP_v6, 1) == false)
{
IPACMERR("Error deleting lan2lan IPv4 flt rules.\n");
res = IPACM_FAILURE;
goto fail;
}
}
IPACMDBG("Deleted lan2lan IPv6 flt rules.\n");
}
IPACMDBG("Finished delete default iface ipv6 filtering rules \n ");
/* delete wan filter rule */
if (IPACM_Wan::isWanUP() && rx_prop != NULL)
{
IPACMDBG("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
handle_wan_down(IPACM_Wan::backhaul_is_sta_mode);
}
if (IPACM_Wan::isWanUP_V6() && rx_prop != NULL)
{
IPACMDBG("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode);
}
/* posting ip to lan2lan module to delete RT/FILTER rules*/
post_lan2lan_client_disconnect_msg();
/* Delete private subnet*/
#ifdef FEATURE_IPA_ANDROID
if (ip_type != IPA_IP_v6)
{
IPACMDBG("current IPACM private subnet_addr number(%d)\n", IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
IPACMDBG(" Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
if(IPACM_Iface::ipacmcfg->DelPrivateSubnet(if_ipv4_subnet, ipa_if_num) == false)
{
IPACMERR(" can't Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
}
}
#endif /* defined(FEATURE_IPA_ANDROID)*/
fail:
/* Delete corresponding ipa_rm_resource_name of RX-endpoint after delete all IPV4V6 FT-rule */
if (rx_prop != NULL)
{
free(rx_prop);
IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
IPACMDBG("Finished delete dependency \n ");
}
if (eth_client != NULL)
{
free(eth_client);
}
if (tx_prop != NULL)
{
free(tx_prop);
}
if (iface_query != NULL)
{
free(iface_query);
}
is_active = false;
post_del_self_evt();
return res;
}
/* install UL filter rule from Q6 */
int IPACM_Lan::handle_uplink_filter_rule(ipacm_ext_prop* prop, ipa_ip_type iptype)
{
ipa_flt_rule_add flt_rule_entry;
int len = 0, cnt, ret = IPACM_SUCCESS;
ipa_ioc_add_flt_rule *pFilteringTable;
ipa_fltr_installed_notif_req_msg_v01 flt_index;
int fd;
int i;
IPACMDBG("Set extended property rules in LAN\n");
if (rx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if(prop == NULL || prop->num_ext_props <= 0)
{
IPACMDBG("No extended property.\n");
return IPACM_SUCCESS;
}
fd = open(IPA_DEVICE_NAME, O_RDWR);
if (0 == fd)
{
IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
}
memset(&flt_index, 0, sizeof(flt_index));
flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
flt_index.filter_index_list_len = prop->num_ext_props;
flt_index.embedded_pipe_index_valid = 1;
flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
flt_index.retain_header_valid = 1;
flt_index.retain_header = 0;
flt_index.embedded_call_mux_id_valid = 1;
flt_index.embedded_call_mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
IPACMDBG("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n", flt_index.source_pipe_index,
flt_index.filter_index_list_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
len = sizeof(struct ipa_ioc_add_flt_rule) + prop->num_ext_props * sizeof(struct ipa_flt_rule_add);
pFilteringTable = (struct ipa_ioc_add_flt_rule*)malloc(len);
if (pFilteringTable == NULL)
{
IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
return IPACM_FAILURE;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ep = rx_prop->rx[0].src_pipe;
pFilteringTable->global = false;
pFilteringTable->ip = iptype;
pFilteringTable->num_rules = prop->num_ext_props;
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
flt_rule_entry.at_rear = 1;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.retain_hdr = 0;
flt_rule_entry.rule.to_uc = 0;
flt_rule_entry.rule.eq_attrib_type = 1;
if(iptype == IPA_IP_v4)
flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
else if(iptype == IPA_IP_v6)
flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
else
{
IPACMERR("IP type is not expected.\n");
ret = IPACM_FAILURE;
goto fail;
}
for(cnt=0; cnt<prop->num_ext_props; cnt++)
{
memcpy(&flt_rule_entry.rule.eq_attrib,
&prop->prop[cnt].eq_attrib,
sizeof(prop->prop[cnt].eq_attrib));
flt_rule_entry.rule.rt_tbl_idx = prop->prop[cnt].rt_tbl_idx;
memcpy(&pFilteringTable->rules[cnt], &flt_rule_entry, sizeof(flt_rule_entry));
if(iptype == IPA_IP_v4)
{
IPACMDBG("Filtering rule %d has index %d\n", cnt, flt_rule_count_v4);
flt_index.filter_index_list[cnt].filter_index = flt_rule_count_v4;
flt_rule_count_v4++;
}
if(iptype == IPA_IP_v6)
{
IPACMDBG("Filtering rule %d has index %d\n", cnt, flt_rule_count_v6);
flt_index.filter_index_list[cnt].filter_index = flt_rule_count_v6;
flt_rule_count_v6++;
}
flt_index.filter_index_list[cnt].filter_handle = prop->prop[cnt].filter_hdl;
}
if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
{
IPACMERR("Error sending filtering rule index, aborting...\n");
ret = IPACM_FAILURE;
goto fail;
}
if(false == m_filtering.AddFilteringRule(pFilteringTable))
{
IPACMERR("Error Adding RuleTable to Filtering, aborting...\n");
ret = IPACM_FAILURE;
goto fail;
}
else
{
if(iptype == IPA_IP_v4)
{
for(i=0; i<pFilteringTable->num_rules; i++)
{
wan_ul_fl_rule_hdl_v4[num_wan_ul_fl_rule_v4] = pFilteringTable->rules[i].flt_rule_hdl;
num_wan_ul_fl_rule_v4++;
}
}
else if(iptype == IPA_IP_v6)
{
for(i=0; i<pFilteringTable->num_rules; i++)
{
wan_ul_fl_rule_hdl_v6[num_wan_ul_fl_rule_v6] = pFilteringTable->rules[i].flt_rule_hdl;
num_wan_ul_fl_rule_v6++;
}
}
else
{
IPACMERR("IP type is not expected.\n");
goto fail;
}
}
fail:
free(pFilteringTable);
close(fd);
return ret;
}
int IPACM_Lan::handle_wan_down_v6(bool is_sta_mode)
{
ipa_fltr_installed_notif_req_msg_v01 flt_index;
int fd;
fd = open(IPA_DEVICE_NAME, O_RDWR);
if (0 == fd)
{
IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
return IPACM_FAILURE;
}
#ifdef CT_OPT
flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + NUM_TCP_CTL_FLT_RULE + MAX_OFFLOAD_PAIR;
#else
flt_rule_count_v6 = IPV6_DEFAULT_FILTERTING_RULES + MAX_OFFLOAD_PAIR;
#endif
if(is_sta_mode == false)
{
if (num_wan_ul_fl_rule_v6 > MAX_WAN_UL_FILTER_RULES)
{
IPACMERR(" the number of rules are bigger than array, aborting...\n");
close(fd);
return IPACM_FAILURE;
}
if (m_filtering.DeleteFilteringHdls(wan_ul_fl_rule_hdl_v6,
IPA_IP_v6, num_wan_ul_fl_rule_v6) == false)
{
IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
close(fd);
return IPACM_FAILURE;
}
memset(wan_ul_fl_rule_hdl_v6, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
num_wan_ul_fl_rule_v6 = 0;
memset(&flt_index, 0, sizeof(flt_index));
flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
flt_index.filter_index_list_len = 0;
flt_index.embedded_pipe_index_valid = 1;
flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
flt_index.retain_header_valid = 1;
flt_index.retain_header = 0;
flt_index.embedded_call_mux_id_valid = 1;
flt_index.embedded_call_mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
{
IPACMERR("Error sending filtering rule index, aborting...\n");
close(fd);
return IPACM_FAILURE;
}
}
else
{
if (m_filtering.DeleteFilteringHdls(&dft_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES],
IPA_IP_v6, 1) == false)
{
IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
close(fd);
return IPACM_FAILURE;
}
}
close(fd);
return IPACM_SUCCESS;
}
/*handle lan2lan client active*/
int IPACM_Lan::handle_lan2lan_client_active(ipacm_event_data_all *data, ipa_cm_event_id event)
{
if(data == NULL)
{
IPACMERR("Event data is empty.\n");
return IPACM_FAILURE;
}
if(data->iptype == IPA_IP_v4 && ip_type != IPA_IP_v4 && ip_type != IPA_IP_MAX)
{
IPACMERR("Client has IPv4 addr but iface does not have IPv4 up.\n");
return IPACM_FAILURE;
}
if(data->iptype == IPA_IP_v6 && ip_type != IPA_IP_v6 && ip_type != IPA_IP_MAX)
{
IPACMERR("Client has IPv6 addr but iface does not have IPv6 up.\n");
return IPACM_FAILURE;
}
ipacm_cmd_q_data evt_data;
memset(&evt_data, 0, sizeof(evt_data));
ipacm_event_lan_client* lan_client;
lan_client = (ipacm_event_lan_client*)malloc(sizeof(ipacm_event_lan_client));
if(lan_client == NULL)
{
IPACMERR("Unable to allocate memory.\n");
return IPACM_FAILURE;
}
memset(lan_client, 0, sizeof(ipacm_event_lan_client));
lan_client->iptype = data->iptype;
lan_client->ipv4_addr = data->ipv4_addr;
memcpy(lan_client->ipv6_addr, data->ipv6_addr, 4 * sizeof(uint32_t));
memcpy(lan_client->mac_addr, data->mac_addr, 6 * sizeof(uint8_t));
lan_client->p_iface = this;
evt_data.event = event;
evt_data.evt_data = (void*)lan_client;
IPACMDBG("Posting event: %d\n", event);
IPACM_EvtDispatcher::PostEvt(&evt_data);
return IPACM_SUCCESS;
}
int IPACM_Lan::add_lan2lan_flt_rule(ipa_ip_type iptype, uint32_t src_v4_addr, uint32_t dst_v4_addr, uint32_t* src_v6_addr, uint32_t* dst_v6_addr, uint32_t* rule_hdl)
{
if(rx_prop == NULL)
{
IPACMERR("There is no rx_prop for iface %s, not able to add lan2lan filtering rule.\n", dev_name);
return IPACM_FAILURE;
}
if(rule_hdl == NULL)
{
IPACMERR("Filteing rule handle is empty.\n");
return IPACM_FAILURE;
}
IPACMDBG("Got a new lan2lan flt rule with IP type: %d\n", iptype);
int i, len, res = IPACM_SUCCESS;
struct ipa_flt_rule_mdfy flt_rule;
struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
len = sizeof(struct ipa_ioc_mdfy_flt_rule) + sizeof(struct ipa_flt_rule_mdfy);
pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
if (pFilteringTable == NULL)
{
IPACMERR("Error allocate lan2lan flt rule memory...\n");
return IPACM_FAILURE;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ip = iptype;
pFilteringTable->num_rules = 1;
memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_mdfy));
if(iptype == IPA_IP_v4)
{
IPACMDBG("src_v4_addr: %d dst_v4_addr: %d\n", src_v4_addr, dst_v4_addr);
if(num_lan2lan_flt_rule_v4 >= MAX_OFFLOAD_PAIR)
{
IPACMERR("Lan2lan flt rule table is full, not able to add.\n");
res = IPACM_FAILURE;
goto fail;
}
if(false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v4))
{
IPACMERR("Failed to get routing table %s handle.\n", IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v4.name);
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("Routing handle for table %s: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v4.name,
IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v4.hdl);
flt_rule.status = -1;
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
if(lan2lan_flt_rule_hdl_v4[i].valid == false)
{
flt_rule.rule_hdl = lan2lan_flt_rule_hdl_v4[i].rule_hdl;
break;
}
}
if(i == MAX_OFFLOAD_PAIR)
{
IPACMERR("Failed to find a filtering rule.\n");
res = IPACM_FAILURE;
goto fail;
}
flt_rule.rule.retain_hdr = 0;
flt_rule.rule.to_uc = 0;
flt_rule.rule.eq_attrib_type = 0;
flt_rule.rule.action = IPA_PASS_TO_ROUTING;
flt_rule.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v4.hdl;
memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
sizeof(flt_rule.rule.attrib));
IPACMDBG("Rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
flt_rule.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
flt_rule.rule.attrib.u.v4.src_addr = src_v4_addr;
flt_rule.rule.attrib.u.v4.src_addr_mask = 0xFFFFFFFF;
flt_rule.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
flt_rule.rule.attrib.u.v4.dst_addr = dst_v4_addr;
flt_rule.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
{
IPACMERR("Error modifying filtering rule.\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
lan2lan_flt_rule_hdl_v4[i].valid = true;
*rule_hdl = lan2lan_flt_rule_hdl_v4[i].rule_hdl;
num_lan2lan_flt_rule_v4++;
IPACMDBG("Flt rule modified, hdl: 0x%x, status: %d\n", pFilteringTable->rules[0].rule_hdl,
pFilteringTable->rules[0].status);
}
}
else if(iptype == IPA_IP_v6)
{
if(num_lan2lan_flt_rule_v6 >= MAX_OFFLOAD_PAIR)
{
IPACMERR("Lan2lan flt rule table is full, not able to add.\n");
res = IPACM_FAILURE;
goto fail;
}
if(src_v6_addr == NULL || dst_v6_addr == NULL)
{
IPACMERR("Got IPv6 flt rule but without IPv6 src/dst addr.\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("src_v6_addr: 0x%08x%08x%08x%08x, dst_v6_addr: 0x%08x%08x%08x%08x\n", src_v6_addr[0], src_v6_addr[1],
src_v6_addr[2], src_v6_addr[3], dst_v6_addr[0], dst_v6_addr[1], dst_v6_addr[2], dst_v6_addr[3]);
if(false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v6))
{
IPACMERR("Failed to get routing table %s handle.\n", IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v6.name);
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("Routing handle for table %s: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v6.name,
IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v6.hdl);
flt_rule.status = -1;
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
if(lan2lan_flt_rule_hdl_v6[i].valid == false)
{
flt_rule.rule_hdl = lan2lan_flt_rule_hdl_v6[i].rule_hdl;
break;
}
}
if(i == MAX_OFFLOAD_PAIR)
{
IPACMERR("Failed to find a filtering rule handle.\n");
res = IPACM_FAILURE;
goto fail;
}
flt_rule.rule.retain_hdr = 0;
flt_rule.rule.to_uc = 0;
flt_rule.rule.eq_attrib_type = 0;
flt_rule.rule.action = IPA_PASS_TO_ROUTING;
flt_rule.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v6.hdl;
memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
sizeof(flt_rule.rule.attrib));
IPACMDBG("Rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
flt_rule.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
flt_rule.rule.attrib.u.v6.src_addr[0] = src_v6_addr[0];
flt_rule.rule.attrib.u.v6.src_addr[1] = src_v6_addr[1];
flt_rule.rule.attrib.u.v6.src_addr[2] = src_v6_addr[2];
flt_rule.rule.attrib.u.v6.src_addr[3] = src_v6_addr[3];
flt_rule.rule.attrib.u.v6.src_addr_mask[0] = 0xFFFFFFFF;
flt_rule.rule.attrib.u.v6.src_addr_mask[1] = 0xFFFFFFFF;
flt_rule.rule.attrib.u.v6.src_addr_mask[2] = 0xFFFFFFFF;
flt_rule.rule.attrib.u.v6.src_addr_mask[3] = 0xFFFFFFFF;
flt_rule.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
flt_rule.rule.attrib.u.v6.dst_addr[0] = dst_v6_addr[0];
flt_rule.rule.attrib.u.v6.dst_addr[1] = dst_v6_addr[1];
flt_rule.rule.attrib.u.v6.dst_addr[2] = dst_v6_addr[2];
flt_rule.rule.attrib.u.v6.dst_addr[3] = dst_v6_addr[3];
flt_rule.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
flt_rule.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
flt_rule.rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
flt_rule.rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
{
IPACMERR("Error modifying filtering rule.\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
lan2lan_flt_rule_hdl_v6[i].valid = true;
*rule_hdl = lan2lan_flt_rule_hdl_v6[i].rule_hdl;
num_lan2lan_flt_rule_v6++;
IPACMDBG("Flt rule modified, hdl: 0x%x, status: %d\n", pFilteringTable->rules[0].rule_hdl,
pFilteringTable->rules[0].status);
}
}
else
{
IPACMERR("IP type is not expected.\n");
res = IPACM_FAILURE;
goto fail;
}
fail:
free(pFilteringTable);
return res;
}
int IPACM_Lan::add_dummy_lan2lan_flt_rule(ipa_ip_type iptype)
{
if(rx_prop == NULL)
{
IPACMDBG("There is no rx_prop for iface %s, not able to add dummy lan2lan filtering rule.\n", dev_name);
return 0;
}
int i, len, res = IPACM_SUCCESS;
struct ipa_flt_rule_add flt_rule;
ipa_ioc_add_flt_rule* pFilteringTable;
len = sizeof(struct ipa_ioc_add_flt_rule) + MAX_OFFLOAD_PAIR * sizeof(struct ipa_flt_rule_add);
pFilteringTable = (struct ipa_ioc_add_flt_rule *)malloc(len);
if (pFilteringTable == NULL)
{
IPACMERR("Error allocate flt table memory...\n");
return IPACM_FAILURE;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ep = rx_prop->rx[0].src_pipe;
pFilteringTable->global = false;
pFilteringTable->ip = iptype;
pFilteringTable->num_rules = MAX_OFFLOAD_PAIR;
memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_add));
flt_rule.rule.retain_hdr = 0;
flt_rule.at_rear = true;
flt_rule.flt_rule_hdl = -1;
flt_rule.status = -1;
flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
sizeof(flt_rule.rule.attrib));
if(iptype == IPA_IP_v4)
{
flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
flt_rule.rule.attrib.u.v4.src_addr_mask = ~0;
flt_rule.rule.attrib.u.v4.src_addr = ~0;
flt_rule.rule.attrib.u.v4.dst_addr_mask = ~0;
flt_rule.rule.attrib.u.v4.dst_addr = ~0;
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_add));
}
if (false == m_filtering.AddFilteringRule(pFilteringTable))
{
IPACMERR("Error adding dummy lan2lan v4 flt rule\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
flt_rule_count_v4 += MAX_OFFLOAD_PAIR;
/* copy filter rule hdls */
for (int i = 0; i < MAX_OFFLOAD_PAIR; i++)
{
if (pFilteringTable->rules[i].status == 0)
{
lan2lan_flt_rule_hdl_v4[i].rule_hdl = pFilteringTable->rules[i].flt_rule_hdl;
IPACMDBG("Lan2lan v4 flt rule %d hdl:0x%x\n", i, lan2lan_flt_rule_hdl_v4[i].rule_hdl);
}
else
{
IPACMERR("Failed adding lan2lan v4 flt rule %d\n", i);
res = IPACM_FAILURE;
goto fail;
}
}
}
}
else if(iptype == IPA_IP_v6)
{
flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
flt_rule.rule.attrib.u.v6.src_addr_mask[0] = ~0;
flt_rule.rule.attrib.u.v6.src_addr_mask[1] = ~0;
flt_rule.rule.attrib.u.v6.src_addr_mask[2] = ~0;
flt_rule.rule.attrib.u.v6.src_addr_mask[3] = ~0;
flt_rule.rule.attrib.u.v6.src_addr[0] = ~0;
flt_rule.rule.attrib.u.v6.src_addr[1] = ~0;
flt_rule.rule.attrib.u.v6.src_addr[2] = ~0;
flt_rule.rule.attrib.u.v6.src_addr[3] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr_mask[0] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr_mask[1] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr_mask[2] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr_mask[3] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr[0] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr[1] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr[2] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr[3] = ~0;
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_add));
}
if (false == m_filtering.AddFilteringRule(pFilteringTable))
{
IPACMERR("Error adding dummy lan2lan v6 flt rule\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
flt_rule_count_v6 += MAX_OFFLOAD_PAIR;
/* copy filter rule hdls */
for (int i = 0; i < MAX_OFFLOAD_PAIR; i++)
{
if (pFilteringTable->rules[i].status == 0)
{
lan2lan_flt_rule_hdl_v6[i].rule_hdl = pFilteringTable->rules[i].flt_rule_hdl;
IPACMDBG("Lan2lan v6 flt rule %d hdl:0x%x\n", i, lan2lan_flt_rule_hdl_v6[i].rule_hdl);
}
else
{
IPACMERR("Failed adding lan2lan v6 flt rule %d\n", i);
res = IPACM_FAILURE;
goto fail;
}
}
}
}
else
{
IPACMERR("IP type is not expected.\n");
goto fail;
}
fail:
free(pFilteringTable);
return res;
}
int IPACM_Lan::del_lan2lan_flt_rule(ipa_ip_type iptype, uint32_t rule_hdl)
{
int i;
IPACMDBG("Del lan2lan flt rule with IP type: %d hdl: %d\n", iptype, rule_hdl);
if(iptype == IPA_IP_v4)
{
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
if(lan2lan_flt_rule_hdl_v4[i].rule_hdl == rule_hdl)
{
if(reset_to_dummy_flt_rule(IPA_IP_v4, rule_hdl) == IPACM_FAILURE)
{
IPACMERR("Failed to delete lan2lan v4 flt rule %d\n", rule_hdl);
return IPACM_FAILURE;
}
IPACMDBG("Deleted lan2lan v4 flt rule %d\n", rule_hdl);
lan2lan_flt_rule_hdl_v4[i].valid = false;
num_lan2lan_flt_rule_v4--;
break;
}
}
if(i == MAX_OFFLOAD_PAIR) //not finding the rule
{
IPACMERR("The rule is not found.\n");
return IPACM_FAILURE;
}
}
else if(iptype == IPA_IP_v6)
{
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
if(lan2lan_flt_rule_hdl_v6[i].rule_hdl == rule_hdl)
{
if(reset_to_dummy_flt_rule(IPA_IP_v6, rule_hdl) == IPACM_FAILURE)
{
IPACMERR("Failed to delete lan2lan v6 flt rule %d\n", rule_hdl);
return IPACM_FAILURE;
}
IPACMDBG("Deleted lan2lan v6 flt rule %d\n", rule_hdl);
lan2lan_flt_rule_hdl_v6[i].valid = false;
num_lan2lan_flt_rule_v6--;
break;
}
}
if(i == MAX_OFFLOAD_PAIR) //not finding the rule
{
IPACMERR("The rule is not found.\n");
return IPACM_FAILURE;
}
}
else
{
IPACMERR("IP type is not expected.\n");
return IPACM_FAILURE;
}
return IPACM_SUCCESS;
}
int IPACM_Lan::reset_to_dummy_flt_rule(ipa_ip_type iptype, uint32_t rule_hdl)
{
int len, res = IPACM_SUCCESS;
struct ipa_flt_rule_mdfy flt_rule;
struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
IPACMDBG("Reset flt rule to dummy, IP type: %d, hdl: %d\n", iptype, rule_hdl);
len = sizeof(struct ipa_ioc_mdfy_flt_rule) + sizeof(struct ipa_flt_rule_mdfy);
pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
if (pFilteringTable == NULL)
{
IPACMERR("Error allocate flt rule memory...\n");
return IPACM_FAILURE;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ip = iptype;
pFilteringTable->num_rules = 1;
memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_mdfy));
flt_rule.status = -1;
flt_rule.rule_hdl = rule_hdl;
flt_rule.rule.retain_hdr = 0;
flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
if(iptype == IPA_IP_v4)
{
IPACMDBG("Reset IPv4 flt rule to dummy\n");
flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
flt_rule.rule.attrib.u.v4.dst_addr = ~0;
flt_rule.rule.attrib.u.v4.dst_addr_mask = ~0;
flt_rule.rule.attrib.u.v4.src_addr = ~0;
flt_rule.rule.attrib.u.v4.src_addr_mask = ~0;
memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
{
IPACMERR("Error modifying filtering rule.\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
IPACMDBG("Flt rule reset to dummy, hdl: 0x%x, status: %d\n", pFilteringTable->rules[0].rule_hdl,
pFilteringTable->rules[0].status);
}
}
else if(iptype == IPA_IP_v6)
{
IPACMDBG("Reset IPv6 flt rule to dummy\n");
flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
flt_rule.rule.attrib.u.v6.src_addr[0] = ~0;
flt_rule.rule.attrib.u.v6.src_addr[1] = ~0;
flt_rule.rule.attrib.u.v6.src_addr[2] = ~0;
flt_rule.rule.attrib.u.v6.src_addr[3] = ~0;
flt_rule.rule.attrib.u.v6.src_addr_mask[0] = ~0;
flt_rule.rule.attrib.u.v6.src_addr_mask[1] = ~0;
flt_rule.rule.attrib.u.v6.src_addr_mask[2] = ~0;
flt_rule.rule.attrib.u.v6.src_addr_mask[3] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr[0] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr[1] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr[2] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr[3] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr_mask[0] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr_mask[1] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr_mask[2] = ~0;
flt_rule.rule.attrib.u.v6.dst_addr_mask[3] = ~0;
memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
{
IPACMERR("Error modifying filtering rule.\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
IPACMDBG("Flt rule reset to dummy, hdl: 0x%x, status: %d\n", pFilteringTable->rules[0].rule_hdl,
pFilteringTable->rules[0].status);
}
}
else
{
IPACMERR("IP type is not expected.\n");
res = IPACM_FAILURE;
goto fail;
}
fail:
free(pFilteringTable);
return res;
}
int IPACM_Lan::add_lan2lan_hdr(ipa_ip_type iptype, uint8_t* src_mac, uint8_t* dst_mac, uint32_t* hdr_hdl)
{
if(tx_prop == NULL)
{
IPACMERR("There is no tx_prop, cannot add header.\n");
return IPACM_FAILURE;
}
if(src_mac == NULL || dst_mac == NULL)
{
IPACMERR("Either src_mac or dst_mac is null, cannot add header.\n");
return IPACM_FAILURE;
}
if(hdr_hdl == NULL)
{
IPACMERR("Header handle is empty.\n");
return IPACM_FAILURE;
}
int i, j, len;
int res = IPACM_SUCCESS;
char index[4];
struct ipa_ioc_copy_hdr sCopyHeader;
struct ipa_ioc_add_hdr *pHeader;
IPACMDBG("Get lan2lan header request, src_mac: 0x%02x%02x%02x%02x%02x%02x dst_mac: 0x%02x%02x%02x%02x%02x%02x\n",
src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5], dst_mac[0], dst_mac[1],
dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5]);
len = sizeof(struct ipa_ioc_add_hdr) + sizeof(struct ipa_hdr_add);
pHeader = (struct ipa_ioc_add_hdr *)malloc(len);
if (pHeader == NULL)
{
IPACMERR("Failed to allocate header\n");
return IPACM_FAILURE;
}
memset(pHeader, 0, len);
if(iptype == IPA_IP_v4)
{ /* copy partial header for v4*/
for(i=0; i<tx_prop->num_tx_props; i++)
{
if(tx_prop->tx[i].ip == IPA_IP_v4)
{
IPACMDBG("Got v4-header name from %d tx props\n", i);
memset(&sCopyHeader, 0, sizeof(sCopyHeader));
memcpy(sCopyHeader.name, tx_prop->tx[i].hdr_name, sizeof(sCopyHeader.name));
IPACMDBG("Header name: %s\n", sCopyHeader.name);
if(m_header.CopyHeader(&sCopyHeader) == false)
{
IPACMERR("Copy header failed\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("Header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
{
IPACMERR("Header oversize\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
memcpy(pHeader->hdr[0].hdr, sCopyHeader.hdr, sCopyHeader.hdr_len);
}
if(sCopyHeader.is_eth2_ofst_valid)
{
memcpy(&pHeader->hdr[0].hdr[sCopyHeader.eth2_ofst], dst_mac, IPA_MAC_ADDR_SIZE);
memcpy(&pHeader->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE], src_mac, IPA_MAC_ADDR_SIZE);
}
else
{
IPACMERR("Ethernet 2 header offset is invalid.\n");
}
pHeader->commit = true;
pHeader->num_hdrs = 1;
memset(pHeader->hdr[0].name, 0, sizeof(pHeader->hdr[0].name));
strlcpy(pHeader->hdr[0].name, IPA_LAN_TO_LAN_USB_HDR_NAME_V4, sizeof(pHeader->hdr[0].name));
for(j=0; j<MAX_OFFLOAD_PAIR; j++)
{
if( lan2lan_hdr_hdl_v4[j].valid == false)
{
IPACMDBG("Construct lan2lan hdr with index %d.\n", j);
break;
}
}
if(j == MAX_OFFLOAD_PAIR)
{
IPACMERR("Failed to find an available hdr index.\n");
res = IPACM_FAILURE;
goto fail;
}
lan2lan_hdr_hdl_v4[j].valid = true;
snprintf(index,sizeof(index), "%d", j);
if (strlcat(pHeader->hdr[0].name, index, sizeof(pHeader->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
{
IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeader->hdr[0].name));
res = IPACM_FAILURE;
goto fail;
}
pHeader->hdr[0].hdr_len = sCopyHeader.hdr_len;
pHeader->hdr[0].is_partial = 0;
pHeader->hdr[0].hdr_hdl = -1;
pHeader->hdr[0].status = -1;
if (m_header.AddHeader(pHeader) == false || pHeader->hdr[0].status != 0)
{
IPACMERR("Ioctl IPA_IOC_ADD_HDR failed with status: %d\n", pHeader->hdr[0].status);
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("Installed v4 full header %s header handle 0x%08x\n", pHeader->hdr[0].name,
pHeader->hdr[0].hdr_hdl);
*hdr_hdl = pHeader->hdr[0].hdr_hdl;
lan2lan_hdr_hdl_v4[j].hdr_hdl = pHeader->hdr[0].hdr_hdl;
break;
}
}
}
else if(iptype == IPA_IP_v6)
{ /* copy partial header for v6*/
for(i=0; i<tx_prop->num_tx_props; i++)
{
if(tx_prop->tx[i].ip == IPA_IP_v6)
{
IPACMDBG("Got v6-header name from %d tx props\n", i);
memset(&sCopyHeader, 0, sizeof(sCopyHeader));
memcpy(sCopyHeader.name, tx_prop->tx[i].hdr_name, sizeof(sCopyHeader.name));
IPACMDBG("Header name: %s\n", sCopyHeader.name);
if(m_header.CopyHeader(&sCopyHeader) == false)
{
IPACMERR("Copy header failed\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("Header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
{
IPACMERR("Header oversize\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
memcpy(pHeader->hdr[0].hdr, sCopyHeader.hdr, sCopyHeader.hdr_len);
}
if(sCopyHeader.is_eth2_ofst_valid)
{
memcpy(&pHeader->hdr[0].hdr[sCopyHeader.eth2_ofst], dst_mac, IPA_MAC_ADDR_SIZE);
memcpy(&pHeader->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE], src_mac, IPA_MAC_ADDR_SIZE);
}
else
{
IPACMERR("Ethernet 2 header offset is invalid.\n");
}
pHeader->commit = true;
pHeader->num_hdrs = 1;
memset(pHeader->hdr[0].name, 0, sizeof(pHeader->hdr[0].name));
strlcpy(pHeader->hdr[0].name, IPA_LAN_TO_LAN_USB_HDR_NAME_V6, sizeof(pHeader->hdr[0].name));
for(j=0; j<MAX_OFFLOAD_PAIR; j++)
{
if( lan2lan_hdr_hdl_v6[j].valid == false)
{
IPACMDBG("Construct lan2lan hdr with index %d.\n", j);
break;
}
}
if(j == MAX_OFFLOAD_PAIR)
{
IPACMERR("Failed to find an available hdr index.\n");
res = IPACM_FAILURE;
goto fail;
}
lan2lan_hdr_hdl_v6[j].valid = true;
snprintf(index,sizeof(index), "%d", j);
if (strlcat(pHeader->hdr[0].name, index, sizeof(pHeader->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
{
IPACMERR(" header name construction failed exceed length (%d)\n", strlen(pHeader->hdr[0].name));
res = IPACM_FAILURE;
goto fail;
}
pHeader->hdr[0].hdr_len = sCopyHeader.hdr_len;
pHeader->hdr[0].is_partial = 0;
pHeader->hdr[0].hdr_hdl = -1;
pHeader->hdr[0].status = -1;
if (m_header.AddHeader(pHeader) == false || pHeader->hdr[0].status != 0)
{
IPACMERR("Ioctl IPA_IOC_ADD_HDR failed with status: %d\n", pHeader->hdr[0].status);
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("Installed v6 full header %s header handle 0x%08x\n", pHeader->hdr[0].name,
pHeader->hdr[0].hdr_hdl);
*hdr_hdl = pHeader->hdr[0].hdr_hdl;
lan2lan_hdr_hdl_v6[j].hdr_hdl = pHeader->hdr[0].hdr_hdl;
break;
}
}
}
else
{
IPACMERR("IP type is not expected.\n");
}
fail:
free(pHeader);
return res;
}
int IPACM_Lan::del_lan2lan_hdr(ipa_ip_type iptype, uint32_t hdr_hdl)
{
int i;
if (m_header.DeleteHeaderHdl(hdr_hdl) == false)
{
IPACMERR("Failed to delete header %d\n", hdr_hdl);
return IPACM_FAILURE;
}
IPACMDBG("Deleted header %d\n", hdr_hdl);
if(iptype == IPA_IP_v4)
{
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
if(lan2lan_hdr_hdl_v4[i].hdr_hdl == hdr_hdl)
{
lan2lan_hdr_hdl_v4[i].valid = false;
break;
}
}
if(i == MAX_OFFLOAD_PAIR)
{
IPACMERR("Failed to find corresponding hdr hdl.\n");
return IPACM_FAILURE;
}
}
else if(iptype == IPA_IP_v6)
{
for(i=0; i<MAX_OFFLOAD_PAIR; i++)
{
if(lan2lan_hdr_hdl_v6[i].hdr_hdl == hdr_hdl)
{
lan2lan_hdr_hdl_v6[i].valid = false;
break;
}
}
if(i == MAX_OFFLOAD_PAIR)
{
IPACMERR("Failed to find corresponding hdr hdl.\n");
return IPACM_FAILURE;
}
}
else
{
IPACMERR("IP type is not expected.\n");
return IPACM_FAILURE;
}
return IPACM_SUCCESS;
}
int IPACM_Lan::add_lan2lan_rt_rule(ipa_ip_type iptype, uint32_t src_v4_addr, uint32_t dst_v4_addr,
uint32_t* src_v6_addr, uint32_t* dst_v6_addr, uint32_t hdr_hdl, lan_to_lan_rt_rule_hdl* rule_hdl)
{
struct ipa_ioc_add_rt_rule *rt_rule;
struct ipa_rt_rule_add *rt_rule_entry;
uint32_t tx_index;
int len;
int res = IPACM_SUCCESS;
IPACMDBG("Got a new lan2lan rt rule with IP type: %d\n", iptype);
if(rule_hdl == NULL)
{
IPACMERR("Rule hdl is empty.\n");
return IPACM_FAILURE;
}
memset(rule_hdl, 0, sizeof(lan_to_lan_rt_rule_hdl));
if(tx_prop == NULL)
{
IPACMDBG("There is no tx_prop for iface %s, not able to add lan2lan routing rule.\n", dev_name);
return IPACM_FAILURE;
}
len = sizeof(struct ipa_ioc_add_rt_rule) + sizeof(struct ipa_rt_rule_add);
rt_rule = (struct ipa_ioc_add_rt_rule *)malloc(len);
if (!rt_rule)
{
IPACMERR("Failed to allocate memory for rt rule\n");
return IPACM_FAILURE;
}
memset(rt_rule, 0, len);
rt_rule->commit = 1;
rt_rule->num_rules = 1;
rt_rule->ip = iptype;
if(iptype == IPA_IP_v4)
{
IPACMDBG("src_v4_addr: 0x%08x dst_v4_addr: 0x%08x\n", src_v4_addr, dst_v4_addr);
strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v4.name);
rt_rule_entry = &rt_rule->rules[0];
rt_rule_entry->at_rear = false;
rt_rule_entry->rt_rule_hdl = 0;
rt_rule_entry->status = -1;
for (tx_index = 0; tx_index<iface_query->num_tx_props; tx_index++)
{
if(tx_prop->tx[tx_index].ip != IPA_IP_v4)
{
IPACMDBG("Tx:%d, iptype: %d conflict ip-type: %d bypass\n",
tx_index, tx_prop->tx[tx_index].ip, IPA_IP_v4);
continue;
}
rt_rule_entry->rule.hdr_hdl = hdr_hdl;
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_SRC_ADDR;
rt_rule_entry->rule.attrib.u.v4.src_addr = src_v4_addr;
rt_rule_entry->rule.attrib.u.v4.src_addr_mask = 0xFFFFFFFF;
rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
rt_rule_entry->rule.attrib.u.v4.dst_addr = dst_v4_addr;
rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
if(m_routing.AddRoutingRule(rt_rule) == false)
{
IPACMERR("Routing rule addition failed\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("Added rt rule hdl: 0x%08x\n", rt_rule_entry->rt_rule_hdl);
rule_hdl->rule_hdl[rule_hdl->num_rule] = rt_rule_entry->rt_rule_hdl;
rule_hdl->num_rule++;
}
}
else if(iptype == IPA_IP_v6)
{
if(src_v6_addr == NULL || dst_v6_addr == NULL)
{
IPACMERR("Got IPv6 rt rule but without IPv6 src/dst addr.\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("src_v6_addr: 0x%08x%08x%08x%08x, dst_v6_addr: 0x%08x%08x%08x%08x\n", src_v6_addr[0], src_v6_addr[1],
src_v6_addr[2], src_v6_addr[3], dst_v6_addr[0], dst_v6_addr[1], dst_v6_addr[2], dst_v6_addr[3]);
strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan2lan_v6.name);
rt_rule_entry = &rt_rule->rules[0];
rt_rule_entry->at_rear = false;
rt_rule_entry->rt_rule_hdl = 0;
rt_rule_entry->status = -1;
for (tx_index = 0; tx_index<iface_query->num_tx_props; tx_index++)
{
if(tx_prop->tx[tx_index].ip != IPA_IP_v6)
{
IPACMDBG("Tx:%d, iptype: %d conflict ip-type: %d bypass\n",
tx_index, tx_prop->tx[tx_index].ip, IPA_IP_v6);
continue;
}
rt_rule_entry->rule.hdr_hdl = hdr_hdl;
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_SRC_ADDR;
rt_rule_entry->rule.attrib.u.v6.src_addr[0] = src_v6_addr[0];
rt_rule_entry->rule.attrib.u.v6.src_addr[1] = src_v6_addr[1];
rt_rule_entry->rule.attrib.u.v6.src_addr[2] = src_v6_addr[2];
rt_rule_entry->rule.attrib.u.v6.src_addr[3] = src_v6_addr[3];
rt_rule_entry->rule.attrib.u.v6.src_addr_mask[0] = 0xFFFFFFFF;
rt_rule_entry->rule.attrib.u.v6.src_addr_mask[1] = 0xFFFFFFFF;
rt_rule_entry->rule.attrib.u.v6.src_addr_mask[2] = 0xFFFFFFFF;
rt_rule_entry->rule.attrib.u.v6.src_addr_mask[3] = 0xFFFFFFFF;
rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = dst_v6_addr[0];
rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = dst_v6_addr[1];
rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = dst_v6_addr[2];
rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = dst_v6_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;
if(m_routing.AddRoutingRule(rt_rule) == false)
{
IPACMERR("Routing rule addition failed\n");
res = IPACM_FAILURE;
goto fail;
}
IPACMDBG("Added rt rule hdl: 0x%08x\n", rt_rule_entry->rt_rule_hdl);
rule_hdl->rule_hdl[rule_hdl->num_rule] = rt_rule_entry->rt_rule_hdl;
rule_hdl->num_rule++;
}
}
else
{
IPACMERR("IP type is not expected.\n");
}
fail:
free(rt_rule);
return res;
}
int IPACM_Lan::del_lan2lan_rt_rule(ipa_ip_type iptype, lan_to_lan_rt_rule_hdl rule_hdl)
{
if(rule_hdl.num_rule <= 0 || rule_hdl.num_rule > MAX_NUM_PROP)
{
IPACMERR("The number of rule handles are not correct.\n");
return IPACM_FAILURE;
}
int i, res = IPACM_SUCCESS;
IPACMDBG("Get %d rule handles with IP type %d\n", rule_hdl.num_rule, iptype);
for(i=0; i<rule_hdl.num_rule; i++)
{
if(m_routing.DeleteRoutingHdl(rule_hdl.rule_hdl[i], iptype) == false)
{
IPACMERR("Failed to delete routing rule hdl %d.\n", rule_hdl.rule_hdl[i]);
res = IPACM_FAILURE;
}
IPACMDBG("Deleted routing rule handle %d\n",rule_hdl.rule_hdl[i]);
}
return res;
}
void IPACM_Lan::post_del_self_evt()
{
ipacm_cmd_q_data evt;
ipacm_event_data_fid* fid;
fid = (ipacm_event_data_fid*)malloc(sizeof(ipacm_event_data_fid));
if(fid == NULL)
{
IPACMERR("Failed to allocate fid memory.\n");
return;
}
memset(fid, 0, sizeof(ipacm_event_data_fid));
memset(&evt, 0, sizeof(ipacm_cmd_q_data));
fid->if_index = ipa_if_num;
evt.evt_data = (void*)fid;
evt.event = IPA_LAN_DELETE_SELF;
IPACMDBG("Posting event IPA_LAN_DELETE_SELF\n");
IPACM_EvtDispatcher::PostEvt(&evt);
}
void IPACM_Lan::post_lan2lan_client_disconnect_msg()
{
int i, j;
ipacm_cmd_q_data evt_data;
ipacm_event_lan_client* lan_client;
for (i = 0; i < num_eth_client; i++)
{
if(get_client_memptr(eth_client, i)->ipv4_set == true)
{
lan_client = (ipacm_event_lan_client*)malloc(sizeof(ipacm_event_lan_client));
if(lan_client == NULL)
{
IPACMERR("Failed to allocate memory.\n");
return;
}
memset(lan_client, 0, sizeof(ipacm_event_lan_client));
lan_client->iptype = IPA_IP_v4;
lan_client->ipv4_addr = get_client_memptr(eth_client, i)->v4_addr;
lan_client->p_iface = this;
memset(&evt_data, 0, sizeof(ipacm_cmd_q_data));
evt_data.evt_data = (void*)lan_client;
evt_data.event = IPA_LAN_CLIENT_DISCONNECT;
IPACMDBG("Posting event IPA_LAN_CLIENT_DISCONNECT\n");
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
for (j = 0; j < get_client_memptr(eth_client, i)->ipv6_set; j++)
{
lan_client = (ipacm_event_lan_client*)malloc(sizeof(ipacm_event_lan_client));
if(lan_client == NULL)
{
IPACMERR("Failed to allocate memory.\n");
return;
}
memset(lan_client, 0, sizeof(ipacm_event_lan_client));
lan_client->iptype = IPA_IP_v6;
lan_client->ipv6_addr[0] = get_client_memptr(eth_client, i)->v6_addr[j][0];
lan_client->ipv6_addr[0] = get_client_memptr(eth_client, i)->v6_addr[j][0];
lan_client->ipv6_addr[0] = get_client_memptr(eth_client, i)->v6_addr[j][0];
lan_client->ipv6_addr[0] = get_client_memptr(eth_client, i)->v6_addr[j][0];
lan_client->p_iface = this;
memset(&evt_data, 0, sizeof(ipacm_cmd_q_data));
evt_data.evt_data = (void*)lan_client;
evt_data.event = IPA_LAN_CLIENT_DISCONNECT;
IPACMDBG("Posting event IPA_LAN_CLIENT_DISCONNECT\n");
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
} /* end of for loop */
return;
}
void IPACM_Lan::install_tcp_ctl_flt_rule(ipa_ip_type iptype)
{
if (rx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return;
}
int len, i;
struct ipa_flt_rule_add flt_rule;
ipa_ioc_add_flt_rule* pFilteringTable;
len = sizeof(struct ipa_ioc_add_flt_rule) + NUM_TCP_CTL_FLT_RULE * sizeof(struct ipa_flt_rule_add);
pFilteringTable = (struct ipa_ioc_add_flt_rule *)malloc(len);
if (pFilteringTable == NULL)
{
IPACMERR("Error allocate flt table memory...\n");
return;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ip = iptype;
pFilteringTable->ep = rx_prop->rx[0].src_pipe;
pFilteringTable->global = false;
pFilteringTable->num_rules = NUM_TCP_CTL_FLT_RULE;
memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_add));
flt_rule.at_rear = true;
flt_rule.flt_rule_hdl = -1;
flt_rule.status = -1;
flt_rule.rule.retain_hdr = 1;
flt_rule.rule.to_uc = 0;
flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
flt_rule.rule.eq_attrib_type = 1;
flt_rule.rule.eq_attrib.rule_eq_bitmap = 0;
flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
flt_rule.rule.eq_attrib.metadata_meq32_present = 1;
flt_rule.rule.eq_attrib.metadata_meq32.offset = 0;
flt_rule.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
flt_rule.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
flt_rule.rule.eq_attrib.protocol_eq_present = 1;
flt_rule.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
flt_rule.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
flt_rule.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
/* add TCP FIN rule*/
flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_add));
/* add TCP SYN rule*/
flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_SYN_SHIFT);
flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_SYN_SHIFT);
memcpy(&(pFilteringTable->rules[1]), &flt_rule, sizeof(struct ipa_flt_rule_add));
/* add TCP RST rule*/
flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
flt_rule.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
memcpy(&(pFilteringTable->rules[2]), &flt_rule, sizeof(struct ipa_flt_rule_add));
if (false == m_filtering.AddFilteringRule(pFilteringTable))
{
IPACMERR("Error adding tcp control flt rule\n");
goto fail;
}
else
{
if(iptype == IPA_IP_v4)
{
for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
{
flt_rule_count_v4++;
tcp_ctl_flt_rule_hdl_v4[i] = pFilteringTable->rules[i].flt_rule_hdl;
}
}
else
{
for(i=0; i<NUM_TCP_CTL_FLT_RULE; i++)
{
flt_rule_count_v6++;
tcp_ctl_flt_rule_hdl_v6[i] = pFilteringTable->rules[i].flt_rule_hdl;
}
}
}
fail:
free(pFilteringTable);
return;
}
int IPACM_Lan::add_dummy_private_subnet_flt_rule(ipa_ip_type iptype)
{
if(rx_prop == NULL)
{
IPACMDBG("There is no rx_prop for iface %s, not able to add dummy private subnet filtering rule.\n", dev_name);
return 0;
}
if(iptype == IPA_IP_v6)
{
IPACMDBG("There is no ipv6 dummy filter rules needed for iface %s\n", dev_name);
return 0;
}
int i, len, res = IPACM_SUCCESS;
struct ipa_flt_rule_add flt_rule;
ipa_ioc_add_flt_rule* pFilteringTable;
len = sizeof(struct ipa_ioc_add_flt_rule) + IPA_MAX_PRIVATE_SUBNET_ENTRIES * sizeof(struct ipa_flt_rule_add);
pFilteringTable = (struct ipa_ioc_add_flt_rule *)malloc(len);
if (pFilteringTable == NULL)
{
IPACMERR("Error allocate flt table memory...\n");
return IPACM_FAILURE;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ep = rx_prop->rx[0].src_pipe;
pFilteringTable->global = false;
pFilteringTable->ip = iptype;
pFilteringTable->num_rules = IPA_MAX_PRIVATE_SUBNET_ENTRIES;
memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_add));
flt_rule.rule.retain_hdr = 0;
flt_rule.at_rear = true;
flt_rule.flt_rule_hdl = -1;
flt_rule.status = -1;
flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
sizeof(flt_rule.rule.attrib));
if(iptype == IPA_IP_v4)
{
flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
flt_rule.rule.attrib.u.v4.src_addr_mask = ~0;
flt_rule.rule.attrib.u.v4.src_addr = ~0;
flt_rule.rule.attrib.u.v4.dst_addr_mask = ~0;
flt_rule.rule.attrib.u.v4.dst_addr = ~0;
for(i=0; i<IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
{
memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_add));
}
if (false == m_filtering.AddFilteringRule(pFilteringTable))
{
IPACMERR("Error adding dummy private subnet v4 flt rule\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
flt_rule_count_v4 += IPA_MAX_PRIVATE_SUBNET_ENTRIES;
/* copy filter rule hdls */
for (int i = 0; i < IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
{
if (pFilteringTable->rules[i].status == 0)
{
private_fl_rule_hdl[i] = pFilteringTable->rules[i].flt_rule_hdl;
IPACMDBG("Private subnet v4 flt rule %d hdl:0x%x\n", i, private_fl_rule_hdl[i]);
}
else
{
IPACMERR("Failed adding lan2lan v4 flt rule %d\n", i);
res = IPACM_FAILURE;
goto fail;
}
}
}
}
fail:
free(pFilteringTable);
return res;
}
int IPACM_Lan::handle_private_subnet_android(ipa_ip_type iptype)
{
int i, len, res = IPACM_SUCCESS, offset;
struct ipa_flt_rule_mdfy flt_rule;
struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
if (rx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if(iptype == IPA_IP_v6)
{
IPACMDBG("There is no ipv6 dummy filter rules needed for iface %s\n", dev_name);
return 0;
}
else
{
for(i=0; i<IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
{
reset_to_dummy_flt_rule(IPA_IP_v4, private_fl_rule_hdl[i]);
}
len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_mdfy);
pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
if (!pFilteringTable)
{
IPACMERR("Failed to allocate ipa_ioc_mdfy_flt_rule memory...\n");
return IPACM_FAILURE;
}
memset(pFilteringTable, 0, len);
pFilteringTable->commit = 1;
pFilteringTable->ip = iptype;
pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
/* Make LAN-traffic always go A5, use default IPA-RT table */
if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4))
{
IPACMERR("Failed to get routing table handle.\n");
res = IPACM_FAILURE;
goto fail;
}
memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_mdfy));
flt_rule.status = -1;
flt_rule.rule.retain_hdr = 1;
flt_rule.rule.to_uc = 0;
flt_rule.rule.action = IPA_PASS_TO_ROUTING;
flt_rule.rule.eq_attrib_type = 0;
flt_rule.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
IPACMDBG("Private filter rule use table: %s\n",IPACM_Iface::ipacmcfg->rt_tbl_default_v4.name);
memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule.rule.attrib));
flt_rule.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
{
flt_rule.rule_hdl = private_fl_rule_hdl[i];
flt_rule.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
flt_rule.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
IPACMDBG(" IPACM private subnet_addr as: 0x%x entry(%d)\n", flt_rule.rule.attrib.u.v4.dst_addr, i);
}
if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
{
IPACMERR("Failed to modify private subnet filtering rules.\n");
res = IPACM_FAILURE;
goto fail;
}
}
fail:
if(pFilteringTable != NULL)
{
free(pFilteringTable);
}
return res;
}