Initial Commit4

This commit is contained in:
MandySingh3
2017-04-03 03:20:44 +05:30
parent bc8e833c07
commit 7beda1dfbc
214 changed files with 50630 additions and 45 deletions

View File

@@ -0,0 +1,98 @@
BOARD_PLATFORM_LIST := msm8916
BOARD_PLATFORM_LIST += msm8909
ifneq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true)
ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM)))
ifneq (, $(filter aarch64 arm arm64, $(TARGET_ARCH)))
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../inc
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ipanat/inc
ifeq ($(call is-platform-sdk-version-at-least,20),true)
LOCAL_C_INCLUDES += external/icu/icu4c/source/common
else
LOCAL_C_INCLUDES += external/icu4c/common
endif
LOCAL_C_INCLUDES += external/libxml2/include
LOCAL_C_INCLUDES += external/libnetfilter_conntrack/include
LOCAL_C_INCLUDES += external/libnfnetlink/include
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_CFLAGS := -v
LOCAL_CFLAGS += -DFEATURE_IPA_ANDROID
ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DDEBUG
endif
ifeq ($(TARGET_BOARD_PLATFORM),msmcobalt)
LOCAL_CFLAGS += -DFEATURE_IPA_V3
endif
filetoadd = bionic/libc/kernel/arch-arm/asm/posix_types.h
LOCAL_CFLAGS += $(shell if [ -a $(filetoadd) ] ; then echo -include $(filetoadd) ; fi ;)
filetoadd = bionic/libc/kernel/arch-arm/asm/byteorder.h
LOCAL_CFLAGS += $(shell if [ -a $(filetoadd) ] ; then echo -include $(filetoadd) ; fi ;)
LOCAL_SRC_FILES := IPACM_Main.cpp \
IPACM_EvtDispatcher.cpp \
IPACM_Config.cpp \
IPACM_CmdQueue.cpp \
IPACM_Filtering.cpp \
IPACM_Routing.cpp \
IPACM_Header.cpp \
IPACM_Lan.cpp \
IPACM_Iface.cpp \
IPACM_Wlan.cpp \
IPACM_Wan.cpp \
IPACM_IfaceManager.cpp \
IPACM_Neighbor.cpp \
IPACM_Netlink.cpp \
IPACM_Xml.cpp \
IPACM_Conntrack_NATApp.cpp\
IPACM_ConntrackClient.cpp \
IPACM_ConntrackListener.cpp \
IPACM_Log.cpp
LOCAL_MODULE := ipacm
LOCAL_CLANG := false
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libipanat
LOCAL_SHARED_LIBRARIES += libxml2
LOCAL_SHARED_LIBRARIES += libnfnetlink
LOCAL_SHARED_LIBRARIES += libnetfilter_conntrack
LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)
################################################################################
define ADD_TEST
include $(CLEAR_VARS)
LOCAL_MODULE := $1
LOCAL_SRC_FILES := $1
LOCAL_MODULE_CLASS := ipacm
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
include $(BUILD_PREBUILT)
endef
include $(CLEAR_VARS)
LOCAL_MODULE := IPACM_cfg.xml
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_MODULE_OWNER := ipacm
include $(BUILD_PREBUILT)
endif # $(TARGET_ARCH)
endif
endif

View File

@@ -0,0 +1,205 @@
/*
Copyright (c) 2013-2016, 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_CmdQueue.cpp
@brief
This file implements the IPAM Comment Queue functionality
@Author
Sunil
*/
#include <string.h>
#include "IPACM_CmdQueue.h"
#include "IPACM_Log.h"
#include "IPACM_Iface.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
MessageQueue* MessageQueue::inst_internal = NULL;
MessageQueue* MessageQueue::inst_external = NULL;
MessageQueue* MessageQueue::getInstanceInternal()
{
if(inst_internal == NULL)
{
inst_internal = new MessageQueue();
if(inst_internal == NULL)
{
IPACMERR("unable to create internal Message Queue instance\n");
return NULL;
}
}
return inst_internal;
}
MessageQueue* MessageQueue::getInstanceExternal()
{
if(inst_external == NULL)
{
inst_external = new MessageQueue();
if(inst_external == NULL)
{
IPACMERR("unable to create external Message Queue instance\n");
return NULL;
}
}
return inst_external;
}
void MessageQueue::enqueue(Message *item)
{
if(!Head)
{
Tail = item;
Head = item;
}
else
{
if(Tail == NULL)
{
IPACMDBG("Tail is null\n");
Head->setnext(item);
}
else
{
Tail->setnext(item);
}
Tail = item;
}
}
Message* MessageQueue::dequeue(void)
{
if(Head == NULL)
{
return NULL;
}
else
{
Message *tmp = Head;
Head = Head->getnext();
return tmp;
}
}
void* MessageQueue::Process(void *param)
{
MessageQueue *MsgQueueInternal = NULL;
MessageQueue *MsgQueueExternal = NULL;
Message *item = NULL;
IPACMDBG("MessageQueue::Process()\n");
MsgQueueInternal = MessageQueue::getInstanceInternal();
if(MsgQueueInternal == NULL)
{
IPACMERR("unable to start internal cmd queue process\n");
return NULL;
}
MsgQueueExternal = MessageQueue::getInstanceExternal();
if(MsgQueueExternal == NULL)
{
IPACMERR("unable to start external cmd queue process\n");
return NULL;
}
while(1)
{
if(pthread_mutex_lock(&mutex) != 0)
{
IPACMERR("unable to lock the mutex\n");
return NULL;
}
item = MsgQueueInternal->dequeue();
if(item == NULL)
{
item = MsgQueueExternal->dequeue();
if(item)
{
IPACMDBG("Get event %s from external queue.\n",
IPACM_Iface::ipacmcfg->getEventName(item->evt.data.event));
}
}
else
{
IPACMDBG("Get event %s from internal queue.\n",
IPACM_Iface::ipacmcfg->getEventName(item->evt.data.event));
}
if(item == NULL)
{
IPACMDBG("Waiting for Message\n");
if(pthread_cond_wait(&cond_var, &mutex) != 0)
{
IPACMERR("unable to lock the mutex\n");
if(pthread_mutex_unlock(&mutex) != 0)
{
IPACMERR("unable to unlock the mutex\n");
return NULL;
}
return NULL;
}
if(pthread_mutex_unlock(&mutex) != 0)
{
IPACMERR("unable to unlock the mutex\n");
return NULL;
}
}
else
{
if(pthread_mutex_unlock(&mutex) != 0)
{
IPACMERR("unable to unlock the mutex\n");
return NULL;
}
IPACMDBG("Processing item %p event ID: %d\n",item,item->evt.data.event);
item->evt.callback_ptr(&item->evt.data);
delete item;
item = NULL;
}
} /* Go forever until a termination indication is received */
}

View File

@@ -0,0 +1,824 @@
/*
Copyright (c) 2013-2016, 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_Config.cpp
@brief
This file implements the IPACM Configuration from XML file
@Author
Skylar Chang
*/
#include <IPACM_Config.h>
#include <IPACM_Log.h>
#include <IPACM_Iface.h>
#include <sys/ioctl.h>
#include <fcntl.h>
IPACM_Config *IPACM_Config::pInstance = NULL;
const char *IPACM_Config::DEVICE_NAME = "/dev/ipa";
const char *IPACM_Config::DEVICE_NAME_ODU = "/dev/odu_ipa_bridge";
#define __stringify(x...) #x
const char *ipacm_event_name[] = {
__stringify(IPA_CFG_CHANGE_EVENT), /* NULL */
__stringify(IPA_PRIVATE_SUBNET_CHANGE_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_FIREWALL_CHANGE_EVENT), /* NULL */
__stringify(IPA_LINK_UP_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_LINK_DOWN_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_USB_LINK_UP_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_BRIDGE_LINK_UP_EVENT), /* ipacm_event_data_all */
__stringify(IPA_WAN_EMBMS_LINK_UP_EVENT), /* ipacm_event_data_mac */
__stringify(IPA_ADDR_ADD_EVENT), /* ipacm_event_data_addr */
__stringify(IPA_ADDR_DEL_EVENT), /* no use */
__stringify(IPA_ROUTE_ADD_EVENT), /* ipacm_event_data_addr */
__stringify(IPA_ROUTE_DEL_EVENT), /* ipacm_event_data_addr */
__stringify(IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_WLAN_AP_LINK_UP_EVENT), /* ipacm_event_data_mac */
__stringify(IPA_WLAN_STA_LINK_UP_EVENT), /* ipacm_event_data_mac */
__stringify(IPA_WLAN_LINK_DOWN_EVENT), /* ipacm_event_data_mac */
__stringify(IPA_WLAN_CLIENT_ADD_EVENT), /* ipacm_event_data_mac */
__stringify(IPA_WLAN_CLIENT_ADD_EVENT_EX), /* ipacm_event_data_wlan_ex */
__stringify(IPA_WLAN_CLIENT_DEL_EVENT), /* ipacm_event_data_mac */
__stringify(IPA_WLAN_CLIENT_POWER_SAVE_EVENT), /* ipacm_event_data_mac */
__stringify(IPA_WLAN_CLIENT_RECOVER_EVENT), /* ipacm_event_data_mac */
__stringify(IPA_NEW_NEIGH_EVENT), /* ipacm_event_data_all */
__stringify(IPA_DEL_NEIGH_EVENT), /* ipacm_event_data_all */
__stringify(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT), /* ipacm_event_data_all */
__stringify(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT), /* ipacm_event_data_all */
__stringify(IPA_SW_ROUTING_ENABLE), /* NULL */
__stringify(IPA_SW_ROUTING_DISABLE), /* NULL */
__stringify(IPA_PROCESS_CT_MESSAGE), /* ipacm_ct_evt_data */
__stringify(IPA_PROCESS_CT_MESSAGE_V6), /* ipacm_ct_evt_data */
__stringify(IPA_LAN_TO_LAN_NEW_CONNECTION), /* ipacm_event_connection */
__stringify(IPA_LAN_TO_LAN_DEL_CONNECTION), /* ipacm_event_connection */
__stringify(IPA_WLAN_SWITCH_TO_SCC), /* No Data */
__stringify(IPA_WLAN_SWITCH_TO_MCC), /* No Data */
__stringify(IPA_CRADLE_WAN_MODE_SWITCH), /* ipacm_event_cradle_wan_mode */
__stringify(IPA_WAN_XLAT_CONNECT_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_TETHERING_STATS_UPDATE_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_NETWORK_STATS_UPDATE_EVENT), /* ipacm_event_data_fid */
__stringify(IPA_EXTERNAL_EVENT_MAX),
__stringify(IPA_HANDLE_WAN_UP), /* ipacm_event_iface_up */
__stringify(IPA_HANDLE_WAN_DOWN), /* ipacm_event_iface_up */
__stringify(IPA_HANDLE_WAN_UP_V6), /* NULL */
__stringify(IPA_HANDLE_WAN_DOWN_V6), /* NULL */
__stringify(IPA_HANDLE_WAN_UP_TETHER), /* ipacm_event_iface_up_tehter */
__stringify(IPA_HANDLE_WAN_DOWN_TETHER), /* ipacm_event_iface_up_tehter */
__stringify(IPA_HANDLE_WAN_UP_V6_TETHER), /* ipacm_event_iface_up_tehter */
__stringify(IPA_HANDLE_WAN_DOWN_V6_TETHER), /* ipacm_event_iface_up_tehter */
__stringify(IPA_HANDLE_WLAN_UP), /* ipacm_event_iface_up */
__stringify(IPA_HANDLE_LAN_UP), /* ipacm_event_iface_up */
__stringify(IPA_ETH_BRIDGE_IFACE_UP), /* ipacm_event_eth_bridge*/
__stringify(IPA_ETH_BRIDGE_IFACE_DOWN), /* ipacm_event_eth_bridge*/
__stringify(IPA_ETH_BRIDGE_CLIENT_ADD), /* ipacm_event_eth_bridge*/
__stringify(IPA_ETH_BRIDGE_CLIENT_DEL), /* ipacm_event_eth_bridge*/
__stringify(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH), /* ipacm_event_eth_bridge*/
__stringify(IPA_LAN_DELETE_SELF), /* ipacm_event_data_fid */
__stringify(IPACM_EVENT_MAX),
};
IPACM_Config::IPACM_Config()
{
iface_table = NULL;
alg_table = NULL;
pNatIfaces = NULL;
memset(&ipa_client_rm_map_tbl, 0, sizeof(ipa_client_rm_map_tbl));
memset(&ipa_rm_tbl, 0, sizeof(ipa_rm_tbl));
ipa_rm_a2_check=0;
ipacm_odu_enable = false;
ipacm_odu_router_mode = false;
ipa_num_wlan_guest_ap = 0;
ipa_num_ipa_interfaces = 0;
ipa_num_private_subnet = 0;
ipa_num_alg_ports = 0;
ipa_nat_max_entries = 0;
ipa_nat_iface_entries = 0;
ipa_sw_rt_enable = false;
ipa_bridge_enable = false;
isMCC_Mode = false;
ipa_max_valid_rm_entry = 0;
memset(&rt_tbl_default_v4, 0, sizeof(rt_tbl_default_v4));
memset(&rt_tbl_lan_v4, 0, sizeof(rt_tbl_lan_v4));
memset(&rt_tbl_wan_v4, 0, sizeof(rt_tbl_wan_v4));
memset(&rt_tbl_v6, 0, sizeof(rt_tbl_v6));
memset(&rt_tbl_wan_v6, 0, sizeof(rt_tbl_wan_v6));
memset(&rt_tbl_wan_dl, 0, sizeof(rt_tbl_wan_dl));
memset(&rt_tbl_odu_v4, 0, sizeof(rt_tbl_odu_v4));
memset(&rt_tbl_odu_v6, 0, sizeof(rt_tbl_odu_v6));
memset(&ext_prop_v4, 0, sizeof(ext_prop_v4));
memset(&ext_prop_v6, 0, sizeof(ext_prop_v6));
qmap_id = ~0;
memset(flt_rule_count_v4, 0, (IPA_CLIENT_CONS - IPA_CLIENT_PROD)*sizeof(int));
memset(flt_rule_count_v6, 0, (IPA_CLIENT_CONS - IPA_CLIENT_PROD)*sizeof(int));
memset(bridge_mac, 0, IPA_MAC_ADDR_SIZE*sizeof(uint8_t));
IPACMDBG_H(" create IPACM_Config constructor\n");
return;
}
int IPACM_Config::Init(void)
{
/* Read IPACM Config file */
char IPACM_config_file[IPA_MAX_FILE_LEN];
IPACM_conf_t *cfg;
cfg = (IPACM_conf_t *)malloc(sizeof(IPACM_conf_t));
if(cfg == NULL)
{
IPACMERR("Unable to allocate cfg memory.\n");
return IPACM_FAILURE;
}
uint32_t subnet_addr;
uint32_t subnet_mask;
int i, ret = IPACM_SUCCESS;
struct in_addr in_addr_print;
m_fd = open(DEVICE_NAME, O_RDWR);
if (0 > m_fd)
{
IPACMERR("Failed opening %s.\n", DEVICE_NAME);
}
strncpy(IPACM_config_file, "/etc/IPACM_cfg.xml", sizeof(IPACM_config_file));
IPACMDBG_H("\n IPACM XML file is %s \n", IPACM_config_file);
if (IPACM_SUCCESS == ipacm_read_cfg_xml(IPACM_config_file, cfg))
{
IPACMDBG_H("\n IPACM XML read OK \n");
}
else
{
IPACMERR("\n IPACM XML read failed \n");
ret = IPACM_FAILURE;
goto fail;
}
/* Check wlan AP-AP access mode configuration */
if (cfg->num_wlan_guest_ap == 2)
{
IPACMDBG_H("IPACM_Config::Both wlan APs can not be configured in guest ap mode. \n");
IPACMDBG_H("IPACM_Config::configure both APs in full access mode or at least one in guest ap mode. \n");
ret = IPACM_FAILURE;
goto fail;
}
/* Construct IPACM Iface table */
ipa_num_ipa_interfaces = cfg->iface_config.num_iface_entries;
if (iface_table != NULL)
{
free(iface_table);
iface_table = NULL;
IPACMDBG_H("RESET IPACM_Config::iface_table\n");
}
iface_table = (ipa_ifi_dev_name_t *)calloc(ipa_num_ipa_interfaces,
sizeof(ipa_ifi_dev_name_t));
if(iface_table == NULL)
{
IPACMERR("Unable to allocate iface_table memory.\n");
ret = IPACM_FAILURE;
goto fail;
}
for (i = 0; i < cfg->iface_config.num_iface_entries; i++)
{
strncpy(iface_table[i].iface_name, cfg->iface_config.iface_entries[i].iface_name, sizeof(iface_table[i].iface_name));
iface_table[i].if_cat = cfg->iface_config.iface_entries[i].if_cat;
iface_table[i].if_mode = cfg->iface_config.iface_entries[i].if_mode;
iface_table[i].wlan_mode = cfg->iface_config.iface_entries[i].wlan_mode;
IPACMDBG_H("IPACM_Config::iface_table[%d] = %s, cat=%d, mode=%d wlan-mode=%d \n", i, iface_table[i].iface_name,
iface_table[i].if_cat, iface_table[i].if_mode, iface_table[i].wlan_mode);
/* copy bridge interface name to ipacmcfg */
if( iface_table[i].if_cat == VIRTUAL_IF)
{
strlcpy(ipa_virtual_iface_name, iface_table[i].iface_name, sizeof(ipa_virtual_iface_name));
IPACMDBG_H("ipa_virtual_iface_name(%s) \n", ipa_virtual_iface_name);
}
}
/* Construct IPACM Private_Subnet table */
memset(&private_subnet_table, 0, sizeof(private_subnet_table));
ipa_num_private_subnet = cfg->private_subnet_config.num_subnet_entries;
for (i = 0; i < cfg->private_subnet_config.num_subnet_entries; i++)
{
memcpy(&private_subnet_table[i].subnet_addr,
&cfg->private_subnet_config.private_subnet_entries[i].subnet_addr,
sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_addr));
memcpy(&private_subnet_table[i].subnet_mask,
&cfg->private_subnet_config.private_subnet_entries[i].subnet_mask,
sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_mask));
subnet_addr = htonl(private_subnet_table[i].subnet_addr);
memcpy(&in_addr_print,&subnet_addr,sizeof(in_addr_print));
IPACMDBG_H("%dst::private_subnet_table= %s \n ", i,
inet_ntoa(in_addr_print));
subnet_mask = htonl(private_subnet_table[i].subnet_mask);
memcpy(&in_addr_print,&subnet_mask,sizeof(in_addr_print));
IPACMDBG_H("%dst::private_subnet_table= %s \n ", i,
inet_ntoa(in_addr_print));
}
/* Construct IPACM ALG table */
ipa_num_alg_ports = cfg->alg_config.num_alg_entries;
if (alg_table != NULL)
{
free(alg_table);
alg_table = NULL;
IPACMDBG_H("RESET IPACM_Config::alg_table \n");
}
alg_table = (ipacm_alg *)calloc(ipa_num_alg_ports,
sizeof(ipacm_alg));
if(alg_table == NULL)
{
IPACMERR("Unable to allocate alg_table memory.\n");
ret = IPACM_FAILURE;
free(iface_table);
goto fail;;
}
for (i = 0; i < cfg->alg_config.num_alg_entries; i++)
{
alg_table[i].protocol = cfg->alg_config.alg_entries[i].protocol;
alg_table[i].port = cfg->alg_config.alg_entries[i].port;
IPACMDBG_H("IPACM_Config::ipacm_alg[%d] = %d, port=%d\n", i, alg_table[i].protocol, alg_table[i].port);
}
ipa_nat_max_entries = cfg->nat_max_entries;
IPACMDBG_H("Nat Maximum Entries %d\n", ipa_nat_max_entries);
/* Find ODU is either router mode or bridge mode*/
ipacm_odu_enable = cfg->odu_enable;
ipacm_odu_router_mode = cfg->router_mode_enable;
ipacm_odu_embms_enable = cfg->odu_embms_enable;
IPACMDBG_H("ipacm_odu_enable %d\n", ipacm_odu_enable);
IPACMDBG_H("ipacm_odu_mode %d\n", ipacm_odu_router_mode);
IPACMDBG_H("ipacm_odu_embms_enable %d\n", ipacm_odu_embms_enable);
ipacm_ip_passthrough_mode = cfg->ip_passthrough_mode;
IPACMDBG_H("ipacm_ip_passthrough_mode %d. \n", ipacm_ip_passthrough_mode);
ipa_num_wlan_guest_ap = cfg->num_wlan_guest_ap;
IPACMDBG_H("ipa_num_wlan_guest_ap %d\n",ipa_num_wlan_guest_ap);
/* Allocate more non-nat entries if the monitored iface dun have Tx/Rx properties */
if (pNatIfaces != NULL)
{
free(pNatIfaces);
pNatIfaces = NULL;
IPACMDBG_H("RESET IPACM_Config::pNatIfaces \n");
}
ipa_nat_iface_entries = 0;
pNatIfaces = (NatIfaces *)calloc(ipa_num_ipa_interfaces, sizeof(NatIfaces));
if (pNatIfaces == NULL)
{
IPACMERR("unable to allocate nat ifaces\n");
ret = IPACM_FAILURE;
free(iface_table);
free(alg_table);
goto fail;
}
/* Construct the routing table ictol name in iface static member*/
rt_tbl_default_v4.ip = IPA_IP_v4;
strncpy(rt_tbl_default_v4.name, V4_DEFAULT_ROUTE_TABLE_NAME, sizeof(rt_tbl_default_v4.name));
rt_tbl_lan_v4.ip = IPA_IP_v4;
strncpy(rt_tbl_lan_v4.name, V4_LAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_lan_v4.name));
rt_tbl_wan_v4.ip = IPA_IP_v4;
strncpy(rt_tbl_wan_v4.name, V4_WAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_v4.name));
rt_tbl_v6.ip = IPA_IP_v6;
strncpy(rt_tbl_v6.name, V6_COMMON_ROUTE_TABLE_NAME, sizeof(rt_tbl_v6.name));
rt_tbl_wan_v6.ip = IPA_IP_v6;
strncpy(rt_tbl_wan_v6.name, V6_WAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_v6.name));
rt_tbl_odu_v4.ip = IPA_IP_v4;
strncpy(rt_tbl_odu_v4.name, V4_ODU_ROUTE_TABLE_NAME, sizeof(rt_tbl_odu_v4.name));
rt_tbl_odu_v6.ip = IPA_IP_v6;
strncpy(rt_tbl_odu_v6.name, V6_ODU_ROUTE_TABLE_NAME, sizeof(rt_tbl_odu_v6.name));
rt_tbl_wan_dl.ip = IPA_IP_MAX;
strncpy(rt_tbl_wan_dl.name, WAN_DL_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_dl.name));
/* Construct IPACM ipa_client map to rm_resource table */
ipa_client_rm_map_tbl[IPA_CLIENT_WLAN1_PROD]= IPA_RM_RESOURCE_WLAN_PROD;
ipa_client_rm_map_tbl[IPA_CLIENT_USB_PROD]= IPA_RM_RESOURCE_USB_PROD;
ipa_client_rm_map_tbl[IPA_CLIENT_A5_WLAN_AMPDU_PROD]= IPA_RM_RESOURCE_HSIC_PROD;
ipa_client_rm_map_tbl[IPA_CLIENT_A2_EMBEDDED_PROD]= IPA_RM_RESOURCE_Q6_PROD;
ipa_client_rm_map_tbl[IPA_CLIENT_A2_TETHERED_PROD]= IPA_RM_RESOURCE_Q6_PROD;
ipa_client_rm_map_tbl[IPA_CLIENT_APPS_LAN_WAN_PROD]= IPA_RM_RESOURCE_Q6_PROD;
ipa_client_rm_map_tbl[IPA_CLIENT_WLAN1_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_WLAN2_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_WLAN3_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_WLAN4_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_USB_CONS]= IPA_RM_RESOURCE_USB_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_A2_EMBEDDED_CONS]= IPA_RM_RESOURCE_Q6_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_A2_TETHERED_CONS]= IPA_RM_RESOURCE_Q6_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_APPS_WAN_CONS]= IPA_RM_RESOURCE_Q6_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_ODU_PROD]= IPA_RM_RESOURCE_ODU_ADAPT_PROD;
ipa_client_rm_map_tbl[IPA_CLIENT_ODU_EMB_CONS]= IPA_RM_RESOURCE_ODU_ADAPT_CONS;
ipa_client_rm_map_tbl[IPA_CLIENT_ODU_TETH_CONS]= IPA_RM_RESOURCE_ODU_ADAPT_CONS;
/* Create the entries which IPACM wants to add dependencies on */
ipa_rm_tbl[0].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
ipa_rm_tbl[0].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
ipa_rm_tbl[0].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
ipa_rm_tbl[0].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
ipa_rm_tbl[1].producer_rm1 = IPA_RM_RESOURCE_USB_PROD;
ipa_rm_tbl[1].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
ipa_rm_tbl[1].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
ipa_rm_tbl[1].consumer_rm2 = IPA_RM_RESOURCE_USB_CONS;
ipa_rm_tbl[2].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
ipa_rm_tbl[2].consumer_rm1 = IPA_RM_RESOURCE_USB_CONS;
ipa_rm_tbl[2].producer_rm2 = IPA_RM_RESOURCE_USB_PROD;
ipa_rm_tbl[2].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
ipa_rm_tbl[3].producer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
ipa_rm_tbl[3].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
ipa_rm_tbl[3].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
ipa_rm_tbl[3].consumer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
ipa_rm_tbl[4].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
ipa_rm_tbl[4].consumer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
ipa_rm_tbl[4].producer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
ipa_rm_tbl[4].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
ipa_rm_tbl[5].producer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
ipa_rm_tbl[5].consumer_rm1 = IPA_RM_RESOURCE_USB_CONS;
ipa_rm_tbl[5].producer_rm2 = IPA_RM_RESOURCE_USB_PROD;
ipa_rm_tbl[5].consumer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
ipa_max_valid_rm_entry = 6; /* max is IPA_MAX_RM_ENTRY (6)*/
IPACMDBG_H(" depend MAP-0 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_Q6_CONS);
IPACMDBG_H(" depend MAP-1 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_USB_PROD, IPA_RM_RESOURCE_Q6_CONS);
IPACMDBG_H(" depend MAP-2 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_USB_CONS);
IPACMDBG_H(" depend MAP-3 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_Q6_CONS);
IPACMDBG_H(" depend MAP-4 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_ODU_ADAPT_CONS);
IPACMDBG_H(" depend MAP-5 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_USB_CONS);
fail:
if (cfg != NULL)
{
free(cfg);
cfg = NULL;
}
return ret;
}
IPACM_Config* IPACM_Config::GetInstance()
{
int res = IPACM_SUCCESS;
if (pInstance == NULL)
{
pInstance = new IPACM_Config();
res = pInstance->Init();
if (res != IPACM_SUCCESS)
{
delete pInstance;
IPACMERR("unable to initialize config instance\n");
return NULL;
}
}
return pInstance;
}
int IPACM_Config::GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts)
{
if (nPorts <= 0 || pAlgPorts == NULL)
{
IPACMERR("Invalid input\n");
return -1;
}
for (int cnt = 0; cnt < nPorts; cnt++)
{
pAlgPorts[cnt].protocol = alg_table[cnt].protocol;
pAlgPorts[cnt].port = alg_table[cnt].port;
}
return 0;
}
int IPACM_Config::GetNatIfaces(int nIfaces, NatIfaces *pIfaces)
{
if (nIfaces <= 0 || pIfaces == NULL)
{
IPACMERR("Invalid input\n");
return -1;
}
for (int cnt=0; cnt<nIfaces; cnt++)
{
memcpy(pIfaces[cnt].iface_name,
pNatIfaces[cnt].iface_name,
sizeof(pIfaces[cnt].iface_name));
}
return 0;
}
int IPACM_Config::AddNatIfaces(char *dev_name)
{
int i;
/* Check if this iface already in NAT-iface*/
for(i = 0; i < ipa_nat_iface_entries; i++)
{
if(strncmp(dev_name,
pNatIfaces[i].iface_name,
sizeof(pNatIfaces[i].iface_name)) == 0)
{
IPACMDBG("Interface (%s) is add to nat iface already\n", dev_name);
return 0;
}
}
IPACMDBG_H("Add iface %s to NAT-ifaces, origin it has %d nat ifaces\n",
dev_name, ipa_nat_iface_entries);
ipa_nat_iface_entries++;
if (ipa_nat_iface_entries < ipa_num_ipa_interfaces)
{
memcpy(pNatIfaces[ipa_nat_iface_entries - 1].iface_name,
dev_name, IPA_IFACE_NAME_LEN);
IPACMDBG_H("Add Nat IfaceName: %s ,update nat-ifaces number: %d\n",
pNatIfaces[ipa_nat_iface_entries - 1].iface_name,
ipa_nat_iface_entries);
}
return 0;
}
int IPACM_Config::DelNatIfaces(char *dev_name)
{
int i = 0;
IPACMDBG_H("Del iface %s from NAT-ifaces, origin it has %d nat ifaces\n",
dev_name, ipa_nat_iface_entries);
for (i = 0; i < ipa_nat_iface_entries; i++)
{
if (strcmp(dev_name, pNatIfaces[i].iface_name) == 0)
{
IPACMDBG_H("Find Nat IfaceName: %s ,previous nat-ifaces number: %d\n",
pNatIfaces[i].iface_name, ipa_nat_iface_entries);
/* Reset the matched entry */
memset(pNatIfaces[i].iface_name, 0, IPA_IFACE_NAME_LEN);
for (; i < ipa_nat_iface_entries - 1; i++)
{
memcpy(pNatIfaces[i].iface_name,
pNatIfaces[i + 1].iface_name, IPA_IFACE_NAME_LEN);
/* Reset the copied entry */
memset(pNatIfaces[i + 1].iface_name, 0, IPA_IFACE_NAME_LEN);
}
ipa_nat_iface_entries--;
IPACMDBG_H("Update nat-ifaces number: %d\n", ipa_nat_iface_entries);
return 0;
}
}
IPACMDBG_H("Can't find Nat IfaceName: %s with total nat-ifaces number: %d\n",
dev_name, ipa_nat_iface_entries);
return 0;
}
/* for IPACM resource manager dependency usage
add either Tx or Rx ipa_rm_resource_name and
also indicate that endpoint property if valid */
void IPACM_Config::AddRmDepend(ipa_rm_resource_name rm1,bool rx_bypass_ipa)
{
int retval = 0;
struct ipa_ioc_rm_dependency dep;
IPACMDBG_H(" Got rm add-depend index : %d \n", rm1);
/* ipa_rm_a2_check: IPA_RM_RESOURCE_Q6_CONS*/
if(rm1 == IPA_RM_RESOURCE_Q6_CONS)
{
ipa_rm_a2_check+=1;
IPACMDBG_H("got %d times default RT routing from A2 \n", ipa_rm_a2_check);
}
for(int i=0;i<ipa_max_valid_rm_entry;i++)
{
if(rm1 == ipa_rm_tbl[i].producer_rm1)
{
ipa_rm_tbl[i].producer1_up = true;
/* entry1's producer actually dun have registered Rx-property */
ipa_rm_tbl[i].rx_bypass_ipa = rx_bypass_ipa;
IPACMDBG_H("Matched RM_table entry: %d's producer_rm1 with non_rx_prop: %d \n", i,ipa_rm_tbl[i].rx_bypass_ipa);
if(ipa_rm_tbl[i].consumer1_up == true && ipa_rm_tbl[i].rm_set == false)
{
IPACMDBG_H("SETUP RM_table entry %d's bi-direction dependency \n", i);
/* add bi-directional dependency*/
if(ipa_rm_tbl[i].rx_bypass_ipa)
{
IPACMDBG_H("Skip ADD entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
}
else
{
memset(&dep, 0, sizeof(dep));
dep.resource_name = ipa_rm_tbl[i].producer_rm1;
dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
if (retval)
{
IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
}
}
memset(&dep, 0, sizeof(dep));
dep.resource_name = ipa_rm_tbl[i].producer_rm2;
dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
if (retval)
{
IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
}
ipa_rm_tbl[i].rm_set = true;
}
else
{
IPACMDBG_H("Not SETUP RM_table entry %d: prod_up:%d, cons_up:%d, rm_set: %d \n", i,ipa_rm_tbl[i].producer1_up, ipa_rm_tbl[i].consumer1_up, ipa_rm_tbl[i].rm_set);
}
}
if(rm1 == ipa_rm_tbl[i].consumer_rm1)
{
ipa_rm_tbl[i].consumer1_up = true;
IPACMDBG_H("Matched RM_table entry: %d's consumer_rm1 \n", i);
if(ipa_rm_tbl[i].producer1_up == true && ipa_rm_tbl[i].rm_set == false)
{
IPACMDBG_H("SETUP RM_table entry %d's bi-direction dependency \n", i);
/* add bi-directional dependency*/
if(ipa_rm_tbl[i].rx_bypass_ipa)
{
IPACMDBG_H("Skip ADD entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
}
else
{
memset(&dep, 0, sizeof(dep));
dep.resource_name = ipa_rm_tbl[i].producer_rm1;
dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
if (retval)
{
IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
}
}
memset(&dep, 0, sizeof(dep));
dep.resource_name = ipa_rm_tbl[i].producer_rm2;
dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
if (retval)
{
IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
}
ipa_rm_tbl[i].rm_set = true;
}
else
{
IPACMDBG_H("Not SETUP RM_table entry %d: prod_up:%d, cons_up:%d, rm_set: %d \n", i,ipa_rm_tbl[i].producer1_up, ipa_rm_tbl[i].consumer1_up, ipa_rm_tbl[i].rm_set);
}
}
}
return ;
}
/* for IPACM resource manager dependency usage
delete either Tx or Rx ipa_rm_resource_name */
void IPACM_Config::DelRmDepend(ipa_rm_resource_name rm1)
{
int retval = 0;
struct ipa_ioc_rm_dependency dep;
IPACMDBG_H(" Got rm del-depend index : %d \n", rm1);
/* ipa_rm_a2_check: IPA_RM_RESOURCE_Q6_CONS*/
if(rm1 == IPA_RM_RESOURCE_Q6_CONS)
{
ipa_rm_a2_check-=1;
IPACMDBG_H("Left %d times default RT routing from A2 \n", ipa_rm_a2_check);
}
for(int i=0;i<ipa_max_valid_rm_entry;i++)
{
if(rm1 == ipa_rm_tbl[i].producer_rm1)
{
if(ipa_rm_tbl[i].rm_set == true)
{
IPACMDBG_H("Matched RM_table entry: %d's producer_rm1 and dependency is up \n", i);
ipa_rm_tbl[i].rm_set = false;
/* delete bi-directional dependency*/
if(ipa_rm_tbl[i].rx_bypass_ipa)
{
IPACMDBG_H("Skip DEL entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
}
else
{
memset(&dep, 0, sizeof(dep));
dep.resource_name = ipa_rm_tbl[i].producer_rm1;
dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
if (retval)
{
IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
}
}
memset(&dep, 0, sizeof(dep));
dep.resource_name = ipa_rm_tbl[i].producer_rm2;
dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
if (retval)
{
IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
}
}
ipa_rm_tbl[i].producer1_up = false;
ipa_rm_tbl[i].rx_bypass_ipa = false;
}
if(rm1 == ipa_rm_tbl[i].consumer_rm1)
{
/* ipa_rm_a2_check: IPA_RM_RESOURCE_!6_CONS*/
if(ipa_rm_tbl[i].consumer_rm1 == IPA_RM_RESOURCE_Q6_CONS && ipa_rm_a2_check == 1)
{
IPACMDBG_H(" still have %d default RT routing from A2 \n", ipa_rm_a2_check);
continue;
}
if(ipa_rm_tbl[i].rm_set == true)
{
IPACMDBG_H("Matched RM_table entry: %d's consumer_rm1 and dependency is up \n", i);
ipa_rm_tbl[i].rm_set = false;
/* delete bi-directional dependency*/
if(ipa_rm_tbl[i].rx_bypass_ipa)
{
IPACMDBG_H("Skip DEL entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
}
else
{
memset(&dep, 0, sizeof(dep));
dep.resource_name = ipa_rm_tbl[i].producer_rm1;
dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
if (retval)
{
IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
}
}
memset(&dep, 0, sizeof(dep));
dep.resource_name = ipa_rm_tbl[i].producer_rm2;
dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
if (retval)
{
IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
}
}
ipa_rm_tbl[i].consumer1_up = false;
}
}
return ;
}
int IPACM_Config::SetExtProp(ipa_ioc_query_intf_ext_props *prop)
{
int i, num;
if(prop == NULL || prop->num_ext_props <= 0)
{
IPACMERR("There is no extended property!\n");
return IPACM_FAILURE;
}
num = prop->num_ext_props;
for(i=0; i<num; i++)
{
if(prop->ext[i].ip == IPA_IP_v4)
{
if(ext_prop_v4.num_ext_props >= MAX_NUM_EXT_PROPS)
{
IPACMERR("IPv4 extended property table is full!\n");
continue;
}
memcpy(&ext_prop_v4.prop[ext_prop_v4.num_ext_props], &prop->ext[i], sizeof(struct ipa_ioc_ext_intf_prop));
ext_prop_v4.num_ext_props++;
}
else if(prop->ext[i].ip == IPA_IP_v6)
{
if(ext_prop_v6.num_ext_props >= MAX_NUM_EXT_PROPS)
{
IPACMERR("IPv6 extended property table is full!\n");
continue;
}
memcpy(&ext_prop_v6.prop[ext_prop_v6.num_ext_props], &prop->ext[i], sizeof(struct ipa_ioc_ext_intf_prop));
ext_prop_v6.num_ext_props++;
}
else
{
IPACMERR("The IP type is not expected!\n");
return IPACM_FAILURE;
}
}
IPACMDBG_H("Set extended property succeeded.\n");
return IPACM_SUCCESS;
}
ipacm_ext_prop* IPACM_Config::GetExtProp(ipa_ip_type ip_type)
{
if(ip_type == IPA_IP_v4)
return &ext_prop_v4;
else if(ip_type == IPA_IP_v6)
return &ext_prop_v6;
else
{
IPACMERR("Failed to get extended property: the IP version is neither IPv4 nor IPv6!\n");
return NULL;
}
}
int IPACM_Config::DelExtProp(ipa_ip_type ip_type)
{
if(ip_type != IPA_IP_v6)
{
memset(&ext_prop_v4, 0, sizeof(ext_prop_v4));
}
if(ip_type != IPA_IP_v4)
{
memset(&ext_prop_v6, 0, sizeof(ext_prop_v6));
}
return IPACM_SUCCESS;
}
const char* IPACM_Config::getEventName(ipa_cm_event_id event_id)
{
if(event_id >= sizeof(ipacm_event_name)/sizeof(ipacm_event_name[0]))
{
IPACMERR("Event name array is not consistent with event array!\n");
return NULL;
}
return ipacm_event_name[event_id];
}

View File

@@ -0,0 +1,652 @@
/*
Copyright (c) 2013-2016, 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include "IPACM_Iface.h"
#include "IPACM_ConntrackListener.h"
#include "IPACM_ConntrackClient.h"
#include "IPACM_Log.h"
#define LO_NAME "lo"
extern IPACM_EvtDispatcher cm_dis;
extern void ParseCTMessage(struct nf_conntrack *ct);
IPACM_ConntrackClient *IPACM_ConntrackClient::pInstance = NULL;
IPACM_ConntrackListener *CtList = NULL;
/* ================================
Local Function Definitions
=================================
*/
IPACM_ConntrackClient::IPACM_ConntrackClient()
{
IPACMDBG("\n");
tcp_hdl = NULL;
udp_hdl = NULL;
tcp_filter = NULL;
udp_filter = NULL;
}
IPACM_ConntrackClient* IPACM_ConntrackClient::GetInstance()
{
if(pInstance == NULL)
{
pInstance = new IPACM_ConntrackClient();
pInstance->udp_filter = nfct_filter_create();
if(pInstance->udp_filter == NULL)
{
IPACMERR("unable to create UDP filter\n");
delete pInstance;
return NULL;
}
IPACMDBG("Created UDP filter\n");
pInstance->tcp_filter = nfct_filter_create();
if(pInstance->tcp_filter == NULL)
{
IPACMERR("unable to create TCP filter\n");
delete pInstance;
return NULL;
}
IPACMDBG("Created TCP filter\n");
}
return pInstance;
}
int IPACM_ConntrackClient::IPAConntrackEventCB
(
enum nf_conntrack_msg_type type,
struct nf_conntrack *ct,
void *data
)
{
ipacm_cmd_q_data evt_data;
ipacm_ct_evt_data *ct_data;
uint8_t ip_type = 0;
IPACMDBG("Event callback called with msgtype: %d\n",type);
/* Retrieve ip type */
ip_type = nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO);
#ifndef CT_OPT
if(AF_INET6 == ip_type)
{
IPACMDBG("Ignoring ipv6(%d) connections\n", ip_type);
goto IGNORE;
}
#endif
ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
if(ct_data == NULL)
{
IPACMERR("unable to allocate memory \n");
goto IGNORE;
}
ct_data->ct = ct;
ct_data->type = type;
evt_data.event = IPA_PROCESS_CT_MESSAGE;
evt_data.evt_data = (void *)ct_data;
#ifdef CT_OPT
if(AF_INET6 == ip_type)
{
evt_data.event = IPA_PROCESS_CT_MESSAGE_V6;
}
#endif
if(0 != IPACM_EvtDispatcher::PostEvt(&evt_data))
{
IPACMERR("Error sending Conntrack message to processing thread!\n");
free(ct_data);
goto IGNORE;
}
/* NFCT_CB_STOLEN means that the conntrack object is not released after the
callback That must be manually done later when the object is no longer needed. */
return NFCT_CB_STOLEN;
IGNORE:
nfct_destroy(ct);
return NFCT_CB_STOLEN;
}
int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Bridge_Addrs
(
struct nfct_filter *filter
)
{
int fd;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0)
{
PERROR("unable to open socket");
return -1;
}
int ret;
uint32_t ipv4_addr;
struct ifreq ifr;
/* retrieve bridge interface ipv4 address */
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_addr.sa_family = AF_INET;
(void)strncpy(ifr.ifr_name, IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, sizeof(ifr.ifr_name));
IPACMDBG("bridge interface name (%s)\n", ifr.ifr_name);
ret = ioctl(fd, SIOCGIFADDR, &ifr);
if (ret < 0)
{
IPACMERR("unable to retrieve (%s) interface address\n",ifr.ifr_name);
close(fd);
return -1;
}
IPACMDBG("Interface (%s) address %s\n", ifr.ifr_name, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
ipv4_addr = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
close(fd);
/* ignore whatever is destined to or originates from broadcast ip address */
struct nfct_filter_ipv4 filter_ipv4;
filter_ipv4.addr = ipv4_addr;
filter_ipv4.mask = 0xffffffff;
nfct_filter_set_logic(filter,
NFCT_FILTER_DST_IPV4,
NFCT_FILTER_LOGIC_NEGATIVE);
nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
nfct_filter_set_logic(filter,
NFCT_FILTER_SRC_IPV4,
NFCT_FILTER_LOGIC_NEGATIVE);
nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
return 0;
}
int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Iface
(
struct nfct_filter *filter,
ipacm_event_iface_up *param
)
{
struct nfct_filter_ipv4 filter_ipv4;
filter_ipv4.addr = param->ipv4_addr;
filter_ipv4.mask = 0xffffffff;
/* ignore whatever is destined to local interfaces */
IPACMDBG("Ignore connections destinated to interface %s", param->ifname);
iptodot("with ipv4 address", param->ipv4_addr);
nfct_filter_set_logic(filter,
NFCT_FILTER_DST_IPV4,
NFCT_FILTER_LOGIC_NEGATIVE);
nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
IPACMDBG("Ignore connections orignated from interface %s", param->ifname);
iptodot("with ipv4 address", filter_ipv4.addr);
nfct_filter_set_logic(filter,
NFCT_FILTER_SRC_IPV4,
NFCT_FILTER_LOGIC_NEGATIVE);
nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
/* Retrieve broadcast address */
/* Intialize with 255.255.255.255 */
uint32_t bc_ip_addr = 0xFFFFFFFF;
/* calculate broadcast address from addr and addr_mask */
bc_ip_addr = (bc_ip_addr & (~param->addr_mask));
bc_ip_addr = (bc_ip_addr | (param->ipv4_addr & param->addr_mask));
/* netfitler expecting in host-byte order */
filter_ipv4.addr = bc_ip_addr;
filter_ipv4.mask = 0xffffffff;
iptodot("with broadcast address", filter_ipv4.addr);
nfct_filter_set_logic(filter,
NFCT_FILTER_DST_IPV4,
NFCT_FILTER_LOGIC_NEGATIVE);
nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
return 0;
}
/* Function which sets up filters to ignore
connections to and from local interfaces */
int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Addrs
(
struct nfct_filter *filter
)
{
struct nfct_filter_ipv4 filter_ipv4;
/* ignore whatever is destined to or originates from broadcast ip address */
filter_ipv4.addr = 0xffffffff;
filter_ipv4.mask = 0xffffffff;
nfct_filter_set_logic(filter,
NFCT_FILTER_DST_IPV4,
NFCT_FILTER_LOGIC_NEGATIVE);
nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
nfct_filter_set_logic(filter,
NFCT_FILTER_SRC_IPV4,
NFCT_FILTER_LOGIC_NEGATIVE);
nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
return 0;
} /* IPA_Conntrack_Filters_Ignore_Local_Addrs() */
/* Initialize TCP Filter */
int IPACM_ConntrackClient::IPA_Conntrack_TCP_Filter_Init(void)
{
int ret = 0;
IPACM_ConntrackClient *pClient;
IPACMDBG("\n");
pClient = IPACM_ConntrackClient::GetInstance();
if(pClient == NULL)
{
IPACMERR("unable to get conntrack client instance\n");
return -1;
}
ret = nfct_filter_set_logic(pClient->tcp_filter,
NFCT_FILTER_L4PROTO,
NFCT_FILTER_LOGIC_POSITIVE);
if(ret == -1)
{
IPACMERR("Unable to set filter logic\n");
return -1;
}
/* set protocol filters as tcp and udp */
nfct_filter_add_attr_u32(pClient->tcp_filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
struct nfct_filter_proto tcp_proto_state;
tcp_proto_state.proto = IPPROTO_TCP;
tcp_proto_state.state = TCP_CONNTRACK_ESTABLISHED;
ret = nfct_filter_set_logic(pClient->tcp_filter,
NFCT_FILTER_L4PROTO_STATE,
NFCT_FILTER_LOGIC_POSITIVE);
if(ret == -1)
{
IPACMERR("unable to set filter logic\n");
return -1;
}
nfct_filter_add_attr(pClient->tcp_filter,
NFCT_FILTER_L4PROTO_STATE,
&tcp_proto_state);
tcp_proto_state.proto = IPPROTO_TCP;
tcp_proto_state.state = TCP_CONNTRACK_FIN_WAIT;
ret = nfct_filter_set_logic(pClient->tcp_filter,
NFCT_FILTER_L4PROTO_STATE,
NFCT_FILTER_LOGIC_POSITIVE);
if(ret == -1)
{
IPACMERR("unable to set filter logic\n");
return -1;
}
nfct_filter_add_attr(pClient->tcp_filter,
NFCT_FILTER_L4PROTO_STATE,
&tcp_proto_state);
return 0;
}
/* Initialize UDP Filter */
int IPACM_ConntrackClient::IPA_Conntrack_UDP_Filter_Init(void)
{
int ret = 0;
IPACM_ConntrackClient *pClient = IPACM_ConntrackClient::GetInstance();
if(pClient == NULL)
{
IPACMERR("unable to get conntrack client instance\n");
return -1;
}
ret = nfct_filter_set_logic(pClient->udp_filter,
NFCT_FILTER_L4PROTO,
NFCT_FILTER_LOGIC_POSITIVE);
if(ret == -1)
{
IPACMERR("unable to set filter logic\n");
}
/* set protocol filters as tcp and udp */
nfct_filter_add_attr_u32(pClient->udp_filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
return 0;
}
void* IPACM_ConntrackClient::UDPConnTimeoutUpdate(void *ptr)
{
NatApp *nat_inst = NULL;
#ifdef IPACM_DEBUG
IPACMDBG("\n");
#endif
nat_inst = NatApp::GetInstance();
if(nat_inst == NULL)
{
IPACMERR("unable to create nat instance\n");
return NULL;
}
while(1)
{
nat_inst->UpdateUDPTimeStamp();
sleep(UDP_TIMEOUT_UPDATE);
} /* end of while(1) loop */
#ifdef IPACM_DEBUG
IPACMDBG("Returning from %s() %d\n", __FUNCTION__, __LINE__);
#endif
return NULL;
}
/* Thread to initialize TCP Conntrack Filters*/
void* IPACM_ConntrackClient::TCPRegisterWithConnTrack(void *)
{
int ret;
IPACM_ConntrackClient *pClient;
unsigned subscrips = 0;
IPACMDBG("\n");
pClient = IPACM_ConntrackClient::GetInstance();
if(pClient == NULL)
{
IPACMERR("unable to get conntrack client instance\n");
return NULL;
}
subscrips = (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
#ifdef CT_OPT
subscrips |= NF_NETLINK_CONNTRACK_NEW;
#endif
pClient->tcp_hdl = nfct_open(CONNTRACK, subscrips);
if(pClient->tcp_hdl == NULL)
{
PERROR("nfct_open\n");
return NULL;
}
/* Initialize the filter */
ret = IPA_Conntrack_TCP_Filter_Init();
if(ret == -1)
{
IPACMERR("Unable to initliaze TCP Filter\n");
return NULL;
}
/* Attach the filter to net filter handler */
ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
if(ret == -1)
{
IPACMDBG("unable to attach TCP filter\n");
return NULL;
}
/* Register callback with netfilter handler */
IPACMDBG_H("tcp handle:%p, fd:%d\n", pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl));
#ifndef CT_OPT
nfct_callback_register(pClient->tcp_hdl,
(nf_conntrack_msg_type) (NFCT_T_UPDATE | NFCT_T_DESTROY | NFCT_T_NEW),
IPAConntrackEventCB, NULL);
#else
nfct_callback_register(pClient->tcp_hdl, (nf_conntrack_msg_type) NFCT_T_ALL, IPAConntrackEventCB, NULL);
#endif
/* Block to catch events from net filter connection track */
/* nfct_catch() receives conntrack events from kernel-space, by default it
blocks waiting for events. */
IPACMDBG("Waiting for events\n");
ret = nfct_catch(pClient->tcp_hdl);
if(ret == -1)
{
IPACMERR("(%d)(%s)\n", ret, strerror(errno));
return NULL;
}
IPACMDBG("Exit from tcp thread\n");
/* destroy the filter.. this will not detach the filter */
nfct_filter_destroy(pClient->tcp_filter);
pClient->tcp_filter = NULL;
/* de-register the callback */
nfct_callback_unregister(pClient->tcp_hdl);
/* close the handle */
nfct_close(pClient->tcp_hdl);
pClient->tcp_hdl = NULL;
pthread_exit(NULL);
return NULL;
}
/* Thread to initialize UDP Conntrack Filters*/
void* IPACM_ConntrackClient::UDPRegisterWithConnTrack(void *)
{
int ret;
IPACM_ConntrackClient *pClient = NULL;
IPACMDBG("\n");
pClient = IPACM_ConntrackClient::GetInstance();
if(pClient == NULL)
{
IPACMERR("unable to retrieve instance of conntrack client\n");
return NULL;
}
pClient->udp_hdl = nfct_open(CONNTRACK,
(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY));
if(pClient->udp_hdl == NULL)
{
PERROR("nfct_open\n");
return NULL;
}
/* Initialize Filter */
ret = IPA_Conntrack_UDP_Filter_Init();
if(-1 == ret)
{
IPACMDBG("Unable to initalize udp filters\n");
return NULL;
}
/* Attach the filter to net filter handler */
ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
if(ret == -1)
{
IPACMDBG("unable to attach the filter\n");
return NULL;
}
/* Register callback with netfilter handler */
IPACMDBG_H("udp handle:%p, fd:%d\n", pClient->udp_hdl, nfct_fd(pClient->udp_hdl));
nfct_callback_register(pClient->udp_hdl,
(nf_conntrack_msg_type)(NFCT_T_NEW | NFCT_T_DESTROY),
IPAConntrackEventCB,
NULL);
/* Block to catch events from net filter connection track */
ctcatch:
ret = nfct_catch(pClient->udp_hdl);
if(ret == -1)
{
IPACMDBG("(%d)(%s)\n", ret, strerror(errno));
return NULL;
}
else
{
IPACMDBG("ctcatch ret:%d\n", ret);
goto ctcatch;
}
IPACMDBG("Exit from udp thread with ret: %d\n", ret);
/* destroy the filter.. this will not detach the filter */
nfct_filter_destroy(pClient->udp_filter);
pClient->udp_filter = NULL;
/* de-register the callback */
nfct_callback_unregister(pClient->udp_hdl);
/* close the handle */
nfct_close(pClient->udp_hdl);
pClient->udp_hdl = NULL;
pthread_exit(NULL);
return NULL;
}
void IPACM_ConntrackClient::UpdateUDPFilters(void *param, bool isWan)
{
static bool isIgnore = false;
int ret = 0;
IPACM_ConntrackClient *pClient = NULL;
pClient = IPACM_ConntrackClient::GetInstance();
if(pClient == NULL)
{
IPACMERR("unable to retrieve conntrack client instance\n");
return;
}
if(pClient->udp_filter == NULL)
{
return;
}
if(!isWan)
{
IPA_Conntrack_Filters_Ignore_Local_Iface(pClient->udp_filter,
(ipacm_event_iface_up *)param);
if(!isIgnore)
{
IPA_Conntrack_Filters_Ignore_Bridge_Addrs(pClient->udp_filter);
IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
isIgnore = true;
}
}
/* Attach the filter to udp handle */
if(pClient->udp_hdl != NULL)
{
IPACMDBG("attaching the filter to udp handle\n");
ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
if(ret == -1)
{
PERROR("unable to attach the filter to udp handle\n");
IPACMERR("udp handle:%p, fd:%d Error: %d\n",pClient->udp_hdl, nfct_fd(pClient->udp_hdl), ret);
return;
}
}
return;
}
void IPACM_ConntrackClient::UpdateTCPFilters(void *param, bool isWan)
{
static bool isIgnore = false;
int ret = 0;
IPACM_ConntrackClient *pClient = NULL;
pClient = IPACM_ConntrackClient::GetInstance();
if(pClient == NULL)
{
IPACMERR("unable to retrieve conntrack client instance\n");
return;
}
if(pClient->tcp_filter == NULL)
return;
if(!isWan)
{
IPA_Conntrack_Filters_Ignore_Local_Iface(pClient->tcp_filter,
(ipacm_event_iface_up *)param);
if(!isIgnore)
{
IPA_Conntrack_Filters_Ignore_Bridge_Addrs(pClient->udp_filter);
IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
isIgnore = true;
}
}
/* Attach the filter to tcp handle */
if(pClient->tcp_hdl != NULL)
{
IPACMDBG("attaching the filter to tcp handle\n");
ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
if(ret == -1)
{
PERROR("unable to attach the filter to tcp handle\n");
IPACMERR("tcp handle:%p, fd:%d Error: %d\n",pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl), ret);
return;
}
}
return;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,969 @@
/*
Copyright (c) 2013-2016, 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.
*/
#include "IPACM_Conntrack_NATApp.h"
#include "IPACM_ConntrackClient.h"
#define INVALID_IP_ADDR 0x0
/* NatApp class Implementation */
NatApp *NatApp::pInstance = NULL;
NatApp::NatApp()
{
max_entries = 0;
cache = NULL;
nat_table_hdl = 0;
pub_ip_addr = 0;
curCnt = 0;
pALGPorts = NULL;
nALGPort = 0;
ct = NULL;
ct_hdl = NULL;
memset(temp, 0, sizeof(temp));
}
int NatApp::Init(void)
{
IPACM_Config *pConfig;
int size = 0;
pConfig = IPACM_Config::GetInstance();
if(pConfig == NULL)
{
IPACMERR("Unable to get Config instance\n");
return -1;
}
max_entries = pConfig->GetNatMaxEntries();
size = (sizeof(nat_table_entry) * max_entries);
cache = (nat_table_entry *)malloc(size);
if(cache == NULL)
{
IPACMERR("Unable to allocate memory for cache\n");
goto fail;
}
IPACMDBG("Allocated %d bytes for config manager nat cache\n", size);
memset(cache, 0, size);
nALGPort = pConfig->GetAlgPortCnt();
if(nALGPort > 0)
{
pALGPorts = (ipacm_alg *)malloc(sizeof(ipacm_alg) * nALGPort);
if(pALGPorts == NULL)
{
IPACMERR("Unable to allocate memory for alg prots\n");
goto fail;
}
memset(pALGPorts, 0, sizeof(ipacm_alg) * nALGPort);
if(pConfig->GetAlgPorts(nALGPort, pALGPorts) != 0)
{
IPACMERR("Unable to retrieve ALG prots\n");
goto fail;
}
IPACMDBG("Printing %d alg ports information\n", nALGPort);
for(int cnt=0; cnt<nALGPort; cnt++)
{
IPACMDBG("%d: Proto[%d], port[%d]\n", cnt, pALGPorts[cnt].protocol, pALGPorts[cnt].port);
}
}
return 0;
fail:
free(cache);
free(pALGPorts);
return -1;
}
NatApp* NatApp::GetInstance()
{
if(pInstance == NULL)
{
pInstance = new NatApp();
if(pInstance->Init())
{
delete pInstance;
return NULL;
}
}
return pInstance;
}
/* NAT APP related object function definitions */
int NatApp::AddTable(uint32_t pub_ip)
{
int ret;
int cnt = 0;
ipa_nat_ipv4_rule nat_rule;
IPACMDBG_H("%s() %d\n", __FUNCTION__, __LINE__);
/* Not reset the cache wait it timeout by destroy event */
#if 0
if (pub_ip != pub_ip_addr_pre)
{
IPACMDBG("Reset the cache because NAT-ipv4 different\n");
memset(cache, 0, sizeof(nat_table_entry) * max_entries);
curCnt = 0;
}
#endif
ret = ipa_nat_add_ipv4_tbl(pub_ip, max_entries, &nat_table_hdl);
if(ret)
{
IPACMERR("unable to create nat table Error:%d\n", ret);
return ret;
}
/* Add back the cached NAT-entry */
if (pub_ip == pub_ip_addr_pre)
{
IPACMDBG("Restore the cache to ipa NAT-table\n");
for(cnt = 0; cnt < max_entries; cnt++)
{
if(cache[cnt].private_ip !=0)
{
memset(&nat_rule, 0 , sizeof(nat_rule));
nat_rule.private_ip = cache[cnt].private_ip;
nat_rule.target_ip = cache[cnt].target_ip;
nat_rule.target_port = cache[cnt].target_port;
nat_rule.private_port = cache[cnt].private_port;
nat_rule.public_port = cache[cnt].public_port;
nat_rule.protocol = cache[cnt].protocol;
if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
{
IPACMERR("unable to add the rule delete from cache\n");
memset(&cache[cnt], 0, sizeof(cache[cnt]));
curCnt--;
continue;
}
cache[cnt].enabled = true;
IPACMDBG("On wan-iface reset added below rule successfully\n");
iptodot("Private IP", nat_rule.private_ip);
iptodot("Target IP", nat_rule.target_ip);
IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
IPACMDBG("Public Port:%d\n", nat_rule.public_port);
IPACMDBG("protocol: %d\n", nat_rule.protocol);
}
}
}
pub_ip_addr = pub_ip;
return 0;
}
void NatApp::Reset()
{
int cnt = 0;
nat_table_hdl = 0;
pub_ip_addr = 0;
/* NAT tbl deleted, reset enabled bit */
for(cnt = 0; cnt < max_entries; cnt++)
{
cache[cnt].enabled = false;
}
}
int NatApp::DeleteTable(uint32_t pub_ip)
{
int ret;
IPACMDBG_H("%s() %d\n", __FUNCTION__, __LINE__);
CHK_TBL_HDL();
if(pub_ip_addr != pub_ip)
{
IPACMDBG("Public ip address is not matching\n");
IPACMERR("unable to delete the nat table\n");
return -1;
}
ret = ipa_nat_del_ipv4_tbl(nat_table_hdl);
if(ret)
{
IPACMERR("unable to delete nat table Error: %d\n", ret);;
return ret;
}
pub_ip_addr_pre = pub_ip_addr;
Reset();
return 0;
}
/* Check for duplicate entries */
bool NatApp::ChkForDup(const nat_table_entry *rule)
{
int cnt = 0;
IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
for(; cnt < max_entries; cnt++)
{
if(cache[cnt].private_ip == rule->private_ip &&
cache[cnt].target_ip == rule->target_ip &&
cache[cnt].private_port == rule->private_port &&
cache[cnt].target_port == rule->target_port &&
cache[cnt].protocol == rule->protocol)
{
log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
rule->target_port,"Duplicate Rule\n");
return true;
}
}
return false;
}
/* Delete the entry from Nat table on connection close */
int NatApp::DeleteEntry(const nat_table_entry *rule)
{
int cnt = 0;
IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
rule->target_port,"for deletion\n");
for(; cnt < max_entries; cnt++)
{
if(cache[cnt].private_ip == rule->private_ip &&
cache[cnt].target_ip == rule->target_ip &&
cache[cnt].private_port == rule->private_port &&
cache[cnt].target_port == rule->target_port &&
cache[cnt].protocol == rule->protocol)
{
if(cache[cnt].enabled == true)
{
if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
{
IPACMERR("%s() %d deletion failed\n", __FUNCTION__, __LINE__);
}
IPACMDBG_H("Deleted Nat entry(%d) Successfully\n", cnt);
}
else
{
IPACMDBG_H("Deleted Nat entry(%d) only from cache\n", cnt);
}
memset(&cache[cnt], 0, sizeof(cache[cnt]));
curCnt--;
break;
}
}
return 0;
}
/* Add new entry to the nat table on new connection */
int NatApp::AddEntry(const nat_table_entry *rule)
{
int cnt = 0;
ipa_nat_ipv4_rule nat_rule;
IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
CHK_TBL_HDL();
log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
rule->target_port,"for addition\n");
if(isAlgPort(rule->protocol, rule->private_port) ||
isAlgPort(rule->protocol, rule->target_port))
{
IPACMERR("connection using ALG Port, ignore\n");
return -1;
}
if(rule->private_ip == 0 ||
rule->target_ip == 0 ||
rule->private_port == 0 ||
rule->target_port == 0 ||
rule->protocol == 0)
{
IPACMERR("Invalid Connection, ignoring it\n");
return 0;
}
if(!ChkForDup(rule))
{
for(; cnt < max_entries; cnt++)
{
if(cache[cnt].private_ip == 0 &&
cache[cnt].target_ip == 0 &&
cache[cnt].private_port == 0 &&
cache[cnt].target_port == 0 &&
cache[cnt].protocol == 0)
{
break;
}
}
if(max_entries == cnt)
{
IPACMERR("Error: Unable to add, reached maximum rules\n");
return -1;
}
else
{
nat_rule.private_ip = rule->private_ip;
nat_rule.target_ip = rule->target_ip;
nat_rule.target_port = rule->target_port;
nat_rule.private_port = rule->private_port;
nat_rule.public_port = rule->public_port;
nat_rule.protocol = rule->protocol;
if(isPwrSaveIf(rule->private_ip) ||
isPwrSaveIf(rule->target_ip))
{
IPACMDBG("Device is Power Save mode: Dont insert into nat table but cache\n");
cache[cnt].enabled = false;
cache[cnt].rule_hdl = 0;
}
else
{
if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
{
IPACMERR("unable to add the rule\n");
return -1;
}
cache[cnt].enabled = true;
}
cache[cnt].private_ip = rule->private_ip;
cache[cnt].target_ip = rule->target_ip;
cache[cnt].target_port = rule->target_port;
cache[cnt].private_port = rule->private_port;
cache[cnt].protocol = rule->protocol;
cache[cnt].timestamp = 0;
cache[cnt].public_port = rule->public_port;
cache[cnt].dst_nat = rule->dst_nat;
curCnt++;
}
}
else
{
IPACMERR("Duplicate rule. Ignore it\n");
return -1;
}
if(cache[cnt].enabled == true)
{
IPACMDBG_H("Added rule(%d) successfully\n", cnt);
}
else
{
IPACMDBG_H("Cached rule(%d) successfully\n", cnt);
}
return 0;
}
void NatApp::UpdateCTUdpTs(nat_table_entry *rule, uint32_t new_ts)
{
int ret;
iptodot("Private IP:", rule->private_ip);
iptodot("Target IP:", rule->target_ip);
IPACMDBG("Private Port: %d, Target Port: %d\n", rule->private_port, rule->target_port);
if(!ct_hdl)
{
ct_hdl = nfct_open(CONNTRACK, 0);
if(!ct_hdl)
{
PERROR("nfct_open");
return;
}
}
if(!ct)
{
ct = nfct_new();
if(!ct)
{
PERROR("nfct_new");
return;
}
}
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
if(rule->protocol == IPPROTO_UDP)
{
nfct_set_attr_u8(ct, ATTR_L4PROTO, rule->protocol);
nfct_set_attr_u32(ct, ATTR_TIMEOUT, udp_timeout);
}
else
{
nfct_set_attr_u8(ct, ATTR_L4PROTO, rule->protocol);
nfct_set_attr_u32(ct, ATTR_TIMEOUT, tcp_timeout);
}
if(rule->dst_nat == false)
{
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->private_ip));
nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->private_port));
nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(rule->target_ip));
nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->target_port));
IPACMDBG("dst nat is not set\n");
}
else
{
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->target_ip));
nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->target_port));
nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(pub_ip_addr));
nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->public_port));
IPACMDBG("dst nat is set\n");
}
iptodot("Source IP:", nfct_get_attr_u32(ct, ATTR_IPV4_SRC));
iptodot("Destination IP:", nfct_get_attr_u32(ct, ATTR_IPV4_DST));
IPACMDBG("Source Port: %d, Destination Port: %d\n",
nfct_get_attr_u16(ct, ATTR_PORT_SRC), nfct_get_attr_u16(ct, ATTR_PORT_DST));
IPACMDBG("updating %d connection with time: %d\n",
rule->protocol, nfct_get_attr_u32(ct, ATTR_TIMEOUT));
ret = nfct_query(ct_hdl, NFCT_Q_UPDATE, ct);
if(ret == -1)
{
IPACMERR("unable to update time stamp");
DeleteEntry(rule);
}
else
{
rule->timestamp = new_ts;
IPACMDBG("Updated time stamp successfully\n");
}
return;
}
void NatApp::UpdateUDPTimeStamp()
{
int cnt;
uint32_t ts;
bool read_to = false;
for(cnt = 0; cnt < max_entries; cnt++)
{
ts = 0;
if(cache[cnt].enabled == true &&
(cache[cnt].private_ip != cache[cnt].public_ip))
{
IPACMDBG("\n");
if(ipa_nat_query_timestamp(nat_table_hdl, cache[cnt].rule_hdl, &ts) < 0)
{
IPACMERR("unable to retrieve timeout for rule hanle: %d\n", cache[cnt].rule_hdl);
continue;
}
if(cache[cnt].timestamp == ts)
{
IPACMDBG("No Change in Time Stamp: cahce:%d, ipahw:%d\n",
cache[cnt].timestamp, ts);
continue;
}
if (read_to == false) {
read_to = true;
Read_TcpUdp_Timeout();
}
UpdateCTUdpTs(&cache[cnt], ts);
} /* end of outer if */
} /* end of for loop */
}
bool NatApp::isAlgPort(uint8_t proto, uint16_t port)
{
int cnt;
for(cnt = 0; cnt < nALGPort; cnt++)
{
if(proto == pALGPorts[cnt].protocol &&
port == pALGPorts[cnt].port)
{
return true;
}
}
return false;
}
bool NatApp::isPwrSaveIf(uint32_t ip_addr)
{
int cnt;
for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
{
if(0 != PwrSaveIfs[cnt] &&
ip_addr == PwrSaveIfs[cnt])
{
return true;
}
}
return false;
}
int NatApp::UpdatePwrSaveIf(uint32_t client_lan_ip)
{
int cnt;
IPACMDBG_H("Received IP address: 0x%x\n", client_lan_ip);
if(client_lan_ip == INVALID_IP_ADDR)
{
IPACMERR("Invalid ip address received\n");
return -1;
}
/* check for duplicate events */
for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
{
if(PwrSaveIfs[cnt] == client_lan_ip)
{
IPACMDBG("The client 0x%x is already in power save\n", client_lan_ip);
return 0;
}
}
for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
{
if(PwrSaveIfs[cnt] == 0)
{
PwrSaveIfs[cnt] = client_lan_ip;
break;
}
}
for(cnt = 0; cnt < max_entries; cnt++)
{
if(cache[cnt].private_ip == client_lan_ip &&
cache[cnt].enabled == true)
{
if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
{
IPACMERR("unable to delete the rule\n");
continue;
}
cache[cnt].enabled = false;
cache[cnt].rule_hdl = 0;
}
}
return 0;
}
int NatApp::ResetPwrSaveIf(uint32_t client_lan_ip)
{
int cnt;
ipa_nat_ipv4_rule nat_rule;
IPACMDBG_H("Received ip address: 0x%x\n", client_lan_ip);
if(client_lan_ip == INVALID_IP_ADDR)
{
IPACMERR("Invalid ip address received\n");
return -1;
}
for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
{
if(PwrSaveIfs[cnt] == client_lan_ip)
{
PwrSaveIfs[cnt] = 0;
break;
}
}
for(cnt = 0; cnt < max_entries; cnt++)
{
IPACMDBG("cache (%d): enable %d, ip 0x%x\n", cnt, cache[cnt].enabled, cache[cnt].private_ip);
if(cache[cnt].private_ip == client_lan_ip &&
cache[cnt].enabled == false)
{
memset(&nat_rule, 0 , sizeof(nat_rule));
nat_rule.private_ip = cache[cnt].private_ip;
nat_rule.target_ip = cache[cnt].target_ip;
nat_rule.target_port = cache[cnt].target_port;
nat_rule.private_port = cache[cnt].private_port;
nat_rule.public_port = cache[cnt].public_port;
nat_rule.protocol = cache[cnt].protocol;
if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
{
IPACMERR("unable to add the rule delete from cache\n");
memset(&cache[cnt], 0, sizeof(cache[cnt]));
curCnt--;
continue;
}
cache[cnt].enabled = true;
IPACMDBG("On power reset added below rule successfully\n");
iptodot("Private IP", nat_rule.private_ip);
iptodot("Target IP", nat_rule.target_ip);
IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
IPACMDBG("Public Port:%d\n", nat_rule.public_port);
IPACMDBG("protocol: %d\n", nat_rule.protocol);
}
}
return -1;
}
uint32_t NatApp::GetTableHdl(uint32_t in_ip_addr)
{
if(in_ip_addr == pub_ip_addr)
{
return nat_table_hdl;
}
return -1;
}
void NatApp::AddTempEntry(const nat_table_entry *new_entry)
{
int cnt;
IPACMDBG("Received below Temp Nat entry\n");
iptodot("Private IP", new_entry->private_ip);
iptodot("Target IP", new_entry->target_ip);
IPACMDBG("Private Port: %d\t Target Port: %d\t", new_entry->private_port, new_entry->target_port);
IPACMDBG("protocolcol: %d\n", new_entry->protocol);
if(isAlgPort(new_entry->protocol, new_entry->private_port) ||
isAlgPort(new_entry->protocol, new_entry->target_port))
{
IPACMDBG("connection using ALG Port. Dont insert into nat cache\n");
return;
}
if(ChkForDup(new_entry))
{
return;
}
for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
{
if(temp[cnt].private_ip == new_entry->private_ip &&
temp[cnt].target_ip == new_entry->target_ip &&
temp[cnt].private_port == new_entry->private_port &&
temp[cnt].target_port == new_entry->target_port &&
temp[cnt].protocol == new_entry->protocol)
{
IPACMDBG("Received duplicate Temp entry\n");
return;
}
}
for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
{
if(temp[cnt].private_ip == 0 &&
temp[cnt].target_ip == 0)
{
memcpy(&temp[cnt], new_entry, sizeof(nat_table_entry));
IPACMDBG("Added Temp Entry\n");
return;
}
}
IPACMDBG("Unable to add temp entry, cache full\n");
return;
}
void NatApp::DeleteTempEntry(const nat_table_entry *entry)
{
int cnt;
IPACMDBG("Received below nat entry\n");
iptodot("Private IP", entry->private_ip);
iptodot("Target IP", entry->target_ip);
IPACMDBG("Private Port: %d\t Target Port: %d\n", entry->private_port, entry->target_port);
IPACMDBG("protocol: %d\n", entry->protocol);
for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
{
if(temp[cnt].private_ip == entry->private_ip &&
temp[cnt].target_ip == entry->target_ip &&
temp[cnt].private_port == entry->private_port &&
temp[cnt].target_port == entry->target_port &&
temp[cnt].protocol == entry->protocol)
{
memset(&temp[cnt], 0, sizeof(nat_table_entry));
IPACMDBG("Delete Temp Entry\n");
return;
}
}
IPACMDBG("No Such Temp Entry exists\n");
return;
}
void NatApp::FlushTempEntries(uint32_t ip_addr, bool isAdd,
bool isDummy)
{
int cnt;
int ret;
IPACMDBG_H("Received below with isAdd:%d ", isAdd);
iptodot("IP Address: ", ip_addr);
for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
{
if(temp[cnt].private_ip == ip_addr ||
temp[cnt].target_ip == ip_addr)
{
if(isAdd)
{
if(temp[cnt].public_ip == pub_ip_addr)
{
if (isDummy) {
/* To avoild DL expections for non IPA path */
temp[cnt].private_ip = temp[cnt].public_ip;
temp[cnt].private_port = temp[cnt].public_port;
IPACMDBG("Flushing dummy temp rule");
iptodot("Private IP", temp[cnt].private_ip);
}
ret = AddEntry(&temp[cnt]);
if(ret)
{
IPACMERR("unable to add temp entry: %d\n", ret);
continue;
}
}
}
memset(&temp[cnt], 0, sizeof(nat_table_entry));
}
}
return;
}
int NatApp::DelEntriesOnClntDiscon(uint32_t ip_addr)
{
int cnt, tmp = 0;
IPACMDBG_H("Received IP address: 0x%x\n", ip_addr);
if(ip_addr == INVALID_IP_ADDR)
{
IPACMERR("Invalid ip address received\n");
return -1;
}
for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
{
if(PwrSaveIfs[cnt] == ip_addr)
{
PwrSaveIfs[cnt] = 0;
IPACMDBG("Remove %d power save entry\n", cnt);
break;
}
}
for(cnt = 0; cnt < max_entries; cnt++)
{
if(cache[cnt].private_ip == ip_addr)
{
if(cache[cnt].enabled == true)
{
if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
{
IPACMERR("unable to delete the rule\n");
continue;
}
else
{
IPACMDBG("won't delete the rule\n");
cache[cnt].enabled = false;
tmp++;
}
}
IPACMDBG("won't delete the rule for entry %d, enabled %d\n",cnt, cache[cnt].enabled);
}
}
IPACMDBG("Deleted (but cached) %d entries\n", tmp);
return 0;
}
int NatApp::DelEntriesOnSTAClntDiscon(uint32_t ip_addr)
{
int cnt, tmp = curCnt;
IPACMDBG_H("Received IP address: 0x%x\n", ip_addr);
if(ip_addr == INVALID_IP_ADDR)
{
IPACMERR("Invalid ip address received\n");
return -1;
}
for(cnt = 0; cnt < max_entries; cnt++)
{
if(cache[cnt].target_ip == ip_addr)
{
if(cache[cnt].enabled == true)
{
if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
{
IPACMERR("unable to delete the rule\n");
continue;
}
}
memset(&cache[cnt], 0, sizeof(cache[cnt]));
curCnt--;
}
}
IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
return 0;
}
void NatApp::CacheEntry(const nat_table_entry *rule)
{
int cnt;
if(rule->private_ip == 0 ||
rule->target_ip == 0 ||
rule->private_port == 0 ||
rule->target_port == 0 ||
rule->protocol == 0)
{
IPACMERR("Invalid Connection, ignoring it\n");
return;
}
if(!ChkForDup(rule))
{
for(cnt=0; cnt < max_entries; cnt++)
{
if(cache[cnt].private_ip == 0 &&
cache[cnt].target_ip == 0 &&
cache[cnt].private_port == 0 &&
cache[cnt].target_port == 0 &&
cache[cnt].protocol == 0)
{
break;
}
}
if(max_entries == cnt)
{
IPACMERR("Error: Unable to add, reached maximum rules\n");
return;
}
else
{
cache[cnt].enabled = false;
cache[cnt].rule_hdl = 0;
cache[cnt].private_ip = rule->private_ip;
cache[cnt].target_ip = rule->target_ip;
cache[cnt].target_port = rule->target_port;
cache[cnt].private_port = rule->private_port;
cache[cnt].protocol = rule->protocol;
cache[cnt].timestamp = 0;
cache[cnt].public_port = rule->public_port;
cache[cnt].public_ip = rule->public_ip;
cache[cnt].dst_nat = rule->dst_nat;
curCnt++;
}
}
else
{
IPACMERR("Duplicate rule. Ignore it\n");
return;
}
IPACMDBG("Cached rule(%d) successfully\n", cnt);
return;
}
void NatApp::Read_TcpUdp_Timeout(void) {
FILE *udp_fd = NULL, *tcp_fd = NULL;
/* Read UDP timeout value */
udp_fd = fopen(IPACM_UDP_FULL_FILE_NAME, "r");
if (udp_fd == NULL) {
IPACMERR("unable to open %s\n", IPACM_UDP_FULL_FILE_NAME);
goto fail;
}
if (fscanf(udp_fd, "%d", &udp_timeout) != 1) {
IPACMERR("Error reading udp timeout\n");
}
IPACMDBG_H("udp timeout value: %d\n", udp_timeout);
/* Read TCP timeout value */
tcp_fd = fopen(IPACM_TCP_FULL_FILE_NAME, "r");
if (tcp_fd == NULL) {
IPACMERR("unable to open %s\n", IPACM_TCP_FULL_FILE_NAME);
goto fail;
}
if (fscanf(tcp_fd, "%d", &tcp_timeout) != 1) {
IPACMERR("Error reading tcp timeout\n");
}
IPACMDBG_H("tcp timeout value: %d\n", tcp_timeout);
fail:
if (udp_fd) {
fclose(udp_fd);
}
if (tcp_fd) {
fclose(tcp_fd);
}
return;
}

View File

@@ -0,0 +1,214 @@
/*
Copyright (c) 2013-2016, 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_EvtDispatcher.cpp
@brief
This file implements the IPAM event dispatcher functionality
@Author
*/
#include <string.h>
#include <pthread.h>
#include <IPACM_EvtDispatcher.h>
#include <IPACM_Neighbor.h>
#include "IPACM_CmdQueue.h"
#include "IPACM_Defs.h"
extern pthread_mutex_t mutex;
extern pthread_cond_t cond_var;
cmd_evts *IPACM_EvtDispatcher::head = NULL;
extern uint32_t ipacm_event_stats[IPACM_EVENT_MAX];
int IPACM_EvtDispatcher::PostEvt
(
ipacm_cmd_q_data *data
)
{
Message *item = NULL;
MessageQueue *MsgQueue = NULL;
if(data->event < IPA_EXTERNAL_EVENT_MAX)
{
IPACMDBG("Insert event into external queue.\n");
MsgQueue = MessageQueue::getInstanceExternal();
}
else
{
IPACMDBG("Insert event into internal queue.\n");
MsgQueue = MessageQueue::getInstanceInternal();
}
if(MsgQueue == NULL)
{
IPACMERR("unable to retrieve MsgQueue instance\n");
return IPACM_FAILURE;
}
item = new Message();
if(item == NULL)
{
IPACMERR("unable to create new message item\n");
return IPACM_FAILURE;
}
item->evt.callback_ptr = IPACM_EvtDispatcher::ProcessEvt;
memcpy(&item->evt.data, data, sizeof(ipacm_cmd_q_data));
if(pthread_mutex_lock(&mutex) != 0)
{
IPACMERR("unable to lock the mutex\n");
return IPACM_FAILURE;
}
IPACMDBG("Enqueing item\n");
MsgQueue->enqueue(item);
IPACMDBG("Enqueued item %p\n", item);
if(pthread_cond_signal(&cond_var) != 0)
{
IPACMDBG("unable to lock the mutex\n");
/* Release the mutex before you return failure */
if(pthread_mutex_unlock(&mutex) != 0)
{
IPACMERR("unable to unlock the mutex\n");
return IPACM_FAILURE;
}
return IPACM_FAILURE;
}
if(pthread_mutex_unlock(&mutex) != 0)
{
IPACMERR("unable to unlock the mutex\n");
return IPACM_FAILURE;
}
return IPACM_SUCCESS;
}
void IPACM_EvtDispatcher::ProcessEvt(ipacm_cmd_q_data *data)
{
cmd_evts *tmp = head, tmp1;
if(head == NULL)
{
IPACMDBG("Queue is empty\n");
}
while(tmp != NULL)
{
memcpy(&tmp1, tmp, sizeof(tmp1));
if(data->event == tmp1.event)
{
ipacm_event_stats[data->event]++;
tmp1.obj->event_callback(data->event, data->evt_data);
IPACMDBG(" Find matched registered events\n");
}
tmp = tmp1.next;
}
IPACMDBG(" Finished process events\n");
if(data->evt_data != NULL)
{
IPACMDBG("free the event:%d data: %p\n", data->event, data->evt_data);
free(data->evt_data);
}
return;
}
int IPACM_EvtDispatcher::registr(ipa_cm_event_id event, IPACM_Listener *obj)
{
cmd_evts *tmp = head,*nw;
nw = (cmd_evts *)malloc(sizeof(cmd_evts));
if(nw != NULL)
{
nw->event = event;
nw->obj = obj;
nw->next = NULL;
}
else
{
return IPACM_FAILURE;
}
if(head == NULL)
{
head = nw;
}
else
{
while(tmp->next)
{
tmp = tmp->next;
}
tmp->next = nw;
}
return IPACM_SUCCESS;
}
int IPACM_EvtDispatcher::deregistr(IPACM_Listener *param)
{
cmd_evts *tmp = head,*tmp1,*prev = head;
while(tmp != NULL)
{
if(tmp->obj == param)
{
tmp1 = tmp;
if(tmp == head)
{
head = head->next;
}
else if(tmp->next == NULL)
{
prev->next = NULL;
}
else
{
prev->next = tmp->next;
}
tmp = tmp->next;
free(tmp1);
}
else
{
prev = tmp;
tmp = tmp->next;
}
}
return IPACM_SUCCESS;
}

View File

@@ -0,0 +1,536 @@
/*
Copyright (c) 2013-2016, 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_Filtering.cpp
@brief
This file implements the IPACM filtering functionality.
@Author
Skylar Chang
*/
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "IPACM_Filtering.h"
#include <IPACM_Log.h>
#include "IPACM_Defs.h"
const char *IPACM_Filtering::DEVICE_NAME = "/dev/ipa";
IPACM_Filtering::IPACM_Filtering()
{
fd = open(DEVICE_NAME, O_RDWR);
if (fd < 0)
{
IPACMERR("Failed opening %s.\n", DEVICE_NAME);
}
}
IPACM_Filtering::~IPACM_Filtering()
{
close(fd);
}
bool IPACM_Filtering::DeviceNodeIsOpened()
{
return fd;
}
bool IPACM_Filtering::AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable)
{
int retval = 0;
IPACMDBG("Printing filter add attributes\n");
IPACMDBG("ip type: %d\n", ruleTable->ip);
IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
IPACMDBG("End point: %d and global value: %d\n", ruleTable->ep, ruleTable->global);
IPACMDBG("commit value: %d\n", ruleTable->commit);
for (int cnt=0; cnt<ruleTable->num_rules; cnt++)
{
IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", cnt,
ruleTable->rules[cnt].rule.attrib.attrib_mask);
}
retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE, ruleTable);
if (retval != 0)
{
IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
PERROR("unable to add filter rule:");
for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
{
if (ruleTable->rules[cnt].status != 0)
{
IPACMERR("Adding Filter rule:%d failed with status:%d\n",
cnt, ruleTable->rules[cnt].status);
}
}
return false;
}
for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
{
if(ruleTable->rules[cnt].status != 0)
{
IPACMERR("Adding Filter rule:%d failed with status:%d\n",
cnt, ruleTable->rules[cnt].status);
}
}
IPACMDBG("Added Filtering rule %p\n", ruleTable);
return true;
}
bool IPACM_Filtering::AddFilteringRuleAfter(struct ipa_ioc_add_flt_rule_after const *ruleTable)
{
#ifdef FEATURE_IPA_V3
int retval = 0;
IPACMDBG("Printing filter add attributes\n");
IPACMDBG("ip type: %d\n", ruleTable->ip);
IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
IPACMDBG("End point: %d\n", ruleTable->ep);
IPACMDBG("commit value: %d\n", ruleTable->commit);
retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE_AFTER, ruleTable);
for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
{
if(ruleTable->rules[cnt].status != 0)
{
IPACMERR("Adding Filter rule:%d failed with status:%d\n",
cnt, ruleTable->rules[cnt].status);
}
}
if (retval != 0)
{
IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
return false;
}
IPACMDBG("Added Filtering rule %p\n", ruleTable);
#endif
return true;
}
bool IPACM_Filtering::DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable)
{
int retval = 0;
retval = ioctl(fd, IPA_IOC_DEL_FLT_RULE, ruleTable);
if (retval != 0)
{
IPACMERR("Failed deleting Filtering rule %p\n", ruleTable);
return false;
}
IPACMDBG("Deleted Filtering rule %p\n", ruleTable);
return true;
}
bool IPACM_Filtering::Commit(enum ipa_ip_type ip)
{
int retval = 0;
retval = ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
if (retval != 0)
{
IPACMERR("failed committing Filtering rules.\n");
return false;
}
IPACMDBG("Committed Filtering rules to IPA HW.\n");
return true;
}
bool IPACM_Filtering::Reset(enum ipa_ip_type ip)
{
int retval = 0;
retval = ioctl(fd, IPA_IOC_RESET_FLT, ip);
retval |= ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
if (retval)
{
IPACMERR("failed resetting Filtering block.\n");
return false;
}
IPACMDBG("Reset command issued to IPA Filtering block.\n");
return true;
}
bool IPACM_Filtering::DeleteFilteringHdls
(
uint32_t *flt_rule_hdls,
ipa_ip_type ip,
uint8_t num_rules
)
{
struct ipa_ioc_del_flt_rule *flt_rule;
bool res = true;
int len = 0, cnt = 0;
const uint8_t UNIT_RULES = 1;
len = (sizeof(struct ipa_ioc_del_flt_rule)) + (UNIT_RULES * sizeof(struct ipa_flt_rule_del));
flt_rule = (struct ipa_ioc_del_flt_rule *)malloc(len);
if (flt_rule == NULL)
{
IPACMERR("unable to allocate memory for del filter rule\n");
return false;
}
for (cnt = 0; cnt < num_rules; cnt++)
{
memset(flt_rule, 0, len);
flt_rule->commit = 1;
flt_rule->num_hdls = UNIT_RULES;
flt_rule->ip = ip;
if (flt_rule_hdls[cnt] == 0)
{
IPACMERR("invalid filter handle passed, ignoring it: %d\n", cnt)
}
else
{
flt_rule->hdl[0].status = -1;
flt_rule->hdl[0].hdl = flt_rule_hdls[cnt];
IPACMDBG("Deleting filter hdl:(0x%x) with ip type: %d\n", flt_rule_hdls[cnt], ip);
if (DeleteFilteringRule(flt_rule) == false)
{
PERROR("Filter rule deletion failed!\n");
res = false;
goto fail;
}
else
{
if (flt_rule->hdl[0].status != 0)
{
IPACMERR("Filter rule hdl 0x%x deletion failed with error:%d\n",
flt_rule->hdl[0].hdl, flt_rule->hdl[0].status);
res = false;
goto fail;
}
}
}
}
fail:
free(flt_rule);
return res;
}
bool IPACM_Filtering::AddWanDLFilteringRule(struct ipa_ioc_add_flt_rule const *rule_table_v4, struct ipa_ioc_add_flt_rule const * rule_table_v6, uint8_t mux_id)
{
int ret = 0, cnt, num_rules = 0, pos = 0;
ipa_install_fltr_rule_req_msg_v01 qmi_rule_msg;
#ifdef FEATURE_IPA_V3
ipa_install_fltr_rule_req_ex_msg_v01 qmi_rule_ex_msg;
#endif
int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
if(fd_wwan_ioctl < 0)
{
IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
return false;
}
if(rule_table_v4 != NULL)
{
num_rules += rule_table_v4->num_rules;
IPACMDBG_H("Get %d WAN DL IPv4 filtering rules.\n", rule_table_v4->num_rules);
}
if(rule_table_v6 != NULL)
{
num_rules += rule_table_v6->num_rules;
IPACMDBG_H("Get %d WAN DL IPv6 filtering rules.\n", rule_table_v6->num_rules);
}
/* if it is not IPA v3, use old QMI format */
#ifndef FEATURE_IPA_V3
if(num_rules > QMI_IPA_MAX_FILTERS_V01)
{
IPACMERR("The number of filtering rules exceed limit.\n");
close(fd_wwan_ioctl);
return false;
}
else
{
memset(&qmi_rule_msg, 0, sizeof(qmi_rule_msg));
if (num_rules > 0)
{
qmi_rule_msg.filter_spec_list_valid = true;
}
else
{
qmi_rule_msg.filter_spec_list_valid = false;
}
qmi_rule_msg.filter_spec_list_len = num_rules;
qmi_rule_msg.source_pipe_index_valid = 0;
IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
if(rule_table_v4 != NULL)
{
for(cnt = rule_table_v4->num_rules - 1; cnt >= 0; cnt--)
{
if (pos < QMI_IPA_MAX_FILTERS_V01)
{
qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
&rule_table_v4->rules[cnt].rule.eq_attrib,
sizeof(struct ipa_filter_rule_type_v01));
pos++;
}
else
{
IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
}
}
}
if(rule_table_v6 != NULL)
{
for(cnt = rule_table_v6->num_rules - 1; cnt >= 0; cnt--)
{
if (pos < QMI_IPA_MAX_FILTERS_V01)
{
qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
&rule_table_v6->rules[cnt].rule.eq_attrib,
sizeof(struct ipa_filter_rule_type_v01));
pos++;
}
else
{
IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
}
}
}
ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE, &qmi_rule_msg);
if (ret != 0)
{
IPACMERR("Failed adding Filtering rule %p with ret %d\n ", &qmi_rule_msg, ret);
close(fd_wwan_ioctl);
return false;
}
}
/* if it is IPA v3, use new QMI format */
#else
if(num_rules > QMI_IPA_MAX_FILTERS_EX_V01)
{
IPACMERR("The number of filtering rules exceed limit.\n");
close(fd_wwan_ioctl);
return false;
}
else
{
memset(&qmi_rule_ex_msg, 0, sizeof(qmi_rule_ex_msg));
if (num_rules > 0)
{
qmi_rule_ex_msg.filter_spec_ex_list_valid = true;
}
else
{
qmi_rule_ex_msg.filter_spec_ex_list_valid = false;
}
qmi_rule_ex_msg.filter_spec_ex_list_len = num_rules;
qmi_rule_ex_msg.source_pipe_index_valid = 0;
IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
if(rule_table_v4 != NULL)
{
for(cnt = rule_table_v4->num_rules - 1; cnt >= 0; cnt--)
{
if (pos < QMI_IPA_MAX_FILTERS_EX_V01)
{
qmi_rule_ex_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
qmi_rule_ex_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
qmi_rule_ex_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
qmi_rule_ex_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
qmi_rule_ex_msg.filter_spec_ex_list[pos].mux_id = mux_id;
qmi_rule_ex_msg.filter_spec_ex_list[pos].rule_id = rule_table_v4->rules[cnt].rule.rule_id;
qmi_rule_ex_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v4->rules[cnt].rule.hashable;
memcpy(&qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_rule,
&rule_table_v4->rules[cnt].rule.eq_attrib,
sizeof(struct ipa_filter_rule_type_v01));
pos++;
}
else
{
IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_EX_V01, pos);
}
}
}
if(rule_table_v6 != NULL)
{
for(cnt = rule_table_v6->num_rules - 1; cnt >= 0; cnt--)
{
if (pos < QMI_IPA_MAX_FILTERS_EX_V01)
{
qmi_rule_ex_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
qmi_rule_ex_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
qmi_rule_ex_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
qmi_rule_ex_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
qmi_rule_ex_msg.filter_spec_ex_list[pos].mux_id = mux_id;
qmi_rule_ex_msg.filter_spec_ex_list[pos].rule_id = rule_table_v6->rules[cnt].rule.rule_id;
qmi_rule_ex_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v6->rules[cnt].rule.hashable;
memcpy(&qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_rule,
&rule_table_v6->rules[cnt].rule.eq_attrib,
sizeof(struct ipa_filter_rule_type_v01));
pos++;
}
else
{
IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_EX_V01, pos);
}
}
}
ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE_EX, &qmi_rule_ex_msg);
if (ret != 0)
{
IPACMERR("Failed adding Filtering rule %p with ret %d\n ", &qmi_rule_ex_msg, ret);
close(fd_wwan_ioctl);
return false;
}
}
#endif
close(fd_wwan_ioctl);
return true;
}
bool IPACM_Filtering::SendFilteringRuleIndex(struct ipa_fltr_installed_notif_req_msg_v01* table)
{
int ret = 0;
int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
if(fd_wwan_ioctl < 0)
{
IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
return false;
}
ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE_INDEX, table);
if (ret != 0)
{
IPACMERR("Failed adding filtering rule index %p with ret %d\n", table, ret);
close(fd_wwan_ioctl);
return false;
}
IPACMDBG("Added Filtering rule index %p\n", table);
close(fd_wwan_ioctl);
return true;
}
ipa_filter_action_enum_v01 IPACM_Filtering::GetQmiFilterAction(ipa_flt_action action)
{
switch(action)
{
case IPA_PASS_TO_ROUTING:
return QMI_IPA_FILTER_ACTION_ROUTING_V01;
case IPA_PASS_TO_SRC_NAT:
return QMI_IPA_FILTER_ACTION_SRC_NAT_V01;
case IPA_PASS_TO_DST_NAT:
return QMI_IPA_FILTER_ACTION_DST_NAT_V01;
case IPA_PASS_TO_EXCEPTION:
return QMI_IPA_FILTER_ACTION_EXCEPTION_V01;
default:
return IPA_FILTER_ACTION_ENUM_MAX_ENUM_VAL_V01;
}
}
bool IPACM_Filtering::ModifyFilteringRule(struct ipa_ioc_mdfy_flt_rule* ruleTable)
{
int i, ret = 0;
IPACMDBG("Printing filtering add attributes\n");
IPACMDBG("IP type: %d Number of rules: %d commit value: %d\n", ruleTable->ip, ruleTable->num_rules, ruleTable->commit);
for (i=0; i<ruleTable->num_rules; i++)
{
IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", i, ruleTable->rules[i].rule.attrib.attrib_mask);
}
ret = ioctl(fd, IPA_IOC_MDFY_FLT_RULE, ruleTable);
if (ret != 0)
{
IPACMERR("Failed modifying filtering rule %p\n", ruleTable);
for (i = 0; i < ruleTable->num_rules; i++)
{
if (ruleTable->rules[i].status != 0)
{
IPACMERR("Modifying filter rule %d failed\n", i);
}
}
return false;
}
IPACMDBG("Modified filtering rule %p\n", ruleTable);
return true;
}

View File

@@ -0,0 +1,236 @@
/*
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.
*/
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "IPACM_Header.h"
#include "IPACM_Log.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//All interaction through the driver are made through this inode.
static const char *DEVICE_NAME = "/dev/ipa";
/////////////////////////////////////////////////////////////////////////////////////////////////////////
IPACM_Header::IPACM_Header()
{
m_fd = open(DEVICE_NAME, O_RDWR);
if (-1 == m_fd)
{
IPACMERR("Failed to open %s in IPACM_Header test application constructor.\n", DEVICE_NAME);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
IPACM_Header::~IPACM_Header()
{
if (-1 != m_fd)
{
close(m_fd);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IPACM_Header::DeviceNodeIsOpened()
{
return (-1 != m_fd);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IPACM_Header::AddHeader(struct ipa_ioc_add_hdr *pHeaderTableToAdd)
{
int nRetVal = 0;
//call the Driver ioctl in order to add header
nRetVal = ioctl(m_fd, IPA_IOC_ADD_HDR, pHeaderTableToAdd);
IPACMDBG("return value: %d\n", nRetVal);
return (-1 != nRetVal);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IPACM_Header::DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTableToDelete)
{
int nRetVal = 0;
//call the Driver ioctl in order to remove header
nRetVal = ioctl(m_fd, IPA_IOC_DEL_HDR, pHeaderTableToDelete);
IPACMDBG("return value: %d\n", nRetVal);
return (-1 != nRetVal);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IPACM_Header::Commit()
{
int nRetVal = 0;
nRetVal = ioctl(m_fd, IPA_IOC_COMMIT_HDR);
IPACMDBG("return value: %d\n", nRetVal);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IPACM_Header::Reset()
{
int nRetVal = 0;
nRetVal = ioctl(m_fd, IPA_IOC_RESET_HDR);
nRetVal |= ioctl(m_fd, IPA_IOC_COMMIT_HDR);
IPACMDBG("return value: %d\n", nRetVal);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IPACM_Header::GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct)
{
int retval = 0;
if (!DeviceNodeIsOpened()) return false;
retval = ioctl(m_fd, IPA_IOC_GET_HDR, pHeaderStruct);
if (retval)
{
IPACMERR("IPA_IOC_GET_HDR ioctl failed, routingTable =0x%p, retval=0x%x.\n", pHeaderStruct, retval);
return false;
}
IPACMDBG("IPA_IOC_GET_HDR ioctl issued to IPA header insertion block.\n");
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
bool IPACM_Header::CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct)
{
int retval = 0;
if (!DeviceNodeIsOpened()) return false;
retval = ioctl(m_fd, IPA_IOC_COPY_HDR, pCopyHeaderStruct);
if (retval)
{
IPACMERR("IPA_IOC_COPY_HDR ioctl failed, retval=0x%x.\n", retval);
return false;
}
IPACMDBG("IPA_IOC_COPY_HDR ioctl issued to IPA header insertion block.\n");
return true;
}
bool IPACM_Header::DeleteHeaderHdl(uint32_t hdr_hdl)
{
const uint8_t NUM_HDLS = 1;
struct ipa_ioc_del_hdr *pHeaderDescriptor = NULL;
struct ipa_hdr_del *hd_rule_entry;
int len = 0;
bool res = true;
if (hdr_hdl == 0)
{
IPACMERR("Invalid header handle passed. Ignoring it\n");
return false;
}
len = (sizeof(struct ipa_ioc_del_hdr)) + (NUM_HDLS * sizeof(struct ipa_hdr_del));
pHeaderDescriptor = (struct ipa_ioc_del_hdr *)malloc(len);
if (pHeaderDescriptor == NULL)
{
IPACMERR("Unable to allocate memory for del header\n");
return false;
}
memset(pHeaderDescriptor, 0, len);
pHeaderDescriptor->commit = true;
pHeaderDescriptor->num_hdls = NUM_HDLS;
hd_rule_entry = &pHeaderDescriptor->hdl[0];
hd_rule_entry->hdl = hdr_hdl;
hd_rule_entry->status = -1;
IPACMDBG("Deleting Header hdl:(%x)\n", hd_rule_entry->hdl);
if ((false == DeleteHeader(pHeaderDescriptor)) ||
(hd_rule_entry->status))
{
IPACMERR("Header hdl:(%x) deletion failed! status: %d\n", hd_rule_entry->hdl,hd_rule_entry->status);
res = false;
goto fail;
}
IPACMDBG_H("Deleted Header hdl:(%x) successfully\n", hd_rule_entry->hdl);
fail:
free(pHeaderDescriptor);
return res;
}
bool IPACM_Header::AddHeaderProcCtx(struct ipa_ioc_add_hdr_proc_ctx* pHeader)
{
int ret = 0;
//call the Driver ioctl to add header processing context
ret = ioctl(m_fd, IPA_IOC_ADD_HDR_PROC_CTX, pHeader);
return (ret == 0);
}
bool IPACM_Header::DeleteHeaderProcCtx(uint32_t hdl)
{
int len, ret;
struct ipa_ioc_del_hdr_proc_ctx* pHeaderTable = NULL;
len = sizeof(struct ipa_ioc_del_hdr_proc_ctx) + sizeof(struct ipa_hdr_proc_ctx_del);
pHeaderTable = (struct ipa_ioc_del_hdr_proc_ctx*)malloc(len);
if(pHeaderTable == NULL)
{
IPACMERR("Failed to allocate buffer.\n");
return false;
}
memset(pHeaderTable, 0, len);
pHeaderTable->commit = 1;
pHeaderTable->num_hdls = 1;
pHeaderTable->hdl[0].hdl = hdl;
ret = ioctl(m_fd, IPA_IOC_DEL_HDR_PROC_CTX, pHeaderTable);
if(ret != 0)
{
IPACMERR("Failed to delete hdr proc ctx: return value %d, status %d\n",
ret, pHeaderTable->hdl[0].status);
}
free(pHeaderTable);
return (ret == 0);
}

View File

@@ -0,0 +1,995 @@
/*
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.Z
*/
/*!
@file
IPACM_Iface.cpp
@brief
This file implements the basis Iface functionality.
@Author
Skylar Chang
*/
#include <fcntl.h>
#include <sys/ioctl.h>
#include <IPACM_Netlink.h>
#include <IPACM_Iface.h>
#include <IPACM_Lan.h>
#include <IPACM_Wan.h>
#include <IPACM_Wlan.h>
#include <string.h>
extern "C"
{
#include <ifaddrs.h>
}
const char *IPACM_Iface::DEVICE_NAME = "/dev/ipa";
IPACM_Routing IPACM_Iface::m_routing;
IPACM_Filtering IPACM_Iface::m_filtering;
IPACM_Header IPACM_Iface::m_header;
IPACM_Config *IPACM_Iface::ipacmcfg = IPACM_Config::GetInstance();
IPACM_Iface::IPACM_Iface(int iface_index)
{
ip_type = IPACM_IP_NULL; /* initially set invalid */
num_dft_rt_v6 = 0;
softwarerouting_act = false;
ipa_if_num = iface_index;
ipa_if_cate = IPACM_Iface::ipacmcfg->iface_table[iface_index].if_cat;
iface_query = NULL;
tx_prop = NULL;
rx_prop = NULL;
memcpy(dev_name,
IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name,
sizeof(IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name));
memset(dft_v4fl_rule_hdl, 0, sizeof(dft_v4fl_rule_hdl));
memset(dft_v6fl_rule_hdl, 0, sizeof(dft_v6fl_rule_hdl));
memset(dft_rt_rule_hdl, 0, sizeof(dft_rt_rule_hdl));
memset(software_routing_fl_rule_hdl, 0, sizeof(software_routing_fl_rule_hdl));
memset(ipv6_addr, 0, sizeof(ipv6_addr));
query_iface_property();
IPACMDBG_H(" create iface-index(%d) constructor\n", ipa_if_num);
return;
}
/* software routing enable */
int IPACM_Iface::handle_software_routing_enable(void)
{
int res = IPACM_SUCCESS;
struct ipa_flt_rule_add flt_rule_entry;
ipa_ioc_add_flt_rule *m_pFilteringTable;
IPACMDBG("\n");
if (softwarerouting_act == true)
{
IPACMDBG("already setup software_routing rule for (%s)iface ip-family %d\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
return IPACM_SUCCESS;
}
if(rx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
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)
{
IPACMERR("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->num_rules = (uint8_t)1;
/* Configuring Software-Routing Filtering Rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = false;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
#ifdef FEATURE_IPA_V3
flt_rule_entry.rule.hashable = true;
#endif
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* check iface is v4 or v6 or both*/
// if (ip_type == IPA_IP_MAX)
// {
/* handle v4 */
m_pFilteringTable->ip = IPA_IP_v4;
if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
else if (m_pFilteringTable->rules[0].status)
{
IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
res = IPACM_FAILURE;
goto fail;
}
IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
/* copy filter hdls */
software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
/* handle v6*/
m_pFilteringTable->ip = IPA_IP_v6;
if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
else if (m_pFilteringTable->rules[0].status)
{
IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
res = IPACM_FAILURE;
goto fail;
}
IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
/* copy filter hdls */
software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
softwarerouting_act = true;
#if 0
}
else
{
if (ip_type == IPA_IP_v4)
{
m_pFilteringTable->ip = IPA_IP_v4;
}
else
{
m_pFilteringTable->ip = IPA_IP_v6;
}
if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
else if (m_pFilteringTable->rules[0].status)
{
IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
res = IPACM_FAILURE;
goto fail;
}
IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, ip_type, 1);
IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
/* copy filter hdls */
if (ip_type == IPA_IP_v4)
{
software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
}
else
{
software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
}
softwarerouting_act = true;
}
#endif
fail:
free(m_pFilteringTable);
return res;
}
/* software routing disable */
int IPACM_Iface::handle_software_routing_disable(void)
{
int res = IPACM_SUCCESS;
ipa_ip_type ip;
uint32_t flt_hdl;
if (rx_prop == NULL)
{
IPACMDBG("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
if (softwarerouting_act == false)
{
IPACMDBG("already delete software_routing rule for (%s)iface ip-family %d\n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
return IPACM_SUCCESS;
}
// if (ip_type == IPA_IP_MAX)
// {
/* ipv4 case */
if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[0],
IPA_IP_v4, 1) == false)
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
/* ipv6 case */
if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[1],
IPA_IP_v6, 1) == false)
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
softwarerouting_act = false;
#if 0
}
else
{
if (ip_type == IPA_IP_v4)
{
ip = IPA_IP_v4;
}
else
{
ip = IPA_IP_v6;
}
if (ip_type == IPA_IP_v4)
{
flt_hdl = software_routing_fl_rule_hdl[0];
}
else
{
flt_hdl = software_routing_fl_rule_hdl[1];
}
if (m_filtering.DeleteFilteringHdls(&flt_hdl, ip, 1) == false)
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, ip, 1);
softwarerouting_act = false;
}
#endif
fail:
return res;
}
/* Query ipa_interface_index by given linux interface_index */
int IPACM_Iface::iface_ipa_index_query
(
int interface_index
)
{
int fd;
int link = INVALID_IFACE;
int i = 0;
struct ifreq ifr;
if(IPACM_Iface::ipacmcfg->iface_table == NULL)
{
IPACMERR("Iface table in IPACM_Config is not available.\n");
return link;
}
/* Search known linux interface-index and map to IPA interface-index*/
for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
{
if (interface_index == IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index)
{
link = i;
IPACMDBG("Interface (%s) found: linux(%d) ipa(%d) \n",
IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index,
link);
return link;
break;
}
}
/* Search/Configure linux interface-index and map it to IPA interface-index */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
PERROR("get interface name socket create failed");
return IPACM_FAILURE;
}
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_ifindex = interface_index;
IPACMDBG_H("Interface index %d\n", interface_index);
if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
{
PERROR("call_ioctl_on_dev: ioctl failed:");
close(fd);
return IPACM_FAILURE;
}
close(fd);
IPACMDBG_H("Received interface name %s\n", ifr.ifr_name);
for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
{
if (strncmp(ifr.ifr_name,
IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
sizeof(IPACM_Iface::ipacmcfg->iface_table[i].iface_name)) == 0)
{
IPACMDBG_H("Interface (%s) linux(%d) mapped to ipa(%d) \n", ifr.ifr_name,
IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index, i);
link = i;
IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index = interface_index;
break;
}
}
return link;
}
/* Query ipa_interface ipv4_addr by given linux interface_index */
void IPACM_Iface::iface_addr_query
(
int interface_index
)
{
int fd;
struct ifreq ifr;
struct ifaddrs *myaddrs, *ifa;
ipacm_cmd_q_data evt_data;
ipacm_event_data_addr *data_addr;
struct in_addr iface_ipv4;
/* use linux interface-index to find interface name */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
PERROR("get interface name socket create failed");
return ;
}
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_ifindex = interface_index;
IPACMDBG_H("Interface index %d\n", interface_index);
if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
{
PERROR("call_ioctl_on_dev: ioctl failed:");
close(fd);
return ;
}
IPACMDBG_H("Interface index %d name: %s\n", interface_index,ifr.ifr_name);
close(fd);
/* query ipv4/v6 address */
if(getifaddrs(&myaddrs) != 0)
{
IPACMERR("getifaddrs");
return ;
}
for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL)
continue;
if (!(ifa->ifa_flags & IFF_UP))
continue;
if(strcmp(ifr.ifr_name,ifa->ifa_name) == 0) // find current iface
{
IPACMDBG_H("Internal post new_addr event for iface %s\n", ifa->ifa_name);
switch (ifa->ifa_addr->sa_family)
{
case AF_INET:
{
struct sockaddr_in *s4 = (struct sockaddr_in *)ifa->ifa_addr;
IPACMDBG_H("ipv4 address %s\n",inet_ntoa(s4->sin_addr));
iface_ipv4 = s4->sin_addr;
/* post new_addr event to command queue */
data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
if(data_addr == NULL)
{
IPACMERR("unable to allocate memory for event data_addr\n");
freeifaddrs(myaddrs);
return ;
}
data_addr->iptype = IPA_IP_v4;
data_addr->if_index = interface_index;
data_addr->ipv4_addr = iface_ipv4.s_addr;
data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
IPACMDBG_H("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv4 addr:0x%x\n",
data_addr->if_index,
data_addr->ipv4_addr);
evt_data.event = IPA_ADDR_ADD_EVENT;
evt_data.evt_data = data_addr;
IPACM_EvtDispatcher::PostEvt(&evt_data);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ifa->ifa_addr;
/* post new_addr event to command queue */
data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
if(data_addr == NULL)
{
IPACMERR("unable to allocate memory for event data_addr\n");
freeifaddrs(myaddrs);
return ;
}
data_addr->iptype = IPA_IP_v6;
data_addr->if_index = interface_index;
memcpy(data_addr->ipv6_addr,
&s6->sin6_addr,
sizeof(data_addr->ipv6_addr));
data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
IPACMDBG_H("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv6 addr:0x%x:%x:%x:%x\n",
data_addr->if_index,
data_addr->ipv6_addr[0], data_addr->ipv6_addr[1], data_addr->ipv6_addr[2], data_addr->ipv6_addr[3]);
evt_data.event = IPA_ADDR_ADD_EVENT;
evt_data.evt_data = data_addr;
IPACM_EvtDispatcher::PostEvt(&evt_data);
break;
}
default:
continue;
}
}
}
freeifaddrs(myaddrs);
return ;
}
/*Query the IPA endpoint property */
int IPACM_Iface::query_iface_property(void)
{
int res = IPACM_SUCCESS, fd = 0;
uint32_t cnt=0;
fd = open(DEVICE_NAME, O_RDWR);
IPACMDBG("iface query-property \n");
if (0 == fd)
{
IPACMERR("Failed opening %s.\n", DEVICE_NAME);
return IPACM_FAILURE;
}
iface_query = (struct ipa_ioc_query_intf *)
calloc(1, sizeof(struct ipa_ioc_query_intf));
if(iface_query == NULL)
{
IPACMERR("Unable to allocate iface_query memory.\n");
close(fd);
return IPACM_FAILURE;
}
IPACMDBG_H("iface name %s\n", dev_name);
memcpy(iface_query->name, dev_name, sizeof(dev_name));
if (ioctl(fd, IPA_IOC_QUERY_INTF, iface_query) < 0)
{
PERROR("ioctl IPA_IOC_QUERY_INTF failed\n");
/* iface_query memory will free when iface-down*/
res = IPACM_FAILURE;
}
if(iface_query->num_tx_props > 0)
{
tx_prop = (struct ipa_ioc_query_intf_tx_props *)
calloc(1, sizeof(struct ipa_ioc_query_intf_tx_props) +
iface_query->num_tx_props * sizeof(struct ipa_ioc_tx_intf_prop));
if(tx_prop == NULL)
{
IPACMERR("Unable to allocate tx_prop memory.\n");
close(fd);
return IPACM_FAILURE;
}
memcpy(tx_prop->name, dev_name, sizeof(tx_prop->name));
tx_prop->num_tx_props = iface_query->num_tx_props;
if (ioctl(fd, IPA_IOC_QUERY_INTF_TX_PROPS, tx_prop) < 0)
{
PERROR("ioctl IPA_IOC_QUERY_INTF_TX_PROPS failed\n");
/* tx_prop memory will free when iface-down*/
res = IPACM_FAILURE;
}
if (res != IPACM_FAILURE)
{
for (cnt = 0; cnt < tx_prop->num_tx_props; cnt++)
{
IPACMDBG_H("Tx(%d):attrib-mask:0x%x, ip-type: %d, dst_pipe: %d, alt_dst_pipe: %d, header: %s\n",
cnt, tx_prop->tx[cnt].attrib.attrib_mask,
tx_prop->tx[cnt].ip, tx_prop->tx[cnt].dst_pipe,
tx_prop->tx[cnt].alt_dst_pipe,
tx_prop->tx[cnt].hdr_name);
if (tx_prop->tx[cnt].dst_pipe == 0)
{
IPACMERR("Tx(%d): wrong tx property: dst_pipe: 0.\n", cnt);
close(fd);
return IPACM_FAILURE;
}
if (tx_prop->tx[cnt].alt_dst_pipe == 0 &&
((memcmp(dev_name, "wlan0", sizeof("wlan0")) == 0) ||
(memcmp(dev_name, "wlan1", sizeof("wlan1")) == 0)))
{
IPACMERR("Tx(%d): wrong tx property: alt_dst_pipe: 0. \n", cnt);
close(fd);
return IPACM_FAILURE;
}
}
}
}
if (iface_query->num_rx_props > 0)
{
rx_prop = (struct ipa_ioc_query_intf_rx_props *)
calloc(1, sizeof(struct ipa_ioc_query_intf_rx_props) +
iface_query->num_rx_props * sizeof(struct ipa_ioc_rx_intf_prop));
if(rx_prop == NULL)
{
IPACMERR("Unable to allocate rx_prop memory.\n");
close(fd);
return IPACM_FAILURE;
}
memcpy(rx_prop->name, dev_name,
sizeof(rx_prop->name));
rx_prop->num_rx_props = iface_query->num_rx_props;
if (ioctl(fd, IPA_IOC_QUERY_INTF_RX_PROPS, rx_prop) < 0)
{
PERROR("ioctl IPA_IOC_QUERY_INTF_RX_PROPS failed\n");
/* rx_prop memory will free when iface-down*/
res = IPACM_FAILURE;
}
if (res != IPACM_FAILURE)
{
for (cnt = 0; cnt < rx_prop->num_rx_props; cnt++)
{
IPACMDBG_H("Rx(%d):attrib-mask:0x%x, ip-type: %d, src_pipe: %d\n",
cnt, rx_prop->rx[cnt].attrib.attrib_mask, rx_prop->rx[cnt].ip, rx_prop->rx[cnt].src_pipe);
}
}
}
/* Add Natting iface to IPACM_Config if there is Rx/Tx property */
if (rx_prop != NULL || tx_prop != NULL)
{
IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
}
close(fd);
return res;
}
/*Configure the initial filter rules */
int IPACM_Iface::init_fl_rule(ipa_ip_type iptype)
{
int res = IPACM_SUCCESS, len = 0;
struct ipa_flt_rule_add flt_rule_entry;
ipa_ioc_add_flt_rule *m_pFilteringTable;
/* Adding this hack because WLAN may not registered for Rx-endpoint, other ifaces will always have*/
const char *dev_wlan0="wlan0";
const char *dev_wlan1="wlan1";
const char *dev_ecm0="ecm0";
/* ADD corresponding ipa_rm_resource_name of RX-endpoint before adding all IPV4V6 FT-rules */
if((IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat== WAN_IF) || (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat== EMBMS_IF))
{
IPACMDBG_H(" NOT add producer dependency on dev %s with registered rx-prop cat:%d \n", dev_name, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat);
}
else
{
if(rx_prop != NULL)
{
IPACMDBG_H("dev %s add producer dependency\n", dev_name);
IPACMDBG_H("depend Got pipe %d rm index : %d \n", rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe],false);
}
else
{
/* only wlan may take software-path, not register Rx-property*/
if(strcmp(dev_name,dev_wlan0) == 0 || strcmp(dev_name,dev_wlan1) == 0)
{
IPACMDBG_H("dev %s add producer dependency\n", dev_name);
IPACMDBG_H("depend Got piperm index : %d \n", IPA_RM_RESOURCE_HSIC_PROD);
IPACM_Iface::ipacmcfg->AddRmDepend(IPA_RM_RESOURCE_HSIC_PROD,true);
}
if(strcmp(dev_name,dev_ecm0) == 0)
{
IPACMDBG_H("dev %s add producer dependency\n", dev_name);
IPACMDBG_H("depend Got piperm index : %d \n", IPA_RM_RESOURCE_USB_PROD);
IPACM_Iface::ipacmcfg->AddRmDepend(IPA_RM_RESOURCE_USB_PROD,true);
}
}
}
if (rx_prop == NULL)
{
IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
return IPACM_SUCCESS;
}
/* construct ipa_ioc_add_flt_rule with default filter rules */
if (iptype == IPA_IP_v4)
{
len = sizeof(struct ipa_ioc_add_flt_rule) +
(IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
if (!m_pFilteringTable)
{
IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
return IPACM_FAILURE;
}
m_pFilteringTable->commit = 1;
m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
m_pFilteringTable->global = false;
m_pFilteringTable->ip = iptype;
m_pFilteringTable->num_rules = (uint8_t)IPV4_DEFAULT_FILTERTING_RULES;
/* Configuring Fragment Filtering Rule */
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.rule.retain_hdr = 1;
flt_rule_entry.at_rear = true;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
#ifdef FEATURE_IPA_V3
flt_rule_entry.at_rear = false;
flt_rule_entry.rule.hashable = false;
#endif
IPACMDBG_H("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
memcpy(&flt_rule_entry.rule.attrib,
&rx_prop->rx[0].attrib,
sizeof(flt_rule_entry.rule.attrib));
flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* Configuring Multicast Filtering Rule */
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 = 0xF0000000;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000;
#ifdef FEATURE_IPA_V3
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.hashable = true;
#endif
memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* Configuring Broadcast Filtering Rule */
flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF;
#ifdef FEATURE_IPA_V3
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.hashable = true;
#endif
memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
/* copy filter hdls */
for (int i = 0; i < IPV4_DEFAULT_FILTERTING_RULES; i++)
{
if (m_pFilteringTable->rules[i].status == 0)
{
dft_v4fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
IPACMDBG_H("Default v4 filter Rule %d HDL:0x%x\n", i, dft_v4fl_rule_hdl[i]);
}
else
{
IPACMERR("Failed adding default v4 Filtering rule %d\n", i);
}
}
}
}
else
{
len = sizeof(struct ipa_ioc_add_flt_rule) +
(IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
if (!m_pFilteringTable)
{
IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
return IPACM_FAILURE;
}
m_pFilteringTable->commit = 1;
m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
m_pFilteringTable->global = false;
m_pFilteringTable->ip = iptype;
m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.rule.retain_hdr = 1;
flt_rule_entry.at_rear = true;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
/* Configuring Multicast Filtering Rule */
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] = 0xFF000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0XFF000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
#ifdef FEATURE_IPA_V3
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.hashable = true;
#endif
memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* Configuring fe80::/10 Link-Scoped Unicast Filtering Rule */
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0XFFC00000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFE800000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
#ifdef FEATURE_IPA_V3
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.hashable = true;
#endif
memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* Configuring fec0::/10 Reserved by IETF Filtering Rule */
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0XFFC00000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFEC00000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
#ifdef FEATURE_IPA_V3
flt_rule_entry.at_rear = true;
flt_rule_entry.rule.hashable = true;
#endif
memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#ifdef FEATURE_IPA_ANDROID
IPACMDBG_H("Add TCP ctrl rules: total num %d\n", IPV6_DEFAULT_FILTERTING_RULES);
memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
flt_rule_entry.at_rear = true;
flt_rule_entry.flt_rule_hdl = -1;
flt_rule_entry.status = -1;
flt_rule_entry.rule.retain_hdr = 1;
flt_rule_entry.rule.to_uc = 0;
flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
flt_rule_entry.rule.eq_attrib_type = 1;
flt_rule_entry.rule.eq_attrib.rule_eq_bitmap = 0;
if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA)
{
flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
flt_rule_entry.rule.eq_attrib.metadata_meq32_present = 1;
flt_rule_entry.rule.eq_attrib.metadata_meq32.offset = 0;
flt_rule_entry.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
flt_rule_entry.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
}
flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
flt_rule_entry.rule.eq_attrib.protocol_eq_present = 1;
flt_rule_entry.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
flt_rule_entry.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
/* add TCP FIN rule*/
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
memcpy(&(m_pFilteringTable->rules[3]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* add TCP SYN rule*/
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_SYN_SHIFT);
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_SYN_SHIFT);
memcpy(&(m_pFilteringTable->rules[4]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
/* add TCP RST rule*/
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
memcpy(&(m_pFilteringTable->rules[5]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
#endif
if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
{
IPACMERR("Error Adding Filtering rule, aborting...\n");
res = IPACM_FAILURE;
goto fail;
}
else
{
IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
/* copy filter hdls */
for (int i = 0;
i < IPV6_DEFAULT_FILTERTING_RULES;
i++)
{
if (m_pFilteringTable->rules[i].status == 0)
{
dft_v6fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
IPACMDBG_H("Default v6 Filter Rule %d HDL:0x%x\n", i, dft_v6fl_rule_hdl[i]);
}
else
{
IPACMERR("Failing adding v6 default IPV6 rule %d\n", i);
}
}
}
}
fail:
free(m_pFilteringTable);
return res;
}
/* get ipa interface name */
int IPACM_Iface::ipa_get_if_index
(
char * if_name,
int * if_index
)
{
int fd;
struct ifreq ifr;
if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
IPACMERR("get interface index socket create failed \n");
return IPACM_FAILURE;
}
memset(&ifr, 0, sizeof(struct ifreq));
(void)strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
IPACMDBG_H("interface name (%s)\n", if_name);
if (ioctl(fd,SIOCGIFINDEX , &ifr) < 0)
{
IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name);
close(fd);
return IPACM_FAILURE;
}
*if_index = ifr.ifr_ifindex;
IPACMDBG_H("Interface index %d\n", *if_index);
close(fd);
return IPACM_SUCCESS;
}
void IPACM_Iface::config_ip_type(ipa_ip_type iptype)
{
/* update the iface ip-type to be IPA_IP_v4, IPA_IP_v6 or both*/
if (iptype == IPA_IP_v4)
{
if ((ip_type == IPA_IP_v4) || (ip_type == IPA_IP_MAX))
{
IPACMDBG_H(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
return;
}
if (ip_type == IPA_IP_v6)
{
ip_type = IPA_IP_MAX;
}
else
{
ip_type = IPA_IP_v4;
}
IPACMDBG_H(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
}
else
{
if ((ip_type == IPA_IP_v6) || (ip_type == IPA_IP_MAX))
{
IPACMDBG_H(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
return;
}
if (ip_type == IPA_IP_v4)
{
ip_type = IPA_IP_MAX;
}
else
{
ip_type = IPA_IP_v6;
}
IPACMDBG_H(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
}
return;
}

View File

@@ -0,0 +1,565 @@
/*
Copyright (c) 2013-2016, 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_IfaceManager.cpp
@brief
This file implements the IPAM iface_manager functionality.
@Author
Skylar Chang
*/
#include <string.h>
#include <sys/ioctl.h>
#include <IPACM_IfaceManager.h>
#include <IPACM_EvtDispatcher.h>
#include <IPACM_Defs.h>
#include <IPACM_Wlan.h>
#include <IPACM_Lan.h>
#include <IPACM_Wan.h>
#include <IPACM_Iface.h>
#include <IPACM_Log.h>
iface_instances *IPACM_IfaceManager::head = NULL;
IPACM_IfaceManager::IPACM_IfaceManager()
{
IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, this); // register for IPA_CFG_CHANGE event
IPACM_EvtDispatcher::registr(IPA_LINK_UP_EVENT, this);
IPACM_EvtDispatcher::registr(IPA_WLAN_AP_LINK_UP_EVENT, this); // register for wlan AP-iface
IPACM_EvtDispatcher::registr(IPA_WLAN_STA_LINK_UP_EVENT, this); // register for wlan STA-iface
#ifndef FEATURE_IPA_ANDROID
/* only MDM targets support device on bridge mode */
IPACM_EvtDispatcher::registr(IPA_BRIDGE_LINK_UP_EVENT, this); // register for IPA_BRIDGE_LINK_UP_EVENT event
#endif /* not defined(FEATURE_IPA_ANDROID)*/
IPACM_EvtDispatcher::registr(IPA_USB_LINK_UP_EVENT, this); // register for USB-iface
IPACM_EvtDispatcher::registr(IPA_WAN_EMBMS_LINK_UP_EVENT, this); // register for wan eMBMS-iface
return;
}
void IPACM_IfaceManager::event_callback(ipa_cm_event_id event, void *param)
{
int ipa_interface_index;
ipacm_event_data_fid *evt_data = (ipacm_event_data_fid *)param;
ipacm_event_data_mac *StaData = (ipacm_event_data_mac *)param;
ipacm_event_data_all *data_all = (ipacm_event_data_all *)param;
ipacm_ifacemgr_data ifmgr_data = {0};
switch(event)
{
case IPA_CFG_CHANGE_EVENT:
IPACMDBG_H(" RESET IPACM_cfg \n");
IPACM_Iface::ipacmcfg->Init();
break;
case IPA_BRIDGE_LINK_UP_EVENT:
IPACMDBG_H(" Save the bridge0 mac info in IPACM_cfg \n");
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("IPA_BRIDGE_LINK_UP_EVENT: not supported iface id: %d\n", data_all->if_index);
break;
}
/* check if iface is bridge interface*/
if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
{
IPACM_Iface::ipacmcfg->ipa_bridge_enable = true;
memcpy(IPACM_Iface::ipacmcfg->bridge_mac,
data_all->mac_addr,
sizeof(IPACM_Iface::ipacmcfg->bridge_mac));
IPACMDBG_H("cached bridge0 MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
IPACM_Iface::ipacmcfg->bridge_mac[0], IPACM_Iface::ipacmcfg->bridge_mac[1], IPACM_Iface::ipacmcfg->bridge_mac[2],
IPACM_Iface::ipacmcfg->bridge_mac[3], IPACM_Iface::ipacmcfg->bridge_mac[4], IPACM_Iface::ipacmcfg->bridge_mac[5]);
}
break;
case IPA_LINK_UP_EVENT:
IPACMDBG_H("Recieved IPA_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("IPA_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
break;
}
/* LTE-backhaul */
if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == EMBMS_IF)
{
IPACMDBG("WAN-EMBMS (%s) link already up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
}
else if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
{
IPACMDBG_H("WAN-LTE (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
ifmgr_data.if_index = evt_data->if_index;
ifmgr_data.if_type = Q6_WAN;
create_iface_instance(&ifmgr_data);
}
break;
case IPA_USB_LINK_UP_EVENT:
IPACMDBG_H("Recieved IPA_USB_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("IPA_USB_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
break;
}
/* check if it's WAN_IF */
if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
{
/* usb-backhaul using sta_mode ECM_WAN*/
IPACMDBG_H("WAN-usb (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name, evt_data->if_index);
ifmgr_data.if_index = evt_data->if_index;
ifmgr_data.if_type = ECM_WAN;
create_iface_instance(&ifmgr_data);
}
else
{
ifmgr_data.if_index = evt_data->if_index;
ifmgr_data.if_type = Q6_WAN;
create_iface_instance(&ifmgr_data);
}
break;
case IPA_WLAN_AP_LINK_UP_EVENT:
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("IPA_WLAN_AP_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
break;
}
/* change iface category from unknown to WLAN_IF */
if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
{
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat = WLAN_IF;
IPACMDBG_H("WLAN AP (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
ifmgr_data.if_index = evt_data->if_index;
ifmgr_data.if_type = Q6_WAN;
create_iface_instance(&ifmgr_data);
}
else
{
IPACMDBG_H("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
}
break;
case IPA_WLAN_STA_LINK_UP_EVENT:
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(StaData->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("IPA_WLAN_STA_LINK_UP_EVENT: not supported iface id: %d\n", StaData->if_index);
break;
}
/* change iface category from unknown to WAN_IF */
if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
{
/* wlan-backhaul using sta_mode WLAN_WAN */
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat = WAN_IF;
IPACMDBG_H("WLAN STA (%s) link up, iface: %d: \n",
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name, StaData->if_index);
ifmgr_data.if_index = StaData->if_index;
ifmgr_data.if_type = WLAN_WAN;
memcpy(ifmgr_data.mac_addr, StaData->mac_addr, sizeof(ifmgr_data.mac_addr));
create_iface_instance(&ifmgr_data);
}
else
{
IPACMDBG_H("iface %s already up and act as %d mode: \n",
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
}
break;
/* Add new instance open for eMBMS iface and wan iface */
case IPA_WAN_EMBMS_LINK_UP_EVENT:
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("IPA_WAN_EMBMS_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
break;
}
/* change iface category from unknown to EMBMS_IF */
if ((IPACM_Iface::ipacmcfg->ipacm_odu_enable == true) && (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true))
{
IPACMDBG(" ODU-mode enable or not (%d) \n",IPACM_Iface::ipacmcfg->ipacm_odu_enable);
if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
{
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat=EMBMS_IF;
IPACMDBG("WAN eMBMS (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
ifmgr_data.if_index = StaData->if_index;
ifmgr_data.if_type = Q6_WAN;
create_iface_instance(&ifmgr_data);
}
else
{
IPACMDBG("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
}
}
break;
default:
break;
}
return;
}
int IPACM_IfaceManager::create_iface_instance(ipacm_ifacemgr_data *param)
{
int if_index = param->if_index;
ipacm_wan_iface_type is_sta_mode = param->if_type;
int ipa_interface_index;
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(if_index);
if(ipa_interface_index == INVALID_IFACE)
{
IPACMDBG_H("Unhandled interface received, fid: %d\n",if_index);
return IPACM_SUCCESS;
}
/* check if duplicate instance*/
if(SearchInstance(ipa_interface_index) == IPA_INSTANCE_NOT_FOUND)
{
/* IPA_INSTANCE_NOT_FOUND */
switch(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat)
{
case LAN_IF:
{
IPACMDBG_H("Creating Lan interface\n");
IPACM_Lan *lan = new IPACM_Lan(ipa_interface_index);
IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, lan);
//IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, lan);
//IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, lan);
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, lan);
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, lan);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, lan);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, lan);
#ifdef FEATURE_IPA_ANDROID
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_TETHER, lan);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6_TETHER, lan);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_TETHER, lan);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6_TETHER, lan);
#else
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, lan);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, lan);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, lan);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, lan);
#endif
IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, lan); // register for IPA_CFG_CHANGE event
IPACM_EvtDispatcher::registr(IPA_PRIVATE_SUBNET_CHANGE_EVENT, lan); // register for IPA_PRIVATE_SUBNET_CHANGE_EVENT event
#ifdef FEATURE_IPA_ANDROID
IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, lan);
#endif
IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, lan);
IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
/* IPA_LAN_DELETE_SELF should be always last */
IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, lan);
IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", lan->dev_name, lan->ipa_if_num);
registr(ipa_interface_index, lan);
/* solve the new_addr comes earlier issue */
IPACM_Iface::iface_addr_query(if_index);
}
break;
case ETH_IF:
{
IPACMDBG_H("Creating ETH interface in router mode\n");
IPACM_Lan *ETH = new IPACM_Lan(ipa_interface_index);
IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, ETH);
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, ETH);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, ETH);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, ETH);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, ETH);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, ETH);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, ETH);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, ETH);
IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, ETH);
IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, ETH);
/* IPA_LAN_DELETE_SELF should be always last */
IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, ETH);
IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", ETH->dev_name, ETH->ipa_if_num);
registr(ipa_interface_index, ETH);
/* solve the new_addr comes earlier issue */
IPACM_Iface::iface_addr_query(if_index);
}
break;
case ODU_IF:
{
if(IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == true)
{
IPACMDBG_H("Creating ODU interface in router mode\n");
IPACM_Lan *odu = new IPACM_Lan(ipa_interface_index);
IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, odu);
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, odu);
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, odu);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, odu);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, odu);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, odu);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, odu);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, odu);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, odu);
IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, odu);
IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, odu);
/* IPA_LAN_DELETE_SELF should be always last */
IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
registr(ipa_interface_index, odu);
/* solve the new_addr comes earlier issue */
IPACM_Iface::iface_addr_query(if_index);
}
else
{
IPACMDBG_H("Creating ODU interface in bridge mode\n");
IPACM_Lan *odu = new IPACM_Lan(ipa_interface_index);
IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, odu);
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, odu);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, odu);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, odu);
IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, odu);
/* IPA_LAN_DELETE_SELF should be always last */
IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
registr(ipa_interface_index, odu);
/* solve the new_addr comes earlier issue */
IPACM_Iface::iface_addr_query(if_index);
}
}
break;
case WLAN_IF:
{
IPACMDBG_H("Creating WLan interface\n");
IPACM_Wlan *wl = new IPACM_Wlan(ipa_interface_index);
IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, wl);
IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, wl);
IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT, wl);
IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT_EX, wl);
IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_DEL_EVENT, wl);
IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_POWER_SAVE_EVENT, wl);
IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_RECOVER_EVENT, wl);
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, wl);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, wl);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, wl);
#ifdef FEATURE_IPA_ANDROID
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_TETHER, wl);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6_TETHER, wl);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_TETHER, wl);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6_TETHER, wl);
#else
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, wl);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, wl);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, wl);
IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, wl);
#endif
IPACM_EvtDispatcher::registr(IPA_PRIVATE_SUBNET_CHANGE_EVENT, wl); // register for IPA_PRIVATE_SUBNET_CHANGE_EVENT event
#ifdef FEATURE_ETH_BRIDGE_LE
IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, wl);
#endif
IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, wl);
IPACM_EvtDispatcher::registr(IPA_WLAN_LINK_DOWN_EVENT, wl);
#ifndef FEATURE_IPA_ANDROID
IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, wl);
IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, wl);
#else
IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, wl);
#endif
/* IPA_LAN_DELETE_SELF should be always last */
IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, wl);
IPACMDBG_H("ipa_WLAN (%s):ipa_index (%d) instance open/registr ok\n", wl->dev_name, wl->ipa_if_num);
registr(ipa_interface_index, wl);
/* solve the new_addr comes earlier issue */
IPACM_Iface::iface_addr_query(if_index);
}
break;
case WAN_IF:
{
if((IPACM_Iface::ipacmcfg->ipacm_odu_enable == false) || (IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == true))
{
IPACMDBG_H("Creating Wan interface\n");
IPACM_Wan *w;
if(is_sta_mode == WLAN_WAN)
{
w = new IPACM_Wan(ipa_interface_index, is_sta_mode, param->mac_addr);
}
else
{
w = new IPACM_Wan(ipa_interface_index, is_sta_mode, NULL);
}
IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, w);
#ifdef FEATURE_IPA_ANDROID
IPACM_EvtDispatcher::registr(IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, w);
IPACM_EvtDispatcher::registr(IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, w);
if(is_sta_mode == Q6_WAN)
{
IPACM_EvtDispatcher::registr(IPA_NETWORK_STATS_UPDATE_EVENT, w);
};
#else/* defined(FEATURE_IPA_ANDROID) */
IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, w);
IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, w);
#endif /* not defined(FEATURE_IPA_ANDROID)*/
IPACM_EvtDispatcher::registr(IPA_FIREWALL_CHANGE_EVENT, w);
IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, w);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, w);
IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, w);
IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, w); // register for IPA_CFG_CHANGE event
IPACM_EvtDispatcher::registr(IPA_WAN_XLAT_CONNECT_EVENT, w);
if(is_sta_mode == WLAN_WAN)
{
IPACM_EvtDispatcher::registr(IPA_WLAN_LINK_DOWN_EVENT, w); // for STA mode
#ifndef FEATURE_IPA_ANDROID
IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, w);
IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, w);
#endif
}
else
{
IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, w);
}
IPACMDBG_H("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", w->dev_name, w->ipa_if_num);
registr(ipa_interface_index, w);
/* solve the new_addr comes earlier issue */
IPACM_Iface::iface_addr_query(if_index);
}
}
break;
/* WAN-eMBMS instance */
case EMBMS_IF:
{
IPACMDBG("Creating Wan-eMBSM interface\n");
IPACM_Wan *embms = new IPACM_Wan(ipa_interface_index, is_sta_mode, NULL);
IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, embms);
IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", embms->dev_name, embms->ipa_if_num);
registr(ipa_interface_index, embms);
}
break;
default:
IPACMDBG_H("Unhandled interface category received iface name: %s, category: %d\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
return IPACM_SUCCESS;
}
}
return IPACM_SUCCESS;
}
int IPACM_IfaceManager::registr(int ipa_if_index, IPACM_Listener *obj)
{
iface_instances *tmp = head,*nw;
nw = (iface_instances *)malloc(sizeof(iface_instances));
if(nw != NULL)
{
nw->ipa_if_index = ipa_if_index;
nw->obj = obj;
nw->next = NULL;
}
else
{
return IPACM_FAILURE;
}
if(head == NULL)
{
head = nw;
}
else
{
while(tmp->next)
{
tmp = tmp->next;
}
tmp->next = nw;
}
return IPACM_SUCCESS;
}
int IPACM_IfaceManager::deregistr(IPACM_Listener *param)
{
iface_instances *tmp = head,*tmp1,*prev = head;
while(tmp != NULL)
{
if(tmp->obj == param)
{
tmp1 = tmp;
if(tmp == head)
{
head = head->next;
}
else if(tmp->next == NULL)
{
prev->next = NULL;
}
else
{
prev->next = tmp->next;
}
tmp = tmp->next;
free(tmp1);
}
else
{
prev = tmp;
tmp = tmp->next;
}
}
return IPACM_SUCCESS;
}
int IPACM_IfaceManager::SearchInstance(int ipa_if_index)
{
iface_instances *tmp = head;
while(tmp != NULL)
{
if(ipa_if_index == tmp->ipa_if_index)
{
IPACMDBG_H("Find existed iface-instance name: %s\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
return IPA_INSTANCE_FOUND;
}
tmp = tmp->next;
}
IPACMDBG_H("No existed iface-instance name: %s,\n",
IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
return IPA_INSTANCE_NOT_FOUND;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
/*
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_log.cpp
@brief
This file implements the IPAM log functionality.
@Author
Skylar Chang
*/
#include "IPACM_Log.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <asm/types.h>
#include <linux/if.h>
#include <sys/un.h>
#include <errno.h>
#include <IPACM_Defs.h>
void logmessage(int log_level)
{
return;
}
/* start IPACMDIAG socket*/
int create_socket(unsigned int *sockfd)
{
if ((*sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) == IPACM_FAILURE)
{
perror("Error creating ipacm_log socket\n");
return IPACM_FAILURE;
}
if(fcntl(*sockfd, F_SETFD, FD_CLOEXEC) < 0)
{
perror("Couldn't set ipacm_log Close on Exec\n");
}
return IPACM_SUCCESS;
}
void ipacm_log_send( void * user_data)
{
ipacm_log_buffer_t ipacm_log_buffer;
int numBytes=0, len;
struct sockaddr_un ipacmlog_socket;
static unsigned int ipacm_log_sockfd = 0;
if(ipacm_log_sockfd == 0)
{
/* start ipacm_log socket */
if(create_socket(&ipacm_log_sockfd) < 0)
{
printf("unable to create ipacm_log socket\n");
return;
}
printf("create ipacm_log socket successfully\n");
}
ipacmlog_socket.sun_family = AF_UNIX;
strcpy(ipacmlog_socket.sun_path, IPACMLOG_FILE);
len = strlen(ipacmlog_socket.sun_path) + sizeof(ipacmlog_socket.sun_family);
memcpy(ipacm_log_buffer.user_data, user_data, MAX_BUF_LEN);
//printf("send : %s\n", ipacm_log_buffer.user_data);
if ((numBytes = sendto(ipacm_log_sockfd, (void *)&ipacm_log_buffer, sizeof(ipacm_log_buffer.user_data), 0,
(struct sockaddr *)&ipacmlog_socket, len)) == -1)
{
printf("Send Failed(%d) %s \n",errno,strerror(errno));
return;
}
return;
}

View File

@@ -0,0 +1,939 @@
/*
Copyright (c) 2013-2016, 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_Main.cpp
@brief
This file implements the IPAM functionality.
@Author
Skylar Chang
*/
/******************************************************************************
IPCM_MAIN.C
******************************************************************************/
#include <sys/socket.h>
#include <signal.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <fcntl.h>
#include <sys/inotify.h>
#include <stdlib.h>
#include <signal.h>
#include "linux/ipa_qmi_service_v01.h"
#include "IPACM_CmdQueue.h"
#include "IPACM_EvtDispatcher.h"
#include "IPACM_Defs.h"
#include "IPACM_Neighbor.h"
#include "IPACM_IfaceManager.h"
#include "IPACM_Log.h"
#include "IPACM_ConntrackListener.h"
#include "IPACM_ConntrackClient.h"
#include "IPACM_Netlink.h"
/* not defined(FEATURE_IPA_ANDROID)*/
#ifndef FEATURE_IPA_ANDROID
#include "IPACM_LanToLan.h"
#endif
#define IPA_DRIVER "/dev/ipa"
#define IPACM_FIREWALL_FILE_NAME "mobileap_firewall.xml"
#define IPACM_CFG_FILE_NAME "IPACM_cfg.xml"
#ifdef FEATURE_IPA_ANDROID
#define IPACM_PID_FILE "/data/misc/ipa/ipacm.pid"
#define IPACM_DIR_NAME "/data"
#else/* defined(FEATURE_IPA_ANDROID) */
#define IPACM_PID_FILE "/etc/ipacm.pid"
#define IPACM_DIR_NAME "/etc"
#endif /* defined(NOT FEATURE_IPA_ANDROID)*/
#define IPACM_NAME "ipacm"
#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
#define INOTIFY_BUF_LEN (INOTIFY_EVENT_SIZE + 2*sizeof(IPACM_FIREWALL_FILE_NAME))
#define IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS 3
#define IPA_DRIVER_WLAN_EVENT_SIZE (sizeof(struct ipa_wlan_msg_ex)+ IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS*sizeof(ipa_wlan_hdr_attrib_val))
#define IPA_DRIVER_PIPE_STATS_EVENT_SIZE (sizeof(struct ipa_get_data_stats_resp_msg_v01))
#define IPA_DRIVER_WLAN_META_MSG (sizeof(struct ipa_msg_meta))
#define IPA_DRIVER_WLAN_BUF_LEN (IPA_DRIVER_PIPE_STATS_EVENT_SIZE + IPA_DRIVER_WLAN_META_MSG)
uint32_t ipacm_event_stats[IPACM_EVENT_MAX];
bool ipacm_logging = true;
void ipa_is_ipacm_running(void);
int ipa_get_if_index(char *if_name, int *if_index);
/* start netlink socket monitor*/
void* netlink_start(void *param)
{
ipa_nl_sk_fd_set_info_t sk_fdset;
int ret_val = 0;
memset(&sk_fdset, 0, sizeof(ipa_nl_sk_fd_set_info_t));
IPACMDBG_H("netlink starter memset sk_fdset succeeds\n");
ret_val = ipa_nl_listener_init(NETLINK_ROUTE, (RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK |
RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH |
RTNLGRP_IPV6_PREFIX),
&sk_fdset, ipa_nl_recv_msg);
if (ret_val != IPACM_SUCCESS)
{
IPACMERR("Failed to initialize IPA netlink event listener\n");
return NULL;
}
return NULL;
}
/* start firewall-rule monitor*/
void* firewall_monitor(void *param)
{
int length;
int wd;
char buffer[INOTIFY_BUF_LEN];
int inotify_fd;
ipacm_cmd_q_data evt_data;
uint32_t mask = IN_MODIFY | IN_MOVE;
inotify_fd = inotify_init();
if (inotify_fd < 0)
{
PERROR("inotify_init");
}
IPACMDBG_H("Waiting for nofications in dir %s with mask: 0x%x\n", IPACM_DIR_NAME, mask);
wd = inotify_add_watch(inotify_fd,
IPACM_DIR_NAME,
mask);
while (1)
{
length = read(inotify_fd, buffer, INOTIFY_BUF_LEN);
if (length < 0)
{
IPACMERR("inotify read() error return length: %d and mask: 0x%x\n", length, mask);
continue;
}
struct inotify_event* event;
event = (struct inotify_event*)malloc(length);
if(event == NULL)
{
IPACMERR("Failed to allocate memory.\n");
return NULL;
}
memset(event, 0, length);
memcpy(event, buffer, length);
if (event->len > 0)
{
if ( (event->mask & IN_MODIFY) || (event->mask & IN_MOVE))
{
if (event->mask & IN_ISDIR)
{
IPACMDBG_H("The directory %s was 0x%x\n", event->name, event->mask);
}
else if (!strncmp(event->name, IPACM_FIREWALL_FILE_NAME, event->len)) // firewall_rule change
{
IPACMDBG_H("File \"%s\" was 0x%x\n", event->name, event->mask);
IPACMDBG_H("The interested file %s .\n", IPACM_FIREWALL_FILE_NAME);
evt_data.event = IPA_FIREWALL_CHANGE_EVENT;
evt_data.evt_data = NULL;
/* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
else if (!strncmp(event->name, IPACM_CFG_FILE_NAME, event->len)) // IPACM_configuration change
{
IPACMDBG_H("File \"%s\" was 0x%x\n", event->name, event->mask);
IPACMDBG_H("The interested file %s .\n", IPACM_CFG_FILE_NAME);
evt_data.event = IPA_CFG_CHANGE_EVENT;
evt_data.evt_data = NULL;
/* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
IPACM_EvtDispatcher::PostEvt(&evt_data);
}
}
IPACMDBG_H("Received monitoring event %s.\n", event->name);
}
free(event);
}
(void)inotify_rm_watch(inotify_fd, wd);
(void)close(inotify_fd);
return NULL;
}
/* start IPACM wan-driver notifier */
void* ipa_driver_msg_notifier(void *param)
{
int length, fd, cnt;
char buffer[IPA_DRIVER_WLAN_BUF_LEN];
struct ipa_msg_meta event_hdr;
struct ipa_ecm_msg event_ecm;
struct ipa_wan_msg event_wan;
struct ipa_wlan_msg_ex event_ex_o;
struct ipa_wlan_msg *event_wlan=NULL;
struct ipa_wlan_msg_ex *event_ex= NULL;
struct ipa_get_data_stats_resp_msg_v01 event_data_stats;
struct ipa_get_apn_data_stats_resp_msg_v01 event_network_stats;
ipacm_cmd_q_data evt_data;
ipacm_event_data_mac *data = NULL;
ipacm_event_data_fid *data_fid = NULL;
ipacm_event_data_iptype *data_iptype = NULL;
ipacm_event_data_wlan_ex *data_ex;
ipa_get_data_stats_resp_msg_v01 *data_tethering_stats = NULL;
ipa_get_apn_data_stats_resp_msg_v01 *data_network_stats = NULL;
ipacm_cmd_q_data new_neigh_evt;
ipacm_event_data_all* new_neigh_data;
fd = open(IPA_DRIVER, O_RDWR);
if (fd < 0)
{
IPACMERR("Failed opening %s.\n", IPA_DRIVER);
return NULL;
}
while (1)
{
IPACMDBG_H("Waiting for nofications from IPA driver \n");
memset(buffer, 0, sizeof(buffer));
memset(&evt_data, 0, sizeof(evt_data));
memset(&new_neigh_evt, 0, sizeof(ipacm_cmd_q_data));
new_neigh_data = NULL;
data = NULL;
data_fid = NULL;
data_tethering_stats = NULL;
data_network_stats = NULL;
length = read(fd, buffer, IPA_DRIVER_WLAN_BUF_LEN);
if (length < 0)
{
PERROR("didn't read IPA_driver correctly");
continue;
}
memcpy(&event_hdr, buffer,sizeof(struct ipa_msg_meta));
IPACMDBG_H("Message type: %d\n", event_hdr.msg_type);
IPACMDBG_H("Event header length received: %d\n",event_hdr.msg_len);
/* Insert WLAN_DRIVER_EVENT to command queue */
switch (event_hdr.msg_type)
{
case SW_ROUTING_ENABLE:
IPACMDBG_H("Received SW_ROUTING_ENABLE\n");
evt_data.event = IPA_SW_ROUTING_ENABLE;
IPACMDBG_H("Not supported anymore\n");
continue;
case SW_ROUTING_DISABLE:
IPACMDBG_H("Received SW_ROUTING_DISABLE\n");
evt_data.event = IPA_SW_ROUTING_DISABLE;
IPACMDBG_H("Not supported anymore\n");
continue;
case WLAN_AP_CONNECT:
event_wlan = (struct ipa_wlan_msg *) (buffer + sizeof(struct ipa_msg_meta));
IPACMDBG_H("Received WLAN_AP_CONNECT name: %s\n",event_wlan->name);
IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for event_wlan data_fid\n");
return NULL;
}
ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
evt_data.event = IPA_WLAN_AP_LINK_UP_EVENT;
evt_data.evt_data = data_fid;
break;
case WLAN_AP_DISCONNECT:
event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
IPACMDBG_H("Received WLAN_AP_DISCONNECT name: %s\n",event_wlan->name);
IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for event_wlan data_fid\n");
return NULL;
}
ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
evt_data.event = IPA_WLAN_LINK_DOWN_EVENT;
evt_data.evt_data = data_fid;
break;
case WLAN_STA_CONNECT:
event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
IPACMDBG_H("Received WLAN_STA_CONNECT name: %s\n",event_wlan->name);
IPACMDBG_H("STA Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
if(data == NULL)
{
IPACMERR("unable to allocate memory for event_wlan data_fid\n");
return NULL;
}
memcpy(data->mac_addr,
event_wlan->mac_addr,
sizeof(event_wlan->mac_addr));
ipa_get_if_index(event_wlan->name, &(data->if_index));
evt_data.event = IPA_WLAN_STA_LINK_UP_EVENT;
evt_data.evt_data = data;
break;
case WLAN_STA_DISCONNECT:
event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
IPACMDBG_H("Received WLAN_STA_DISCONNECT name: %s\n",event_wlan->name);
IPACMDBG_H("STA Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for event_wlan data_fid\n");
return NULL;
}
ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
evt_data.event = IPA_WLAN_LINK_DOWN_EVENT;
evt_data.evt_data = data_fid;
break;
case WLAN_CLIENT_CONNECT:
event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
IPACMDBG_H("Received WLAN_CLIENT_CONNECT\n");
IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
if (data == NULL)
{
IPACMERR("unable to allocate memory for event_wlan data\n");
return NULL;
}
memcpy(data->mac_addr,
event_wlan->mac_addr,
sizeof(event_wlan->mac_addr));
ipa_get_if_index(event_wlan->name, &(data->if_index));
evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT;
evt_data.evt_data = data;
break;
case WLAN_CLIENT_CONNECT_EX:
IPACMDBG_H("Received WLAN_CLIENT_CONNECT_EX\n");
memcpy(&event_ex_o, buffer + sizeof(struct ipa_msg_meta),sizeof(struct ipa_wlan_msg_ex));
if(event_ex_o.num_of_attribs > IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS)
{
IPACMERR("buffer size overflow\n");
return NULL;
}
length = sizeof(ipa_wlan_msg_ex)+ event_ex_o.num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val);
IPACMDBG_H("num_of_attribs %d, length %d\n", event_ex_o.num_of_attribs, length);
event_ex = (ipa_wlan_msg_ex *)malloc(length);
if(event_ex == NULL )
{
IPACMERR("Unable to allocate memory\n");
return NULL;
}
memcpy(event_ex, buffer + sizeof(struct ipa_msg_meta), length);
data_ex = (ipacm_event_data_wlan_ex *)malloc(sizeof(ipacm_event_data_wlan_ex) + event_ex_o.num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val));
if (data_ex == NULL)
{
IPACMERR("unable to allocate memory for event data\n");
return NULL;
}
data_ex->num_of_attribs = event_ex->num_of_attribs;
memcpy(data_ex->attribs,
event_ex->attribs,
event_ex->num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val));
ipa_get_if_index(event_ex->name, &(data_ex->if_index));
evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT_EX;
evt_data.evt_data = data_ex;
/* Construct new_neighbor msg with netdev device internally */
new_neigh_data = (ipacm_event_data_all*)malloc(sizeof(ipacm_event_data_all));
if(new_neigh_data == NULL)
{
IPACMERR("Failed to allocate memory.\n");
return NULL;
}
memset(new_neigh_data, 0, sizeof(ipacm_event_data_all));
new_neigh_data->iptype = IPA_IP_v6;
for(cnt = 0; cnt < event_ex->num_of_attribs; cnt++)
{
if(event_ex->attribs[cnt].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
{
memcpy(new_neigh_data->mac_addr, event_ex->attribs[cnt].u.mac_addr, sizeof(new_neigh_data->mac_addr));
IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_ex->attribs[cnt].u.mac_addr[0], event_ex->attribs[cnt].u.mac_addr[1], event_ex->attribs[cnt].u.mac_addr[2],
event_ex->attribs[cnt].u.mac_addr[3], event_ex->attribs[cnt].u.mac_addr[4], event_ex->attribs[cnt].u.mac_addr[5]);
}
else if(event_ex->attribs[cnt].attrib_type == WLAN_HDR_ATTRIB_STA_ID)
{
IPACMDBG_H("Wlan client id %d\n",event_ex->attribs[cnt].u.sta_id);
}
else
{
IPACMDBG_H("Wlan message has unexpected type!\n");
}
}
new_neigh_data->if_index = data_ex->if_index;
new_neigh_evt.evt_data = (void*)new_neigh_data;
new_neigh_evt.event = IPA_NEW_NEIGH_EVENT;
free(event_ex);
break;
case WLAN_CLIENT_DISCONNECT:
IPACMDBG_H("Received WLAN_CLIENT_DISCONNECT\n");
event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
if (data == NULL)
{
IPACMERR("unable to allocate memory for event_wlan data\n");
return NULL;
}
memcpy(data->mac_addr,
event_wlan->mac_addr,
sizeof(event_wlan->mac_addr));
ipa_get_if_index(event_wlan->name, &(data->if_index));
evt_data.event = IPA_WLAN_CLIENT_DEL_EVENT;
evt_data.evt_data = data;
break;
case WLAN_CLIENT_POWER_SAVE_MODE:
IPACMDBG_H("Received WLAN_CLIENT_POWER_SAVE_MODE\n");
event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
if (data == NULL)
{
IPACMERR("unable to allocate memory for event_wlan data\n");
return NULL;
}
memcpy(data->mac_addr,
event_wlan->mac_addr,
sizeof(event_wlan->mac_addr));
ipa_get_if_index(event_wlan->name, &(data->if_index));
evt_data.event = IPA_WLAN_CLIENT_POWER_SAVE_EVENT;
evt_data.evt_data = data;
break;
case WLAN_CLIENT_NORMAL_MODE:
IPACMDBG_H("Received WLAN_CLIENT_NORMAL_MODE\n");
event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
if (data == NULL)
{
IPACMERR("unable to allocate memory for event_wlan data\n");
return NULL;
}
memcpy(data->mac_addr,
event_wlan->mac_addr,
sizeof(event_wlan->mac_addr));
ipa_get_if_index(event_wlan->name, &(data->if_index));
evt_data.evt_data = data;
evt_data.event = IPA_WLAN_CLIENT_RECOVER_EVENT;
break;
case ECM_CONNECT:
memcpy(&event_ecm, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_ecm_msg));
IPACMDBG_H("Received ECM_CONNECT name: %s\n",event_ecm.name);
data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for event_ecm data_fid\n");
return NULL;
}
data_fid->if_index = event_ecm.ifindex;
evt_data.event = IPA_USB_LINK_UP_EVENT;
evt_data.evt_data = data_fid;
break;
case ECM_DISCONNECT:
memcpy(&event_ecm, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_ecm_msg));
IPACMDBG_H("Received ECM_DISCONNECT name: %s\n",event_ecm.name);
data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for event_ecm data_fid\n");
return NULL;
}
data_fid->if_index = event_ecm.ifindex;
evt_data.event = IPA_LINK_DOWN_EVENT;
evt_data.evt_data = data_fid;
break;
/* Add for 8994 Android case */
case WAN_UPSTREAM_ROUTE_ADD:
memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD name: %s, tethered name: %s\n", event_wan.upstream_ifname, event_wan.tethered_ifname);
data_iptype = (ipacm_event_data_iptype *)malloc(sizeof(ipacm_event_data_iptype));
if(data_iptype == NULL)
{
IPACMERR("unable to allocate memory for event_ecm data_iptype\n");
return NULL;
}
ipa_get_if_index(event_wan.upstream_ifname, &(data_iptype->if_index));
ipa_get_if_index(event_wan.tethered_ifname, &(data_iptype->if_index_tether));
data_iptype->iptype = event_wan.ip;
#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
data_iptype->ipv4_addr_gw = event_wan.ipv4_addr_gw;
data_iptype->ipv6_addr_gw[0] = event_wan.ipv6_addr_gw[0];
data_iptype->ipv6_addr_gw[1] = event_wan.ipv6_addr_gw[1];
data_iptype->ipv6_addr_gw[2] = event_wan.ipv6_addr_gw[2];
data_iptype->ipv6_addr_gw[3] = event_wan.ipv6_addr_gw[3];
IPACMDBG_H("default gw ipv4 (%x)\n", data_iptype->ipv4_addr_gw);
IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
data_iptype->ipv6_addr_gw[0], data_iptype->ipv6_addr_gw[1], data_iptype->ipv6_addr_gw[2], data_iptype->ipv6_addr_gw[3]);
#endif
IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", data_iptype->if_index,
data_iptype->if_index_tether, data_iptype->iptype);
evt_data.event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT;
evt_data.evt_data = data_iptype;
break;
case WAN_UPSTREAM_ROUTE_DEL:
memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL name: %s, tethered name: %s\n", event_wan.upstream_ifname, event_wan.tethered_ifname);
data_iptype = (ipacm_event_data_iptype *)malloc(sizeof(ipacm_event_data_iptype));
if(data_iptype == NULL)
{
IPACMERR("unable to allocate memory for event_ecm data_iptype\n");
return NULL;
}
ipa_get_if_index(event_wan.upstream_ifname, &(data_iptype->if_index));
ipa_get_if_index(event_wan.tethered_ifname, &(data_iptype->if_index_tether));
data_iptype->iptype = event_wan.ip;
IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL: fid(%d) ip-type(%d)\n", data_iptype->if_index, data_iptype->iptype);
evt_data.event = IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT;
evt_data.evt_data = data_iptype;
break;
/* End of adding for 8994 Android case */
/* Add for embms case */
case WAN_EMBMS_CONNECT:
memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
IPACMDBG("Received WAN_EMBMS_CONNECT name: %s\n",event_wan.upstream_ifname);
data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for event data_fid\n");
return NULL;
}
ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
evt_data.event = IPA_WAN_EMBMS_LINK_UP_EVENT;
evt_data.evt_data = data_fid;
break;
case WLAN_SWITCH_TO_SCC:
IPACMDBG_H("Received WLAN_SWITCH_TO_SCC\n");
case WLAN_WDI_ENABLE:
IPACMDBG_H("Received WLAN_WDI_ENABLE\n");
if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
{
IPACM_Iface::ipacmcfg->isMCC_Mode = false;
evt_data.event = IPA_WLAN_SWITCH_TO_SCC;
break;
}
continue;
case WLAN_SWITCH_TO_MCC:
IPACMDBG_H("Received WLAN_SWITCH_TO_MCC\n");
case WLAN_WDI_DISABLE:
IPACMDBG_H("Received WLAN_WDI_DISABLE\n");
if (IPACM_Iface::ipacmcfg->isMCC_Mode == false)
{
IPACM_Iface::ipacmcfg->isMCC_Mode = true;
evt_data.event = IPA_WLAN_SWITCH_TO_MCC;
break;
}
continue;
case WAN_XLAT_CONNECT:
memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta),
sizeof(struct ipa_wan_msg));
IPACMDBG_H("Received WAN_XLAT_CONNECT name: %s\n",
event_wan.upstream_ifname);
/* post IPA_LINK_UP_EVENT event
* may be WAN interface is not up
*/
data_fid = (ipacm_event_data_fid *)calloc(1, sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for xlat event\n");
return NULL;
}
ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
evt_data.event = IPA_LINK_UP_EVENT;
evt_data.evt_data = data_fid;
IPACMDBG_H("Posting IPA_LINK_UP_EVENT event:%d\n", evt_data.event);
IPACM_EvtDispatcher::PostEvt(&evt_data);
/* post IPA_WAN_XLAT_CONNECT_EVENT event */
memset(&evt_data, 0, sizeof(evt_data));
data_fid = (ipacm_event_data_fid *)calloc(1, sizeof(ipacm_event_data_fid));
if(data_fid == NULL)
{
IPACMERR("unable to allocate memory for xlat event\n");
return NULL;
}
ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
evt_data.event = IPA_WAN_XLAT_CONNECT_EVENT;
evt_data.evt_data = data_fid;
IPACMDBG_H("Posting IPA_WAN_XLAT_CONNECT_EVENT event:%d\n", evt_data.event);
break;
case IPA_TETHERING_STATS_UPDATE_STATS:
memcpy(&event_data_stats, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_get_data_stats_resp_msg_v01));
data_tethering_stats = (ipa_get_data_stats_resp_msg_v01 *)malloc(sizeof(struct ipa_get_data_stats_resp_msg_v01));
if(data_tethering_stats == NULL)
{
IPACMERR("unable to allocate memory for event data_tethering_stats\n");
return NULL;
}
memcpy(data_tethering_stats,
&event_data_stats,
sizeof(struct ipa_get_data_stats_resp_msg_v01));
IPACMDBG("Received IPA_TETHERING_STATS_UPDATE_STATS ipa_stats_type: %d\n",data_tethering_stats->ipa_stats_type);
IPACMDBG("Received %d UL, %d DL pipe stats\n",data_tethering_stats->ul_src_pipe_stats_list_len, data_tethering_stats->dl_dst_pipe_stats_list_len);
evt_data.event = IPA_TETHERING_STATS_UPDATE_EVENT;
evt_data.evt_data = data_tethering_stats;
break;
case IPA_TETHERING_STATS_UPDATE_NETWORK_STATS:
memcpy(&event_network_stats, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
data_network_stats = (ipa_get_apn_data_stats_resp_msg_v01 *)malloc(sizeof(ipa_get_apn_data_stats_resp_msg_v01));
if(data_network_stats == NULL)
{
IPACMERR("unable to allocate memory for event data_network_stats\n");
return NULL;
}
memcpy(data_network_stats,
&event_network_stats,
sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
IPACMDBG("Received %d apn network stats \n", data_network_stats->apn_data_stats_list_len);
evt_data.event = IPA_NETWORK_STATS_UPDATE_EVENT;
evt_data.evt_data = data_network_stats;
break;
default:
IPACMDBG_H("Unhandled message type: %d\n", event_hdr.msg_type);
continue;
}
/* finish command queue */
IPACMDBG_H("Posting event:%d\n", evt_data.event);
IPACM_EvtDispatcher::PostEvt(&evt_data);
/* push new_neighbor with netdev device internally */
if(new_neigh_data != NULL)
{
IPACMDBG_H("Internally post event IPA_NEW_NEIGH_EVENT\n");
IPACM_EvtDispatcher::PostEvt(&new_neigh_evt);
}
}
(void)close(fd);
return NULL;
}
void IPACM_Sig_Handler(int sig)
{
int cnt;
ipacm_cmd_q_data evt_data;
printf("Received Signal: %d\n", sig);
memset(&evt_data, 0, sizeof(evt_data));
switch(sig)
{
case SIGUSR1:
IPACMDBG_H("Received SW_ROUTING_ENABLE request \n");
evt_data.event = IPA_SW_ROUTING_ENABLE;
IPACM_Iface::ipacmcfg->ipa_sw_rt_enable = true;
break;
case SIGUSR2:
IPACMDBG_H("Received SW_ROUTING_DISABLE request \n");
evt_data.event = IPA_SW_ROUTING_DISABLE;
IPACM_Iface::ipacmcfg->ipa_sw_rt_enable = false;
break;
}
/* finish command queue */
IPACMDBG_H("Posting event:%d\n", evt_data.event);
IPACM_EvtDispatcher::PostEvt(&evt_data);
return;
}
void RegisterForSignals(void)
{
signal(SIGUSR1, IPACM_Sig_Handler);
signal(SIGUSR2, IPACM_Sig_Handler);
}
int main(int argc, char **argv)
{
int ret;
pthread_t netlink_thread = 0, monitor_thread = 0, ipa_driver_thread = 0;
pthread_t cmd_queue_thread = 0;
/* check if ipacm is already running or not */
ipa_is_ipacm_running();
IPACMDBG_H("In main()\n");
IPACM_Neighbor *neigh = new IPACM_Neighbor();
IPACM_IfaceManager *ifacemgr = new IPACM_IfaceManager();
#ifdef FEATURE_ETH_BRIDGE_LE
IPACM_LanToLan* lan2lan = new IPACM_LanToLan();
#endif
IPACM_ConntrackClient *cc = IPACM_ConntrackClient::GetInstance();
CtList = new IPACM_ConntrackListener();
IPACMDBG_H("Staring IPA main\n");
IPACMDBG_H("ipa_cmdq_successful\n");
RegisterForSignals();
if (IPACM_SUCCESS == cmd_queue_thread)
{
ret = pthread_create(&cmd_queue_thread, NULL, MessageQueue::Process, NULL);
if (IPACM_SUCCESS != ret)
{
IPACMERR("unable to command queue thread\n");
return ret;
}
IPACMDBG_H("created command queue thread\n");
if(pthread_setname_np(cmd_queue_thread, "cmd queue process") != 0)
{
IPACMERR("unable to set thread name\n");
}
}
if (IPACM_SUCCESS == netlink_thread)
{
ret = pthread_create(&netlink_thread, NULL, netlink_start, NULL);
if (IPACM_SUCCESS != ret)
{
IPACMERR("unable to create netlink thread\n");
return ret;
}
IPACMDBG_H("created netlink thread\n");
if(pthread_setname_np(netlink_thread, "netlink socket") != 0)
{
IPACMERR("unable to set thread name\n");
}
}
/* Enable Firewall support only on MDM targets */
#ifndef FEATURE_IPA_ANDROID
if (IPACM_SUCCESS == monitor_thread)
{
ret = pthread_create(&monitor_thread, NULL, firewall_monitor, NULL);
if (IPACM_SUCCESS != ret)
{
IPACMERR("unable to create monitor thread\n");
return ret;
}
IPACMDBG_H("created firewall monitor thread\n");
if(pthread_setname_np(monitor_thread, "firewall cfg process") != 0)
{
IPACMERR("unable to set thread name\n");
}
}
#endif
if (IPACM_SUCCESS == ipa_driver_thread)
{
ret = pthread_create(&ipa_driver_thread, NULL, ipa_driver_msg_notifier, NULL);
if (IPACM_SUCCESS != ret)
{
IPACMERR("unable to create ipa_driver_wlan thread\n");
return ret;
}
IPACMDBG_H("created ipa_driver_wlan thread\n");
if(pthread_setname_np(ipa_driver_thread, "ipa driver ntfy") != 0)
{
IPACMERR("unable to set thread name\n");
}
}
pthread_join(cmd_queue_thread, NULL);
pthread_join(netlink_thread, NULL);
pthread_join(monitor_thread, NULL);
pthread_join(ipa_driver_thread, NULL);
return IPACM_SUCCESS;
}
/*===========================================================================
FUNCTION ipa_is_ipacm_running
===========================================================================*/
/*!
@brief
Determine whether there's already an IPACM process running, if so, terminate
the current one
@return
None
@note
- Dependencies
- None
- Side Effects
- None
*/
/*=========================================================================*/
void ipa_is_ipacm_running(void) {
int fd;
struct flock lock;
int retval;
fd = open(IPACM_PID_FILE, O_RDWR | O_CREAT, 0600);
if ( fd <= 0 )
{
IPACMERR("Failed to open %s, error is %d - %s\n",
IPACM_PID_FILE, errno, strerror(errno));
exit(0);
}
/*
* Getting an exclusive Write lock on the file, if it fails,
* it means that another instance of IPACM is running and it
* got the lock before us.
*/
memset(&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
retval = fcntl(fd, F_SETLK, &lock);
if (retval != 0)
{
retval = fcntl(fd, F_GETLK, &lock);
if (retval == 0)
{
IPACMERR("Unable to get lock on file %s (my PID %d), PID %d already has it\n",
IPACM_PID_FILE, getpid(), lock.l_pid);
close(fd);
exit(0);
}
}
else
{
IPACMERR("PID %d is IPACM main process\n", getpid());
}
return;
}
/*===========================================================================
FUNCTION ipa_get_if_index
===========================================================================*/
/*!
@brief
get ipa interface index by given the interface name
@return
IPACM_SUCCESS or IPA_FALUIRE
@note
- Dependencies
- None
- Side Effects
- None
*/
/*=========================================================================*/
int ipa_get_if_index
(
char *if_name,
int *if_index
)
{
int fd;
struct ifreq ifr;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
PERROR("get interface index socket create failed");
return IPACM_FAILURE;
}
memset(&ifr, 0, sizeof(struct ifreq));
(void)strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
{
IPACMERR("call_ioctl_on_dev: ioctl failed: can't find device %s",if_name);
*if_index = -1;
close(fd);
return IPACM_FAILURE;
}
*if_index = ifr.ifr_ifindex;
close(fd);
return IPACM_SUCCESS;
}

View File

@@ -0,0 +1,570 @@
/*
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_Neighbor.cpp
@brief
This file implements the functionality of handling IPACM Neighbor events.
@Author
Skylar Chang
*/
#include <sys/ioctl.h>
#include <IPACM_Neighbor.h>
#include <IPACM_EvtDispatcher.h>
#include "IPACM_Defs.h"
#include "IPACM_Log.h"
IPACM_Neighbor::IPACM_Neighbor()
{
num_neighbor_client = 0;
circular_index = 0;
memset(neighbor_client, 0, IPA_MAX_NUM_NEIGHBOR_CLIENTS * sizeof(ipa_neighbor_client));
IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT_EX, this);
IPACM_EvtDispatcher::registr(IPA_NEW_NEIGH_EVENT, this);
IPACM_EvtDispatcher::registr(IPA_DEL_NEIGH_EVENT, this);
return;
}
void IPACM_Neighbor::event_callback(ipa_cm_event_id event, void *param)
{
ipacm_event_data_all *data_all = NULL;
int i, ipa_interface_index;
ipacm_cmd_q_data evt_data;
int num_neighbor_client_temp = num_neighbor_client;
IPACMDBG("Recieved event %d\n", event);
switch (event)
{
case IPA_WLAN_CLIENT_ADD_EVENT_EX:
{
ipacm_event_data_wlan_ex *data = (ipacm_event_data_wlan_ex *)param;
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("IPA_WLAN_CLIENT_ADD_EVENT_EX: not supported iface id: %d\n", data->if_index);
break;
}
uint8_t client_mac_addr[6];
IPACMDBG_H("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
for(i = 0; i < data->num_of_attribs; i++)
{
if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
{
memcpy(client_mac_addr,
data->attribs[i].u.mac_addr,
sizeof(client_mac_addr));
IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
client_mac_addr[0], client_mac_addr[1], client_mac_addr[2],
client_mac_addr[3], client_mac_addr[4], client_mac_addr[5]);
}
else
{
IPACMDBG_H("The attribute type is not expected!\n");
}
}
for (i = 0; i < num_neighbor_client_temp; i++)
{
/* find the client */
if (memcmp(neighbor_client[i].mac_addr, client_mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
{
/* check if iface is not bridge interface*/
if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
{
/* use previous ipv4 first */
if(data->if_index != neighbor_client[i].iface_index)
{
IPACMERR("update new kernel iface index \n");
neighbor_client[i].iface_index = data->if_index;
}
/* check if client associated with previous network interface */
if(ipa_interface_index != neighbor_client[i].ipa_if_num)
{
IPACMERR("client associate to different AP \n");
return;
}
if (neighbor_client[i].v4_addr != 0) /* not 0.0.0.0 */
{
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
if (data_all == NULL)
{
IPACMERR("Unable to allocate memory\n");
return;
}
data_all->iptype = IPA_IP_v4;
data_all->if_index = neighbor_client[i].iface_index;
data_all->ipv4_addr = neighbor_client[i].v4_addr; //use previous ipv4 address
memcpy(data_all->mac_addr,
neighbor_client[i].mac_addr,
sizeof(data_all->mac_addr));
evt_data.evt_data = (void *)data_all;
IPACM_EvtDispatcher::PostEvt(&evt_data);
/* ask for replaced iface name*/
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("not supported iface id: %d\n", data_all->if_index);
} else {
IPACMDBG_H("Posted event %d, with %s for ipv4 client re-connect\n",
evt_data.event,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
}
}
}
break;
}
}
}
break;
default:
{
if (event == IPA_NEW_NEIGH_EVENT)
{
IPACMDBG_H("Received IPA_NEW_NEIGH_EVENT\n");
}
else
{
IPACMDBG_H("Received IPA_DEL_NEIGH_EVENT\n");
}
ipacm_event_data_all *data = (ipacm_event_data_all *)param;
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("not supported iface id: %d\n", data->if_index);
break;
}
if (data->iptype == IPA_IP_v4)
{
if (data->ipv4_addr != 0) /* not 0.0.0.0 */
{
IPACMDBG("Got Neighbor event with ipv4 address: 0x%x \n", data->ipv4_addr);
/* check if ipv4 address is link local(169.254.xxx.xxx) */
if ((data->ipv4_addr & IPV4_ADDR_LINKLOCAL_MASK) == IPV4_ADDR_LINKLOCAL)
{
IPACMDBG_H("This is link local ipv4 address: 0x%x : ignore this NEIGH_EVENT\n", data->ipv4_addr);
return;
}
/* check if iface is bridge interface*/
if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
{
/* searh if seen this client or not*/
for (i = 0; i < num_neighbor_client_temp; i++)
{
if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
{
data->if_index = neighbor_client[i].iface_index;
neighbor_client[i].v4_addr = data->ipv4_addr; // cache client's previous ipv4 address
/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
if (event == IPA_NEW_NEIGH_EVENT)
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
else
/* not to clean-up the client mac cache on bridge0 delneigh */
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
if (data_all == NULL)
{
IPACMERR("Unable to allocate memory\n");
return;
}
memcpy(data_all, data, sizeof(ipacm_event_data_all));
evt_data.evt_data = (void *)data_all;
IPACM_EvtDispatcher::PostEvt(&evt_data);
/* ask for replaced iface name*/
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("not supported iface id: %d\n", data_all->if_index);
} else {
IPACMDBG_H("Posted event %d,\
with %s for ipv4\n",
evt_data.event,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
}
break;
}
}
}
else
{
/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
if (event == IPA_NEW_NEIGH_EVENT)
{
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
/* Also save to cache for ipv4 */
/*searh if seen this client or not*/
for (i = 0; i < num_neighbor_client_temp; i++)
{
/* find the client */
if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
{
/* update the network interface client associated */
neighbor_client[i].iface_index = data->if_index;
neighbor_client[i].ipa_if_num = ipa_interface_index;
neighbor_client[i].v4_addr = data->ipv4_addr; // cache client's previous ipv4 address
IPACMDBG_H("update cache %d-entry, with %s iface, ipv4 address: 0x%x\n",
i,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
data->ipv4_addr);
break;
}
}
/* not find client */
if (i == num_neighbor_client_temp)
{
if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
{
memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
data->mac_addr,
sizeof(data->mac_addr));
neighbor_client[num_neighbor_client_temp].iface_index = data->if_index;
/* cache the network interface client associated */
neighbor_client[num_neighbor_client_temp].ipa_if_num = ipa_interface_index;
neighbor_client[num_neighbor_client_temp].v4_addr = data->ipv4_addr;
num_neighbor_client++;
IPACMDBG_H("Cache client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
neighbor_client[num_neighbor_client_temp].mac_addr[0],
neighbor_client[num_neighbor_client_temp].mac_addr[1],
neighbor_client[num_neighbor_client_temp].mac_addr[2],
neighbor_client[num_neighbor_client_temp].mac_addr[3],
neighbor_client[num_neighbor_client_temp].mac_addr[4],
neighbor_client[num_neighbor_client_temp].mac_addr[5],
num_neighbor_client);
}
else
{
IPACMERR("error: neighbor client oversize! recycle %d-st entry ! \n", circular_index);
memcpy(neighbor_client[circular_index].mac_addr,
data->mac_addr,
sizeof(data->mac_addr));
neighbor_client[circular_index].iface_index = data->if_index;
/* cache the network interface client associated */
neighbor_client[circular_index].ipa_if_num = ipa_interface_index;
neighbor_client[circular_index].v4_addr = 0;
IPACMDBG_H("Copy wlan-iface client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d, circular %d\n",
neighbor_client[circular_index].mac_addr[0],
neighbor_client[circular_index].mac_addr[1],
neighbor_client[circular_index].mac_addr[2],
neighbor_client[circular_index].mac_addr[3],
neighbor_client[circular_index].mac_addr[4],
neighbor_client[circular_index].mac_addr[5],
num_neighbor_client,
circular_index);
circular_index++;
}
}
}
else
{
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
/*searh if seen this client or not*/
for (i = 0; i < num_neighbor_client_temp; i++)
{
/* find the client */
if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
{
IPACMDBG_H("Clean %d-st Cached client-MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
i,
neighbor_client[i].mac_addr[0],
neighbor_client[i].mac_addr[1],
neighbor_client[i].mac_addr[2],
neighbor_client[i].mac_addr[3],
neighbor_client[i].mac_addr[4],
neighbor_client[i].mac_addr[5],
num_neighbor_client);
memset(neighbor_client[i].mac_addr, 0, sizeof(neighbor_client[i].mac_addr));
neighbor_client[i].iface_index = 0;
neighbor_client[i].v4_addr = 0;
neighbor_client[i].ipa_if_num = 0;
for (; i < num_neighbor_client_temp - 1; i++)
{
memcpy(neighbor_client[i].mac_addr,
neighbor_client[i+1].mac_addr,
sizeof(neighbor_client[i].mac_addr));
neighbor_client[i].iface_index = neighbor_client[i+1].iface_index;
neighbor_client[i].v4_addr = neighbor_client[i+1].v4_addr;
neighbor_client[i].ipa_if_num = neighbor_client[i+1].ipa_if_num;
}
num_neighbor_client--;
IPACMDBG_H(" total number of left cased clients: %d\n", num_neighbor_client);
break;
}
}
/* not find client, no need clean-up */
}
data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
if (data_all == NULL)
{
IPACMERR("Unable to allocate memory\n");
return;
}
memcpy(data_all, data, sizeof(ipacm_event_data_all));
evt_data.evt_data = (void *)data_all;
IPACM_EvtDispatcher::PostEvt(&evt_data);
IPACMDBG_H("Posted event %d with %s for ipv4\n",
evt_data.event,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
}
}
}
else
{ //ipv6 starts
if ((data->ipv6_addr[0]) || (data->ipv6_addr[1]) || (data->ipv6_addr[2]) || (data->ipv6_addr[3]))
{
IPACMDBG("Got New_Neighbor event with ipv6 address \n");
/* check if iface is bridge interface*/
if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
{
/* searh if seen this client or not*/
for (i = 0; i < num_neighbor_client_temp; i++)
{
if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
{
data->if_index = neighbor_client[i].iface_index;
/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
if (event == IPA_NEW_NEIGH_EVENT) evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
else evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
if (data_all == NULL)
{
IPACMERR("Unable to allocate memory\n");
return;
}
memcpy(data_all, data, sizeof(ipacm_event_data_all));
evt_data.evt_data = (void *)data_all;
IPACM_EvtDispatcher::PostEvt(&evt_data);
/* ask for replaced iface name*/
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("not supported iface id: %d\n", data_all->if_index);
} else {
IPACMDBG_H("Posted event %d,\
with %s for ipv6\n",
evt_data.event,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
}
break;
};
}
}
else
{
/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
if (event == IPA_NEW_NEIGH_EVENT)
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
else
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
if (data_all == NULL)
{
IPACMERR("Unable to allocate memory\n");
return;
}
memcpy(data_all, data, sizeof(ipacm_event_data_all));
evt_data.evt_data = (void *)data_all;
IPACM_EvtDispatcher::PostEvt(&evt_data);
IPACMDBG_H("Posted event %d with %s for ipv6\n",
evt_data.event,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
}
}
else
{
IPACMDBG(" Got Neighbor event with no ipv6/ipv4 address \n");
/*no ipv6 in data searh if seen this client or not*/
for (i = 0; i < num_neighbor_client_temp; i++)
{
/* find the client */
if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
{
IPACMDBG_H(" find %d-st client, MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
i,
neighbor_client[i].mac_addr[0],
neighbor_client[i].mac_addr[1],
neighbor_client[i].mac_addr[2],
neighbor_client[i].mac_addr[3],
neighbor_client[i].mac_addr[4],
neighbor_client[i].mac_addr[5],
num_neighbor_client);
/* check if iface is not bridge interface*/
if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
{
/* use previous ipv4 first */
if(data->if_index != neighbor_client[i].iface_index)
{
IPACMDBG_H("update new kernel iface index \n");
neighbor_client[i].iface_index = data->if_index;
}
/* check if client associated with previous network interface */
if(ipa_interface_index != neighbor_client[i].ipa_if_num)
{
IPACMDBG_H("client associate to different AP \n");
}
if (neighbor_client[i].v4_addr != 0) /* not 0.0.0.0 */
{
/* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
if (event == IPA_NEW_NEIGH_EVENT)
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
else
evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
if (data_all == NULL)
{
IPACMERR("Unable to allocate memory\n");
return;
}
data_all->iptype = IPA_IP_v4;
data_all->if_index = neighbor_client[i].iface_index;
data_all->ipv4_addr = neighbor_client[i].v4_addr; //use previous ipv4 address
memcpy(data_all->mac_addr,
neighbor_client[i].mac_addr,
sizeof(data_all->mac_addr));
evt_data.evt_data = (void *)data_all;
IPACM_EvtDispatcher::PostEvt(&evt_data);
/* ask for replaced iface name*/
ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
/* check for failure return */
if (IPACM_FAILURE == ipa_interface_index) {
IPACMERR("not supported iface id: %d\n", data_all->if_index);
} else {
IPACMDBG_H("Posted event %d,\
with %s for ipv4 client re-connect\n",
evt_data.event,
IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
}
}
}
/* delete cache neighbor entry */
if (event == IPA_DEL_NEIGH_EVENT)
{
IPACMDBG_H("Clean %d-st Cached client-MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
i,
neighbor_client[i].mac_addr[0],
neighbor_client[i].mac_addr[1],
neighbor_client[i].mac_addr[2],
neighbor_client[i].mac_addr[3],
neighbor_client[i].mac_addr[4],
neighbor_client[i].mac_addr[5],
num_neighbor_client);
memset(neighbor_client[i].mac_addr, 0, sizeof(neighbor_client[i].mac_addr));
neighbor_client[i].iface_index = 0;
neighbor_client[i].v4_addr = 0;
neighbor_client[i].ipa_if_num = 0;
for (; i < num_neighbor_client_temp - 1; i++)
{
memcpy(neighbor_client[i].mac_addr,
neighbor_client[i+1].mac_addr,
sizeof(neighbor_client[i].mac_addr));
neighbor_client[i].iface_index = neighbor_client[i+1].iface_index;
neighbor_client[i].v4_addr = neighbor_client[i+1].v4_addr;
neighbor_client[i].ipa_if_num = neighbor_client[i+1].ipa_if_num;
}
num_neighbor_client--;
IPACMDBG_H(" total number of left cased clients: %d\n", num_neighbor_client);
}
break;
}
}
/* not find client */
if ((i == num_neighbor_client_temp) && (event == IPA_NEW_NEIGH_EVENT))
{
/* check if iface is not bridge interface*/
if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
{
if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
{
memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
data->mac_addr,
sizeof(data->mac_addr));
neighbor_client[num_neighbor_client_temp].iface_index = data->if_index;
/* cache the network interface client associated */
neighbor_client[num_neighbor_client_temp].ipa_if_num = ipa_interface_index;
neighbor_client[num_neighbor_client_temp].v4_addr = 0;
num_neighbor_client++;
IPACMDBG_H("Copy client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
neighbor_client[num_neighbor_client_temp].mac_addr[0],
neighbor_client[num_neighbor_client_temp].mac_addr[1],
neighbor_client[num_neighbor_client_temp].mac_addr[2],
neighbor_client[num_neighbor_client_temp].mac_addr[3],
neighbor_client[num_neighbor_client_temp].mac_addr[4],
neighbor_client[num_neighbor_client_temp].mac_addr[5],
num_neighbor_client);
return;
}
else
{
IPACMERR("error: neighbor client oversize! recycle %d-st entry ! \n", circular_index);
memcpy(neighbor_client[circular_index].mac_addr,
data->mac_addr,
sizeof(data->mac_addr));
neighbor_client[circular_index].iface_index = data->if_index;
/* cache the network interface client associated */
neighbor_client[circular_index].ipa_if_num = ipa_interface_index;
neighbor_client[circular_index].v4_addr = 0;
IPACMDBG_H("Copy wlan-iface client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d, circular %d\n",
neighbor_client[circular_index].mac_addr[0],
neighbor_client[circular_index].mac_addr[1],
neighbor_client[circular_index].mac_addr[2],
neighbor_client[circular_index].mac_addr[3],
neighbor_client[circular_index].mac_addr[4],
neighbor_client[circular_index].mac_addr[5],
num_neighbor_client,
circular_index);
circular_index++;
return;
}
}
}
}
} //ipv6 ends
}
break;
}
return;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,276 @@
/*
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_Routing.cpp
@brief
This file implements the IPACM routing functionality.
@Author
*/
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include "IPACM_Routing.h"
#include <IPACM_Log.h>
const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa";
IPACM_Routing::IPACM_Routing()
{
m_fd = open(DEVICE_NAME, O_RDWR);
if (0 == m_fd)
{
IPACMERR("Failed opening %s.\n", DEVICE_NAME);
}
}
IPACM_Routing::~IPACM_Routing()
{
close(m_fd);
}
bool IPACM_Routing::DeviceNodeIsOpened()
{
int res = fcntl(m_fd, F_GETFL);
if (m_fd > 0 && res >= 0) return true;
else return false;
}
bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
{
int retval = 0, cnt=0;
bool isInvalid = false;
if (!DeviceNodeIsOpened())
{
IPACMERR("Device is not opened\n");
return false;
}
for(cnt=0; cnt<ruleTable->num_rules; cnt++)
{
if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX)
{
IPACMERR("Invalid dst pipe, Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
isInvalid = true;
}
}
if(isInvalid)
{
return false;
}
retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
if (retval)
{
IPACMERR("Failed adding routing rule %p\n", ruleTable);
return false;
}
for(cnt=0; cnt<ruleTable->num_rules; cnt++)
{
IPACMDBG("Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
}
IPACMDBG_H("Added routing rule %p\n", ruleTable);
return true;
}
bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
{
int retval = 0;
if (!DeviceNodeIsOpened()) return false;
retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
if (retval)
{
IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
return false;
}
IPACMDBG_H("Deleted routing rule %p\n", ruleTable);
return true;
}
bool IPACM_Routing::Commit(enum ipa_ip_type ip)
{
int retval = 0;
if (!DeviceNodeIsOpened()) return false;
retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
if (retval)
{
IPACMERR("Failed commiting routing rules.\n");
return false;
}
IPACMDBG_H("Commited routing rules to IPA HW.\n");
return true;
}
bool IPACM_Routing::Reset(enum ipa_ip_type ip)
{
int retval = 0;
if (!DeviceNodeIsOpened()) return false;
retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
if (retval)
{
IPACMERR("Failed resetting routing block.\n");
return false;
}
IPACMDBG_H("Reset command issued to IPA routing block.\n");
return true;
}
bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
{
int retval = 0;
if (!DeviceNodeIsOpened()) return false;
retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
if (retval)
{
IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
return false;
}
IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
/* put routing table right after successfully get routing table */
PutRoutingTable(routingTable->hdl);
return true;
}
bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
{
int retval = 0;
if (!DeviceNodeIsOpened()) return false;
retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
if (retval)
{
IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
return false;
}
IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
return true;
}
bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
{
const uint8_t NUM_RULES = 1;
struct ipa_ioc_del_rt_rule *rt_rule;
struct ipa_rt_rule_del *rt_rule_entry;
bool res = true;
int len = 0;
if (rt_rule_hdl == 0)
{
IPACMERR(" No route handle passed. Ignoring it\n");
return res;
}
len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
if (rt_rule == NULL)
{
IPACMERR("unable to allocate memory for del route rule\n");
return false;
}
memset(rt_rule, 0, len);
rt_rule->commit = 1;
rt_rule->num_hdls = NUM_RULES;
rt_rule->ip = ip;
rt_rule_entry = &rt_rule->hdl[0];
rt_rule_entry->status = -1;
rt_rule_entry->hdl = rt_rule_hdl;
IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
if ((false == DeleteRoutingRule(rt_rule)) ||
(rt_rule_entry->status))
{
PERROR("Routing rule deletion failed!\n");
goto fail;
res = false;
}
fail:
free(rt_rule);
return res;
}
bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules)
{
int retval = 0, cnt;
if (!DeviceNodeIsOpened())
{
IPACMERR("Device is not opened\n");
return false;
}
retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules);
if (retval)
{
IPACMERR("Failed modifying routing rules %p\n", mdfyRules);
return false;
}
for(cnt=0; cnt<mdfyRules->num_rules; cnt++)
{
if(mdfyRules->rules[cnt].status != 0)
{
IPACMERR("Unable to modify rule: %d\n", cnt);
}
}
IPACMDBG_H("Modified routing rules %p\n", mdfyRules);
return true;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ipacm_cfg.xsd">
<ODUCFG>
<OduMode>router</OduMode>
<eMBMS_offload>0</eMBMS_offload>
</ODUCFG>
<IPACM>
<IPACMIface>
<Iface>
<Name>rndis0</Name>
<Category>LAN</Category>
</Iface>
<Iface>
<Name>ecm0</Name>
<Category>LAN</Category>
<Mode>ROUTER</Mode>
</Iface>
<Iface>
<Name>rmnet_data0</Name>
<Category>WAN</Category>
<Mode>ROUTER</Mode>
</Iface>
<Iface>
<Name>rmnet_data1</Name>
<Category>WAN</Category>
</Iface>
<Iface>
<Name>rmnet_data2</Name>
<Category>WAN</Category>
</Iface>
<Iface>
<Name>rmnet_data3</Name>
<Category>WAN</Category>
</Iface>
<Iface>
<Name>rmnet_data4</Name>
<Category>WAN</Category>
</Iface>
<Iface>
<Name>rmnet_data5</Name>
<Category>WAN</Category>
</Iface>
<Iface>
<Name>rmnet_data6</Name>
<Category>WAN</Category>
</Iface>
<Iface>
<Name>rmnet_data7</Name>
<Category>WAN</Category>
</Iface>
<Iface>
<Name>softap0</Name>
<Category>UNKNOWN</Category>
<WlanMode>full</WlanMode>
</Iface>
<Iface>
<Name>wlan0</Name>
<Category>UNKNOWN</Category>
<WlanMode>full</WlanMode>
</Iface>
<Iface>
<Name>wlan1</Name>
<Category>UNKNOWN</Category>
<WlanMode>full</WlanMode>
</Iface>
<Iface>
<Name>wlan2</Name>
<Category>UNKNOWN</Category>
<WlanMode>full</WlanMode>
</Iface>
<Iface>
<Name>wlan3</Name>
<Category>UNKNOWN</Category>
<WlanMode>full</WlanMode>
</Iface>
<Iface>
<Name>eth0</Name>
<Category>ODU</Category>
</Iface>
<Iface>
<Name>bridge0</Name>
<Category>VIRTUAL</Category>
</Iface>
</IPACMIface>
<IPPassthroughFlag>
<IPPassthroughMode>0</IPPassthroughMode>
</IPPassthroughFlag>
<IPACMPrivateSubnet>
<Subnet>
<SubnetAddress>192.168.225.0</SubnetAddress>
<SubnetMask>255.255.255.0</SubnetMask>
</Subnet>
</IPACMPrivateSubnet>
<IPACMALG>
<ALG>
<Protocol>TCP</Protocol>
<Port>21</Port>
<Description>FTP</Description>
</ALG>
<ALG>
<Protocol>TCP</Protocol>
<Port>554</Port>
<Description>RTSP</Description>
</ALG>
<ALG>
<Protocol>TCP</Protocol>
<Port>5060</Port>
<Description>SIP</Description>
</ALG>
<ALG>
<Protocol>UDP</Protocol>
<Port>5060</Port>
<Description>SIP</Description>
</ALG>
<ALG>
<Protocol>TCP</Protocol>
<Port>1723</Port>
<Description>PPTP</Description>
</ALG>
<ALG>
<Protocol>UDP</Protocol>
<Port>69</Port>
<Description>TFTP</Description>
</ALG>
<ALG>
<Protocol>UDP</Protocol>
<Port>53</Port>
<Description>DNS</Description>
</ALG>
<ALG>
<Protocol>TCP</Protocol>
<Port>53</Port>
<Description>DNS</Description>
</ALG>
<ALG>
<Protocol>UDP</Protocol>
<Port>10080</Port>
<Description>AMANDA</Description>
</ALG>
<ALG>
<Protocol>UDP</Protocol>
<Port>1719</Port>
<Description>H323</Description>
</ALG>
<ALG>
<Protocol>TCP</Protocol>
<Port>1720</Port>
<Description>H323</Description>
</ALG>
<ALG>
<Protocol>TCP</Protocol>
<Port>6667</Port>
<Description>IRC</Description>
</ALG>
<ALG>
<Protocol>UDP</Protocol>
<Port>137</Port>
<Description>NETBIOS_NS</Description>
</ALG>
<ALG>
<Protocol>UDP</Protocol>
<Port>138</Port>
<Description>NETBIOS_NS</Description>
</ALG>
<ALG>
<Protocol>TCP</Protocol>
<Port>6566</Port>
<Description>SANE</Description>
</ALG>
</IPACMALG>
<IPACMNAT>
<MaxNatEntries>500</MaxNatEntries>
</IPACMNAT>
</IPACM>
</system>

View File

@@ -0,0 +1,55 @@
AM_CPPFLAGS = -I./../inc \
-I$(top_srcdir)/ipanat/inc \
${LIBXML_CFLAGS}
AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
AM_CPPFLAGS += -DDEBUG -g -DFEATURE_ETH_BRIDGE_LE
AM_CPPFLAGS += -DFEATURE_IPA_V3
ipacm_SOURCES = IPACM_Main.cpp \
IPACM_Conntrack_NATApp.cpp\
IPACM_ConntrackClient.cpp \
IPACM_ConntrackListener.cpp \
IPACM_EvtDispatcher.cpp \
IPACM_Config.cpp \
IPACM_CmdQueue.cpp \
IPACM_Log.cpp \
IPACM_Filtering.cpp \
IPACM_Routing.cpp \
IPACM_Header.cpp \
IPACM_Lan.cpp \
IPACM_Iface.cpp \
IPACM_Wlan.cpp \
IPACM_Wan.cpp \
IPACM_IfaceManager.cpp \
IPACM_Neighbor.cpp \
IPACM_Netlink.cpp \
IPACM_Xml.cpp \
IPACM_LanToLan.cpp
bin_PROGRAMS = ipacm
requiredlibs = ${LIBXML_LIB} -lxml2 -lpthread -lnetfilter_conntrack -lnfnetlink\
../../ipanat/src/libipanat.la
AM_CPPFLAGS += "-std=c++0x"
if USE_GLIB
ipacm_CFLAGS = $(AM_CFLAGS) -DUSE_GLIB @GLIB_CFLAGS@
ipacm_LDFLAGS = -lpthread @GLIB_LIBS@
ipacm_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
else
ipacm_CFLAGS = $(AM_CFLAGS)
ipacm_LDFLAGS = -lpthread
ipacm_CPPFLAGS = $(AM_CPPFLAGS)
endif
ipacm_LDADD = $(requiredlibs)
LOCAL_MODULE := libipanat
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
etcdir = ${sysconfdir}
etc_SCRIPTS = IPACM_cfg.xml
init_ddir = ${sysconfdir}/init.d
init_d_SCRIPTS = start_ipacm_le

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="mobileap_firewall_cfg.xsd">
<MobileAPFirewallCfg>
<FirewallEnabled>1</FirewallEnabled>
<FirewallPktsAllowed>0</FirewallPktsAllowed>
</MobileAPFirewallCfg>
</system>

View File

@@ -0,0 +1,57 @@
#! /bin/sh
#
################################
# 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.
################################
# ipacm init.d script to start the data-ipa Software's ipacm daemon
set -e
case "$1" in
start)
echo -n "Starting ipacm: "
start-stop-daemon -S -b -a ipacm
echo "done"
;;
stop)
echo -n "Stopping ipacm: "
start-stop-daemon -K -n ipacm
echo "done"
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage ipacm { start | stop | restart}" >&2
exit 1
;;
esac
exit 0