IPA configuration manager daemon and IPA NAT library.
These are user-space components which configure IPA
(Internet Protocol Accelerator) HW using the services
provided by the IPA driver (running in kernel space).
NAT stands for Network Address Translation. This is the
initial commit of these components.
Change-Id: I0934f54c36a7134af143e4f1cd9fbb0682df52d0
diff --git a/ipacm/src/IPACM_CmdQueue.cpp b/ipacm/src/IPACM_CmdQueue.cpp
new file mode 100644
index 0000000..632ae5d
--- /dev/null
+++ b/ipacm/src/IPACM_CmdQueue.cpp
@@ -0,0 +1,165 @@
+/*
+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_CmdQueue.cpp
+
+ @brief
+ This file implements the IPAM Comment Queue functionality
+
+ @Author
+ Sunil
+
+*/
+#include <string.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Log.h"
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
+
+MessageQueue* MessageQueue::inst = NULL;
+MessageQueue* MessageQueue::getInstance()
+{
+ if(inst == NULL)
+ {
+ inst = new MessageQueue();
+ if(inst == NULL)
+ {
+ IPACMERR("unable to create Message Queue instance\n");
+ return NULL;
+ }
+ }
+
+ return inst;
+}
+
+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 *MsgQueue = NULL;
+ Message *item = NULL;
+ IPACMDBG("MessageQueue::Process()\n");
+
+ MsgQueue = MessageQueue::getInstance();
+ if(MsgQueue == NULL)
+ {
+ IPACMDBG("unable to start cmd queue process\n");
+ return NULL;
+ }
+
+ while(1)
+ {
+ if(pthread_mutex_lock(&mutex) != 0)
+ {
+ IPACMERR("unable to lock the mutex\n");
+ return NULL;
+ }
+
+ item = MsgQueue->dequeue();
+
+ 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\n",item);
+ item->evt.callback_ptr(&item->evt.data);
+ delete item;
+ item = NULL;
+ }
+
+ } /* Go forever until a termination indication is received */
+
+}
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
new file mode 100644
index 0000000..413d1ba
--- /dev/null
+++ b/ipacm/src/IPACM_Config.cpp
@@ -0,0 +1,190 @@
+/*
+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_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>
+
+IPACM_Config *IPACM_Config::pInstance = NULL;
+
+IPACM_Config::IPACM_Config()
+{
+ iface_table = NULL;
+ alg_table = NULL;
+ memset(&private_subnet_table, 0, sizeof(private_subnet_table));
+
+ ipa_num_ipa_interfaces = 0;
+ ipa_num_private_subnet = 0;
+ ipa_num_alg_ports = 0;
+ ipa_nat_max_entries = 0;
+
+ 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));
+
+ IPACMDBG(" 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));
+ uint32_t subnet_addr;
+ uint32_t subnet_mask;
+ int i, ret = IPACM_SUCCESS;
+
+ strncpy(IPACM_config_file, "/etc/IPACM_cfg.xml", sizeof(IPACM_config_file));
+
+
+ IPACMDBG("\n IPACM XML file is %s \n", IPACM_config_file);
+ if (IPACM_SUCCESS == ipacm_read_cfg_xml(IPACM_config_file, cfg))
+ {
+ IPACMDBG("\n IPACM XML read OK \n");
+ }
+ else
+ {
+ IPACMERR("\n IPACM XML read failed \n");
+ ret = IPACM_FAILURE;
+ goto fail;
+ }
+
+ /* Construct IPACM Iface table */
+ ipa_num_ipa_interfaces = cfg->iface_config.num_iface_entries;
+ iface_table = (ipa_ifi_dev_name_t *)calloc(ipa_num_ipa_interfaces,
+ sizeof(ipa_ifi_dev_name_t));
+
+ 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;
+ IPACMDBG("IPACM_Config::iface_table[%d] = %s, cat=%d\n", i, iface_table[i].iface_name, iface_table[i].if_cat);
+ }
+
+ /* Construct IPACM 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);
+ IPACMDBG("%dst::private_subnet_table= %s \n ", i,
+ inet_ntoa(*(struct in_addr *)&(subnet_addr)));
+
+ subnet_mask = htonl(private_subnet_table[i].subnet_mask);
+ IPACMDBG("%dst::private_subnet_table= %s \n ", i,
+ inet_ntoa(*(struct in_addr *)&(subnet_mask)));
+ }
+
+ /* Construct IPACM ALG table */
+ ipa_num_alg_ports = cfg->alg_config.num_alg_entries;
+ alg_table = (ipacm_alg *)calloc(ipa_num_alg_ports,
+ sizeof(ipacm_alg));
+
+ for (i = 0; i < cfg->alg_config.num_alg_entries; i++)
+ {
+ //strncpy(alg_table[i].protocol, cfg->alg_config.alg_entries[i].protocol, sizeof(alg_table[i].protocol));
+ alg_table[i].protocol = cfg->alg_config.alg_entries[i].protocol;
+ alg_table[i].port = cfg->alg_config.alg_entries[i].port;
+ IPACMDBG("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("Nat Maximum Entries %d\n", ipa_nat_max_entries);
+
+ /* Construct the routing table ictol name in iface static member*/
+ 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_v6.ip = IPA_IP_v6;
+ strncpy(rt_tbl_v6.name, V6_COMMON_ROUTE_TABLE_NAME, sizeof(rt_tbl_v6.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));
+
+fail:
+ free(cfg);
+
+ 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;
+ 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;
+}
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
new file mode 100644
index 0000000..7e48822
--- /dev/null
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -0,0 +1,699 @@
+/*
+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 <iostream>
+
+#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_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_Log.h"
+
+#define LO_NAME "lo"
+
+extern IPACM_EvtDispatcher cm_dis;
+
+IPACM_ConntrackClient *IPACM_ConntrackClient::pInstance = NULL;
+IPACM_ConntrackListener *ct = new IPACM_ConntrackListener();
+
+/* ================================
+ Local Function Definitions
+ =================================
+*/
+#ifdef IPACM_DEBUG
+void IPACM_ConntrackClient::iptodot(const char *type, uint32_t ipAddr)
+{
+ int i;
+ unsigned char octet[4] = { 0 };
+ IPACMDBG("Received IPv4 addr: 0x%x\n", ipAddr);
+
+ for(i = 0; i < 4; i++)
+ {
+ octet[i] = (ipAddr >> (i * 8)) & 0xFF;
+ }
+
+ IPACMDBG("%s:", type);
+ IPACMDBG("%d.%d.%d.%d\n", octet[3], octet[2], octet[1], octet[0]);
+}
+#endif
+
+IPACM_ConntrackClient::IPACM_ConntrackClient()
+{
+ IPACMDBG("%s %d", __FUNCTION__, __LINE__);
+
+ tcp_hdl = NULL;
+ udp_hdl = NULL;
+ tcp_filter = NULL;
+ udp_filter = NULL;
+}
+
+IPACM_ConntrackClient* IPACM_ConntrackClient::GetInstance()
+{
+ if(pInstance == NULL)
+ {
+ pInstance = new IPACM_ConntrackClient();
+ }
+
+ 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;
+
+ IPACMDBG("Event callback called with msgtype: %d\n",type);
+
+ ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
+ if(ct_data == NULL)
+ {
+ IPACMERR("unable to allocate memory \n");
+ return -1;
+ }
+
+ ct_data->ct = ct;
+ ct_data->type = type;
+
+ evt_data.event = IPA_PROCESS_CT_MESSAGE;
+ evt_data.evt_data = (void *)ct_data;
+
+ if(0 != IPACM_EvtDispatcher::PostEvt(&evt_data))
+ {
+ IPACMERR("Error sending Conntrack message to processing thread!\n");
+ free(ct_data);
+ }
+
+#if 0
+ IPACMDBG("Posted message to Cmd Queue\n");
+#endif
+
+ /* 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;
+}
+
+
+/* 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
+)
+{
+ char buf[1024];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ int i, sck, nInterfaces;
+ 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);
+
+
+
+ /* Get a socket handle. */
+ sck = socket(AF_INET, SOCK_DGRAM, 0);
+ if(sck < 0)
+ {
+ PERROR("socket");
+ return -1;
+ }
+
+ /* Query available interfaces. */
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+
+ /* get iface list */
+ if(ioctl(sck, SIOCGIFCONF, &ifc) < 0)
+ {
+ PERROR("ioctl(SIOCGIFCONF)");
+ return -1;
+ }
+
+ /* Iterate through the list of interfaces. */
+ ifr = ifc.ifc_req;
+ nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
+
+#ifdef IPACM_DEBUG
+ IPACMDBG("====Printing Local Interfaces=====\n");
+#endif
+
+ for(i = 0; i < nInterfaces; i++)
+ {
+ /* Interface request structure */
+ struct ifreq *item = &ifr[i];
+
+#ifdef IPACM_DEBUG
+ /* Show the device name and IP address */
+ if(item->ifr_name != NULL)
+ {
+ IPACMDBG("%s: IP %s\n",
+ item->ifr_name,
+ inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr));
+ }
+#endif
+
+ /* Convert data to host-byte order */
+ filter_ipv4.addr =
+ ntohl(inet_addr(inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr)));
+ filter_ipv4.mask = 0xffffffff;
+
+ /* ignore whatever is destined to or originates from local interfaces */
+ if(item->ifr_name != NULL)
+ {
+ if(strncmp(ct->wan_ifname, item->ifr_name, strlen(item->ifr_name)) != 0)
+ {
+ IPACMDBG("ignore connections destinated to interface %s\n", item->ifr_name);
+ IPACM_ConntrackClient::iptodot("with ipv4 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);
+ }
+ }
+
+ IPACMDBG("ignore connections orignated to interface %s\n", item->ifr_name);
+ IPACM_ConntrackClient::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);
+
+ /* Find broadcast address for non lo interfaces */
+ if(strncmp(LO_NAME, item->ifr_name, 2) != 0)
+ {
+ /* Get the broadcast address */
+ if(ioctl(sck, SIOCGIFBRDADDR, item) < 0)
+ {
+ PERROR("broadcast address error: ioctl(SIOCGIFBRDADDR)");
+ return -1;
+ }
+
+#ifdef IPACM_DEBUG
+ /* Show the device name and IP address */
+ if(item->ifr_name != NULL)
+ {
+ IPACMDBG("%s: BroadCast IP %s\n",
+ item->ifr_name,
+ inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr));
+ }
+#endif
+
+ /* Convert data to host-byte order */
+ filter_ipv4.addr =
+ ntohl(inet_addr(inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr)));
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACMDBG("ignore connections destinated to interface %s broadcast\n", item->ifr_name);
+ IPACM_ConntrackClient::iptodot("with ipv4 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);
+ }
+
+ }
+
+ close(sck);
+ 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 = IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->tcp_filter);
+ if(ret == -1)
+ {
+ IPACMERR("Unable to set local addr filters\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();
+
+ ret = IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+ if(ret == -1)
+ {
+ IPACMERR("Unable to set local addr filters\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)
+{
+
+#ifdef IPACM_DEBUG
+ IPACMDBG("\n");
+#endif
+
+ while(1)
+ {
+ NatApp::GetInstance()->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;
+
+ IPACMDBG("\n");
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to get conntrack client instance\n");
+ return -1;
+ }
+
+ pClient->tcp_hdl = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_UPDATE);
+ if(pClient->tcp_hdl == NULL)
+ {
+ PERROR("nfct_open\n");
+ return NULL;
+ }
+
+ /* Allocate new filter */
+ pClient->tcp_filter = nfct_filter_create();
+ if(pClient->tcp_filter == NULL)
+ {
+ IPACMERR("unable to create TCP filter\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("tcp handle:%p, fd:%d\n", pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl));
+ nfct_callback_register(pClient->tcp_hdl, NFCT_T_UPDATE, IPAConntrackEventCB, NULL);
+
+ /* 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;
+ }
+
+ /* Add filter */
+ //struct nfct_filter *udp_filter = NULL;
+
+ /* Allocate new filter */
+ pClient->udp_filter = nfct_filter_create();
+ if(pClient->udp_filter == NULL)
+ {
+ IPACMERR("unable to create UDP filter\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("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 */
+ ret = nfct_catch(pClient->udp_hdl);
+ if(ret == -1)
+ {
+ IPACMDBG("(%d)(%s)\n", ret, strerror(errno));
+ return NULL;
+ }
+
+
+ IPACMDBG("Exit from udp thread\n");
+
+ /* 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)
+{
+ int ret = 0;
+ struct nfct_filter_ipv4 filter_ipv4;
+ IPACM_ConntrackClient *pClient = NULL;
+
+ /* Intialize with 255.255.255.255 */
+ uint32_t bc_ip_addr = 0xFFFFFFFF;
+
+ uint32_t ipv4_addr = ((ipacm_event_iface_up *)param)->ipv4_addr;
+ uint32_t ipv4_addr_mask = ((ipacm_event_iface_up *)param)->addr_mask;
+
+ IPACM_ConntrackClient::iptodot("Received ipv4 address and", ipv4_addr);
+ IPACM_ConntrackClient::iptodot("ipv4 address mask", ipv4_addr_mask);
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to retrieve conntrack client instance\n");
+ return;
+ }
+
+ /* calculate broadcast address from addr and addr_mask */
+ bc_ip_addr = (bc_ip_addr & (~ipv4_addr_mask));
+ bc_ip_addr = (bc_ip_addr | (ipv4_addr & ipv4_addr_mask));
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = ipv4_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACMDBG("ignoring interface:%s", ((ipacm_event_iface_up *)param)->ifname);
+ IPACM_ConntrackClient::iptodot("with ipv4 address", filter_ipv4.addr);
+ if(pClient->udp_filter != NULL)
+ {
+ nfct_filter_set_logic(pClient->udp_filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ nfct_filter_set_logic(pClient->udp_filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+ }
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = bc_ip_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACM_ConntrackClient::iptodot("with broadcast address", filter_ipv4.addr);
+ if(pClient->udp_filter != NULL)
+ {
+ nfct_filter_set_logic(pClient->udp_filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+ }
+
+ /* 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)
+{
+ int ret = 0;
+ uint32_t ipv4_addr = ((ipacm_event_iface_up *)param)->ipv4_addr;
+ uint32_t ipv4_addr_mask = ((ipacm_event_iface_up *)param)->addr_mask;
+ struct nfct_filter_ipv4 filter_ipv4;
+ IPACM_ConntrackClient *pClient = NULL;
+ /* Intialize with 255.255.255.255 */
+ uint32_t bc_ip_addr = 0xFFFFFFFF;
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to retrieve conntrack client instance\n");
+ return;
+ }
+
+ /* calculate broadcast address from addr and addr_mask */
+ bc_ip_addr = (bc_ip_addr & (~ipv4_addr_mask));
+ bc_ip_addr = (bc_ip_addr | (ipv4_addr & ipv4_addr_mask));
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = ipv4_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACMDBG("ignoring interface:%s", ((ipacm_event_iface_up *)param)->ifname);
+ IPACM_ConntrackClient::iptodot("with ipv4 address", filter_ipv4.addr);
+
+ if(pClient->tcp_filter != NULL)
+ {
+ nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+ }
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = bc_ip_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACM_ConntrackClient::iptodot("with broadcast address", filter_ipv4.addr);
+ if(pClient->tcp_filter != NULL)
+ {
+ nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+ }
+
+ /* 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;
+}
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
new file mode 100644
index 0000000..66a6355
--- /dev/null
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -0,0 +1,429 @@
+/*
+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 "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_EvtDispatcher.h"
+
+IPACM_ConntrackListener::IPACM_ConntrackListener()
+{
+ IPACMDBG("%d %s()\n", __LINE__, __FUNCTION__);
+
+ isCTReg = false;
+ isWanUp = false;
+
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, this);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, this);
+ IPACM_EvtDispatcher::registr(IPA_PROCESS_CT_MESSAGE, this);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WLAN_UP, this);
+}
+
+void IPACM_ConntrackListener::event_callback(ipa_cm_event_id evt,
+ void *data)
+{
+ ipacm_ct_evt_data *evt_data = NULL;
+ uint32_t *pub_addr = NULL;
+
+ if(data == NULL)
+ {
+ IPACMERR("Invalid Data\n");
+ return;
+ }
+
+ switch(evt)
+ {
+ case IPA_PROCESS_CT_MESSAGE:
+ IPACMDBG("Received IPA_PROCESS_CT_MESSAGE event\n");
+ evt_data = (ipacm_ct_evt_data *)data;
+ ProcessCTMessage(evt_data);
+ break;
+
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+ TriggerWANUp(data);
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+ pub_addr = (uint32_t *)data;
+ TriggerWANDown(*pub_addr);
+ break;
+
+ /* if wlan or lan comes up after wan interface, modify
+ tcp/udp filters to ignore local wlan or lan connections */
+ case IPA_HANDLE_WLAN_UP:
+ case IPA_HANDLE_LAN_UP:
+ IPACMDBG("Received event: %d\n", evt);
+ if(isWanUp == true)
+ {
+ IPACM_ConntrackClient::UpdateUDPFilters(data);
+ IPACM_ConntrackClient::UpdateTCPFilters(data);
+ }
+ break;
+
+ default:
+ IPACMDBG("Ignore cmd %d\n", evt);
+ break;
+ }
+}
+
+void IPACM_ConntrackListener::TriggerWANUp(void *in_param)
+{
+ ipacm_event_iface_up *wanup_data = (ipacm_event_iface_up *)in_param;
+
+ IPACMDBG("Recevied below informatoin during wanup:\n");
+ IPACMDBG("if_name:%s, ipv4_address:0x%x\n",
+ wanup_data->ifname, wanup_data->ipv4_addr);
+
+ isWanUp = true;
+ wan_ipaddr = wanup_data->ipv4_addr;
+ IPACM_ConntrackClient::iptodot("public ip address", wanup_data->ipv4_addr);
+
+ memcpy(wan_ifname, wanup_data->ifname, sizeof(wan_ifname));
+ NatApp::GetInstance()->AddTable(wanup_data->ipv4_addr);
+
+ IPACMDBG("creating nat threads\n");
+ CreateNatThreads();
+}
+
+int IPACM_ConntrackListener::CreateNatThreads(void)
+{
+ int ret;
+ pthread_t tcp_thread = 0, udp_thread = 0, udpcto_thread = 0;
+
+ if(isCTReg == false)
+ {
+
+ if(!tcp_thread)
+ {
+ ret = pthread_create(&tcp_thread, NULL, IPACM_ConntrackClient::TCPRegisterWithConnTrack, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create TCP conntrack event listner thread\n");
+ return -1;
+ }
+
+ IPACMDBG("created TCP conntrack event listner thread\n");
+ }
+
+ if(!udp_thread)
+ {
+ ret = pthread_create(&udp_thread, NULL, IPACM_ConntrackClient::UDPRegisterWithConnTrack, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create UDP conntrack event listner thread\n");
+ goto error;
+ }
+
+ IPACMDBG("created UDP conntrack event listner thread\n");
+ }
+
+ if(!udpcto_thread)
+ {
+ ret = pthread_create(&udpcto_thread, NULL, IPACM_ConntrackClient::UDPConnTimeoutUpdate, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create udp conn timeout thread\n");
+ goto error;
+ }
+
+ IPACMDBG("created upd conn timeout thread\n");
+ }
+
+ isCTReg = true;
+ }
+
+ //pthread_join(tcp_thread, NULL);
+ //pthread_join(udp_thread, NULL);
+ //pthread_join(udpcto_thread, NULL);
+
+ return 0;
+
+error:
+ if(tcp_thread)
+ {
+ pthread_cancel(tcp_thread);
+ }
+
+ if(udp_thread)
+ {
+ pthread_cancel(tcp_thread);
+ }
+
+ if(udpcto_thread)
+ {
+ pthread_cancel(udpcto_thread);
+ }
+
+ return -1;
+}
+
+void IPACM_ConntrackListener::TriggerWANDown(uint32_t wan_addr)
+{
+ IPACMDBG("Deleting ipv4 nat table with ");
+ IPACM_ConntrackClient::iptodot("public ip address", wan_addr);
+ isWanUp = false;
+
+ NatApp::GetInstance()->DeleteTable(wan_addr);
+}
+
+
+void ParseCTMessage(struct nf_conntrack *ct)
+{
+ uint32_t status;
+ IPACMDBG("Printing conntrack parameters\n");
+
+ IPACM_ConntrackClient::iptodot("ATTR_IPV4_SRC = ATTR_ORIG_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC));
+ IPACM_ConntrackClient::iptodot("ATTR_IPV4_DST = ATTR_ORIG_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST));
+ IPACMDBG("ATTR_PORT_SRC = ATTR_ORIG_PORT_SRC: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC));
+ IPACMDBG("ATTR_PORT_DST = ATTR_ORIG_PORT_DST: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST));
+
+ IPACM_ConntrackClient::iptodot("ATTR_REPL_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC));
+ IPACM_ConntrackClient::iptodot("ATTR_REPL_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST));
+ IPACMDBG("ATTR_REPL_PORT_SRC: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC));
+ IPACMDBG("ATTR_REPL_PORT_DST: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST));
+
+ IPACM_ConntrackClient::iptodot("ATTR_SNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_SNAT_IPV4));
+ IPACM_ConntrackClient::iptodot("ATTR_DNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_DNAT_IPV4));
+ IPACMDBG("ATTR_SNAT_PORT: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_SNAT_PORT));
+ IPACMDBG("ATTR_DNAT_PORT: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_DNAT_PORT));
+
+ IPACMDBG("ATTR_MARK: 0x%x\n", nfct_get_attr_u32(ct, ATTR_MARK));
+ IPACMDBG("ATTR_USE: 0x:%x\n", nfct_get_attr_u32(ct, ATTR_USE));
+ IPACMDBG("ATTR_ID: 0x:%x\n", nfct_get_attr_u32(ct, ATTR_ID));
+
+ status = nfct_get_attr_u32(ct, ATTR_STATUS);
+ IPACMDBG("ATTR_STATUS: 0x:%x\n", status);
+
+ if(IPS_SRC_NAT & status)
+ {
+ IPACMDBG("IPS_SRC_NAT set\n");
+ }
+
+ if(IPS_DST_NAT & status)
+ {
+ IPACMDBG("IPS_SRC_NAT set\n");
+ }
+
+ if(IPS_SRC_NAT_DONE & status)
+ {
+ IPACMDBG("IPS_SRC_NAT_DONE set\n");
+ }
+
+ if(IPS_DST_NAT_DONE & status)
+ {
+ IPACMDBG(" IPS_DST_NAT_DONE set\n");
+ }
+
+ IPACMDBG("\n");
+ return;
+}
+
+void IPACM_ConntrackListener::ProcessCTMessage(void *param)
+{
+ ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
+ u_int8_t l4proto = 0;
+
+#ifdef IPACM_DEBUG
+ char buf[1024];
+
+ /* Process message and generate ioctl call to kernel thread */
+ nfct_snprintf(buf, sizeof(buf), evt_data->ct,
+ evt_data->type, NFCT_O_PLAIN, NFCT_OF_TIME);
+ IPACMDBG("%s\n", buf);
+ IPACMDBG("\n");
+
+ ParseCTMessage(evt_data->ct);
+#endif
+
+ l4proto = nfct_get_attr_u8(evt_data->ct, ATTR_ORIG_L4PROTO);
+ if(IPPROTO_UDP != l4proto && IPPROTO_TCP != l4proto)
+ {
+ IPACMDBG("Received unexpected protocl %d conntrack message\n", l4proto);
+ }
+ else
+ {
+ ProcessTCPorUDPMsg(evt_data->ct, evt_data->type, l4proto);
+ }
+
+ /* Cleanup item that was allocated during the original CT callback */
+ nfct_destroy(evt_data->ct);
+ return;
+}
+
+
+/* conntrack send in host order and ipa expects in host order */
+void IPACM_ConntrackListener::ProcessTCPorUDPMsg(
+ struct nf_conntrack *ct,
+ enum nf_conntrack_msg_type type,
+ u_int8_t l4proto)
+{
+ nat_table_entry rule;
+ u_int8_t tcp_state;
+ uint32_t status = 0;
+
+ status = nfct_get_attr_u32(ct, ATTR_STATUS);
+
+ if(IPS_DST_NAT & status)
+ {
+ IPACMDBG("Destination nat flag set\n");
+ rule.dst_nat = true;
+
+ IPACMDBG("Parse reply tuple\n");
+ rule.target_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+ rule.target_ip = ntohl(rule.target_ip);
+
+ /* Retriev target/dst port */
+ rule.target_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
+ rule.target_port = ntohs(rule.target_port);
+ if(0 == rule.target_port)
+ {
+ IPACMDBG("unable to retrieve target port\n");
+ }
+
+ rule.public_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+ rule.public_port = ntohs(rule.public_port);
+
+ /* Retriev src/private ip address */
+ rule.private_ip = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC);
+ rule.private_ip = ntohl(rule.private_ip);
+ if(0 == rule.private_ip)
+ {
+ IPACMDBG("unable to retrieve private ip address\n");
+ }
+
+ /* Retriev src/private port */
+ rule.private_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
+ rule.private_port = ntohs(rule.private_port);
+ if(0 == rule.private_port)
+ {
+ IPACMDBG("unable to retrieve private port\n");
+ }
+ }
+ else
+ {
+ IPACMDBG("destination nat flag reset\n");
+ rule.dst_nat = false;
+
+ /* Retriev target/dst ip address */
+ IPACMDBG("Parse source tuple\n");
+ rule.target_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST);
+ rule.target_ip = ntohl(rule.target_ip);
+ if(0 == rule.target_ip)
+ {
+ IPACMDBG("unable to retrieve target ip address\n");
+ }
+ /* Retriev target/dst port */
+ rule.target_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+ rule.target_port = ntohs(rule.target_port);
+ if(0 == rule.target_port)
+ {
+ IPACMDBG("unable to retrieve target port\n");
+ }
+
+ /* Retriev public port */
+ rule.public_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST);
+ rule.public_port = ntohs(rule.public_port);
+ if(0 == rule.public_port)
+ {
+ IPACMDBG("unable to retrieve public port\n");
+ }
+
+ /* Retriev src/private ip address */
+ rule.private_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+ rule.private_ip = ntohl(rule.private_ip);
+ if(0 == rule.private_ip)
+ {
+ IPACMDBG("unable to retrieve private ip address\n");
+ }
+
+ /* Retriev src/private port */
+ rule.private_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
+ rule.private_port = ntohs(rule.private_port);
+ if(0 == rule.private_port)
+ {
+ IPACMDBG("unable to retrieve private port\n");
+ }
+ }
+ /* Retrieve Protocol */
+ rule.protocol = nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO);
+
+
+ IPACMDBG("Nat Entry with below information will be added\n");
+ IPACM_ConntrackClient::iptodot("target ip or dst ip", rule.target_ip);
+ IPACMDBG("target port or dst port: 0x%x Decimal:%d\n", rule.target_port, rule.target_port);
+ IPACM_ConntrackClient::iptodot("private ip or src ip", rule.private_ip);
+ IPACMDBG("private port or src port: 0x%x, Decimal:%d\n", rule.private_port, rule.private_port);
+ IPACMDBG("public port or reply dst port: 0x%x, Decimal:%d\n", rule.public_port, rule.public_port);
+ IPACMDBG("Protocol: %d, destination nat flag: %d\n", rule.protocol, rule.dst_nat);
+
+ if(IPPROTO_TCP == rule.protocol)
+ {
+ tcp_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+ if(TCP_CONNTRACK_ESTABLISHED == tcp_state)
+ {
+ IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED(%d)\n", tcp_state);
+ NatApp::GetInstance()->AddEntry(&rule);
+ }
+ else if(TCP_CONNTRACK_FIN_WAIT == tcp_state)
+ {
+ IPACMDBG("TCP state TCP_CONNTRACK_FIN_WAIT(%d)\n", tcp_state);
+ NatApp::GetInstance()->DeleteEntry(&rule);
+ }
+ else
+ {
+ IPACMDBG("Ignore tcp state: %d and type: %d\n", tcp_state, type);
+ }
+
+ }
+ else if(IPPROTO_UDP == rule.protocol)
+ {
+ if(NFCT_T_NEW == type)
+ {
+ IPACMDBG("New UDP connection at time %ld\n", time(NULL));
+ NatApp::GetInstance()->AddEntry(&rule);
+ }
+ else if(NFCT_T_DESTROY == type)
+ {
+ IPACMDBG("UDP connection close at time %ld\n", time(NULL));
+ NatApp::GetInstance()->DeleteEntry(&rule);
+ }
+ }
+ else
+ {
+ IPACMDBG("Ignore protocol: %d and type: %d\n", rule.protocol, type);
+ }
+
+ return;
+}
+
+
+
+
+
+
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
new file mode 100644
index 0000000..63b158c
--- /dev/null
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -0,0 +1,504 @@
+/*
+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 "IPACM_Conntrack_NATApp.h"
+#include "IPACM_ConntrackClient.h"
+
+#define UDP_TIMEOUT_VALUE 30
+
+/* 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;
+}
+
+int NatApp::Init(void)
+{
+ IPACM_Config *pConfig;
+
+ pConfig = IPACM_Config::GetInstance();
+ if(pConfig == NULL)
+ {
+ IPACMERR("Unable to get Config instance\n");
+ return -1;
+ }
+
+ max_entries = pConfig->GetNatMaxEntries();
+
+ cache = (nat_table_entry *)malloc(sizeof(nat_table_entry) * max_entries);
+ if(cache == NULL)
+ {
+ IPACMERR("Unable to allocate memory for cache\n");
+ goto fail;
+ }
+ memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+
+ nALGPort = pConfig->GetAlgPortCnt();
+ 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;
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ 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;
+ }
+
+ pub_ip_addr = pub_ip;
+ return 0;
+}
+
+void NatApp::Reset()
+{
+ memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+
+ nat_table_hdl = 0;
+ pub_ip_addr = 0;
+ curCnt = 0;
+}
+
+int NatApp::DeleteTable(uint32_t pub_ip)
+{
+ int ret;
+ IPACMDBG("%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;
+ }
+
+ 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 < curCnt; 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)
+ {
+ IPACMDBG("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__);
+
+ CHK_TBL_HDL();
+
+#ifdef IPACM_DEBUG
+ IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
+ IPACM_ConntrackClient::iptodot("Target IP", rule->target_ip);
+ IPACMDBG("Private Port: %d\t Target Port: %d\t", rule->private_port, rule->target_port);
+ IPACMDBG("protocolcol: %d\n", rule->protocol);
+#endif
+
+ 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(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("%s() %d\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ memset(&cache[cnt], 0, sizeof(cache[cnt]));
+ curCnt--;
+ }
+ }
+
+ 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();
+
+ if(isAlgPort(rule->protocol, rule->private_port) ||
+ isAlgPort(rule->protocol, rule->target_port))
+ {
+ IPACMERR("connection using ALG Port. Dont insert into nat table\n");
+ return -1;
+ }
+
+ if(isPwrSaveIf(rule->private_ip) ||
+ isPwrSaveIf(rule->target_ip))
+ {
+ IPACMERR("Device is Power Save mode: Dont insert into nat table\n");
+ return -1;
+ }
+
+ 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(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].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;
+ }
+
+
+#ifdef IPACM_DEBUG
+ IPACMDBG("Added below rule successfully\n");
+ IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
+ IPACM_ConntrackClient::iptodot("Target IP", rule->target_ip);
+ IPACMDBG("Private Port:%d \t Target Port: %d\t", rule->private_port, rule->target_port);
+ IPACMDBG("Public Port:%d\n", rule->public_port);
+ IPACMDBG("protocol: %d\n", rule->protocol);
+#endif
+
+ return 0;
+}
+
+void NatApp::UpdateCTUdpTs(nat_table_entry *rule, uint32_t new_ts)
+{
+ int ret;
+
+#ifdef IPACM_DEBUG
+ IPACM_ConntrackClient::iptodot("Private IP:", rule->private_ip);
+ IPACM_ConntrackClient::iptodot("Target IP:", rule->target_ip);
+ IPACMDBG("Private Port: %d, Target Port: %d\n", rule->private_port, rule->target_port);
+#endif
+
+ 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);
+ nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_UDP);
+ nfct_set_attr_u32(ct, ATTR_TIMEOUT, UDP_TIMEOUT_VALUE);
+
+ 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");
+ }
+
+ IPACM_ConntrackClient::iptodot("Source IP:", nfct_get_attr_u32(ct, ATTR_IPV4_SRC));
+ IPACM_ConntrackClient::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 udp connection with time: %d\n", UDP_TIMEOUT_VALUE);
+ ret = nfct_query(ct_hdl, NFCT_Q_UPDATE, ct);
+ if(ret == -1)
+ {
+ PERROR("unable to update time stamp");
+ }
+ else
+ {
+ rule->timestamp = new_ts;
+ IPACMDBG("Updated time stamp successfully\n");
+ }
+
+ return;
+}
+
+void NatApp::UpdateUDPTimeStamp()
+{
+ int cnt;
+ uint32_t ts;
+
+ for(cnt = 0; cnt < curCnt; cnt++)
+ {
+ ts = 0;
+ if(IPPROTO_UDP == cache[cnt].protocol)
+ {
+ 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(ts == cache[cnt].timestamp)
+ {
+ continue;
+ }
+
+ 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;
+
+ CHK_TBL_HDL();
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(PwrSaveIfs[cnt] == 0)
+ {
+ PwrSaveIfs[cnt] = client_lan_ip;
+ }
+ }
+
+ for(cnt = 0; cnt < curCnt; cnt++)
+ {
+ if(cache[cnt].private_ip == client_lan_ip)
+ {
+ 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--;
+ }
+ }
+
+ return 0;
+}
+
+int NatApp::ResetPwrSaveIf(uint32_t client_lan_ip)
+{
+ int cnt;
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(PwrSaveIfs[cnt] == client_lan_ip)
+ {
+ PwrSaveIfs[cnt] = 0;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+
diff --git a/ipacm/src/IPACM_EvtDispatcher.cpp b/ipacm/src/IPACM_EvtDispatcher.cpp
new file mode 100644
index 0000000..2d2909b
--- /dev/null
+++ b/ipacm/src/IPACM_EvtDispatcher.cpp
@@ -0,0 +1,199 @@
+/*
+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_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;
+
+int IPACM_EvtDispatcher::PostEvt
+(
+ ipacm_cmd_q_data *data
+)
+{
+ Message *item = NULL;
+ MessageQueue *MsgQueue = NULL;
+
+ MsgQueue = MessageQueue::getInstance();
+ 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;
+ }
+
+ IPACMDBG("Populating item to post to queue\n");
+ 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;
+
+ if(head == NULL)
+ {
+ IPACMDBG("Queue is empty\n");
+ }
+
+ while(tmp != NULL)
+ {
+ if(data->event == tmp->event)
+ {
+ tmp->obj->event_callback(data->event, data->evt_data);
+ }
+ tmp = tmp->next;
+ }
+
+ if(data->evt_data != NULL)
+ {
+ 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;
+}
diff --git a/ipacm/src/IPACM_Filtering.cpp b/ipacm/src/IPACM_Filtering.cpp
new file mode 100644
index 0000000..4241549
--- /dev/null
+++ b/ipacm/src/IPACM_Filtering.cpp
@@ -0,0 +1,223 @@
+/*
+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_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>
+
+const char *IPACM_Filtering::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Filtering::IPACM_Filtering()
+{
+ fd = open(DEVICE_NAME, O_RDWR);
+ if (0 == fd)
+ {
+ 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::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;
+
+ len = (sizeof(struct ipa_ioc_del_flt_rule)) + (num_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;
+ }
+
+ memset(flt_rule, 0, len);
+ flt_rule->commit = 1;
+ flt_rule->num_hdls = num_rules;
+ flt_rule->ip = ip;
+
+ for (cnt = 0; cnt < flt_rule->num_hdls; cnt++)
+ {
+
+ if (flt_rule_hdls[cnt] == 0)
+ {
+ IPACMERR("invalid filter handle passed, ignoring it: %d\n", cnt)
+ res = false;
+ goto fail;
+ }
+
+ flt_rule->hdl[cnt].status = -1;
+ flt_rule->hdl[cnt].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;
+ }
+
+ for (cnt = 0; cnt < flt_rule->num_hdls; cnt++)
+ {
+ if (flt_rule->hdl[cnt].status != 0)
+ {
+ IPACMERR("Filter rule hdl 0x%x deletion failed with error:%d\n",
+ flt_rule->hdl[cnt].hdl, flt_rule->hdl[cnt].status);
+ res = false;
+ }
+ }
+
+fail:
+ free(flt_rule);
+
+ return res;
+}
+
diff --git a/ipacm/src/IPACM_Header.cpp b/ipacm/src/IPACM_Header.cpp
new file mode 100644
index 0000000..0ebb83d
--- /dev/null
+++ b/ipacm/src/IPACM_Header.cpp
@@ -0,0 +1,200 @@
+/*
+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)
+ {
+ IPACMDBG("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))
+ {
+ PERROR("Header deletion failed!\n");
+ res = false;
+ goto fail;
+ }
+
+ IPACMDBG("Deleted Header hdl:(%x) successfully\n", hd_rule_entry->hdl);
+
+fail:
+ free(pHeaderDescriptor);
+
+ return res;
+
+}
+
diff --git a/ipacm/src/IPACM_Iface.cpp b/ipacm/src/IPACM_Iface.cpp
new file mode 100644
index 0000000..cc6ce13
--- /dev/null
+++ b/ipacm/src/IPACM_Iface.cpp
@@ -0,0 +1,598 @@
+/*
+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 <ifaddrs.h>
+
+#include <IPACM_Netlink.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Wlan.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 = 0;
+ softwarerouting_act = false;
+ ipa_if_num = iface_index;
+
+ 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));
+
+ query_iface_property();
+ IPACMDBG(" 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");
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->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;
+ 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))
+ {
+ PERROR("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;
+ }
+
+ 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))
+ {
+ PERROR("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;
+ }
+
+ 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;
+ }
+ 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))
+ {
+ PERROR("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;
+ }
+
+ 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;
+ }
+
+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;
+
+ IPACMDBG("ip-type: %d\n", ip_type);
+
+ if (ip_type == IPA_IP_MAX)
+ {
+ /* ipv4 case */
+ if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[0],
+ IPA_IP_v4, 1) == false)
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ /* ipv6 case */
+ if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[1],
+ IPA_IP_v6, 1) == false)
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ softwarerouting_act = false;
+ }
+ 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)
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ softwarerouting_act = false;
+ }
+
+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 = -1;
+ int i = 0;
+ struct ifreq ifr;
+
+
+ /* 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("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("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("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 the IPA endpoint property */
+int IPACM_Iface::query_iface_property(void)
+{
+ int res = IPACM_SUCCESS, fd = 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));
+
+ IPACMDBG("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;
+ }
+
+ 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));
+
+ 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;
+ }
+
+ 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));
+
+ 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)
+ {
+ IPACMDBG("Rx property attribute mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+ for(uint32_t cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ IPACMDBG("Tx property:%d attribute mask:0x%x, ip-type: %d\n",
+ cnt, tx_prop->tx[0].attrib.attrib_mask,tx_prop->tx[0].ip);
+ }
+ }
+
+ 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;
+
+ /* 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(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+ return res;
+ }
+
+ if (ip_type == IPA_IP_v6)
+ {
+ ip_type = IPA_IP_MAX;
+ }
+ else
+ {
+ ip_type = IPA_IP_v4;
+ }
+
+ IPACMDBG(" 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(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+ return res;
+ }
+
+ if (ip_type == IPA_IP_v4)
+ {
+ ip_type = IPA_IP_MAX;
+ }
+ else
+ {
+ ip_type = IPA_IP_v6;
+ }
+
+ IPACMDBG(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+ }
+
+
+ /* 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)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = 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.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ IPACMDBG("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;
+ 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;
+ memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ /* 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("Default v4 filter Rule %d HDL:0x%x\n", i, dft_v4fl_rule_hdl[i]);
+ }
+ else
+ {
+ IPACMDBG("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)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
+
+ /* Configuring Fragment Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.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;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ /* 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("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;
+}
diff --git a/ipacm/src/IPACM_IfaceManager.cpp b/ipacm/src/IPACM_IfaceManager.cpp
new file mode 100644
index 0000000..747cbfe
--- /dev/null
+++ b/ipacm/src/IPACM_IfaceManager.cpp
@@ -0,0 +1,242 @@
+/*
+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_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_LINK_UP_EVENT, this); // skylar fix register name, class name
+ return; //skylar no interface_id
+}
+
+void IPACM_IfaceManager::event_callback(ipa_cm_event_id event, void *param) //skylar rename:event_callback
+{
+ ipacm_event_data_fid *evt_data = (ipacm_event_data_fid *)param;
+ IPACMDBG("\n");
+ switch(event)
+ {
+
+ case IPA_LINK_UP_EVENT:
+ IPACMDBG("link up %d: \n", evt_data->if_index);
+ create_iface_instance(evt_data->if_index);
+ break;
+
+ default:
+ break;
+ }
+ return;
+}
+
+int IPACM_IfaceManager::create_iface_instance(int if_index)
+{
+ int ipa_interface_index;
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(if_index);
+
+ /* 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("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);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, lan);
+ IPACMDBG("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", lan->dev_name, lan->ipa_if_num);
+ registr(ipa_interface_index, lan);
+ }
+ break;
+
+ case WLAN_IF:
+ {
+ IPACMDBG("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_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);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, wl);
+ IPACMDBG("ipa_WLAN (%s):ipa_index (%d) instance open/registr ok\n", wl->dev_name, wl->ipa_if_num);
+ registr(ipa_interface_index, wl);
+ }
+ break;
+
+ case WAN_IF:
+ {
+ IPACMDBG("Creating Wan interface\n");
+ IPACM_Wan *w = new IPACM_Wan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, w);
+ 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_LINK_DOWN_EVENT, w);
+ IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", w->dev_name, w->ipa_if_num);
+ registr(ipa_interface_index, w);
+ }
+ break;
+
+ default:
+ IPACMERR("Unhandled interface received\n");
+ 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("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("No existed iface-instance name: %s,\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+
+ return IPA_INSTANCE_NOT_FOUND;
+}
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
new file mode 100644
index 0000000..8b47985
--- /dev/null
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -0,0 +1,902 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials provided
+with the distribution.
+
+* Neither the name of The Linux Foundation nor the names of its
+contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Lan.cpp
+
+ @brief
+ This file implements the LAN iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+#include <IPACM_Netlink.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_IfaceManager.h>
+
+IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index)
+{
+ num_uni_rt = 0;
+ num_dft_rt = 0;
+
+ rt_rule_len = sizeof(struct ipa_lan_rt_rule) + (iface_query->num_tx_props * sizeof(uint32_t));
+ route_rule = (struct ipa_lan_rt_rule *)calloc(IPA_MAX_NUM_UNICAST_ROUTE_RULES, rt_rule_len);
+ if (route_rule == NULL)
+ {
+ IPACMERR("unable to allocate memory\n");
+ return;
+ }
+
+ IPACMDBG(" IPACM->IPACM_Lan(%d) constructor: Tx:%d Rx:%d\n", ipa_if_num,
+ iface_query->num_tx_props, iface_query->num_rx_props);
+
+ return;
+}
+
+IPACM_Lan::~IPACM_Lan()
+{
+ IPACM_EvtDispatcher::deregistr(this);
+ IPACM_IfaceManager::deregistr(this);
+ return;
+}
+
+
+/* LAN-iface's callback function */
+void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param)
+{
+ int ipa_interface_index;
+
+ switch (event)
+ {
+ case IPA_LINK_DOWN_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ IPACMDBG("ipa_LAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ delete this;
+ return;
+ }
+ }
+ break;
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ADDR_ADD_EVENT\n");
+
+ if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+ {
+ handle_addr_evt(data);
+ handle_private_subnet(data->iptype);
+ if (IPACM_Wan::isWanUP() && (data->iptype == IPA_IP_v4))
+ {
+ handle_wan_up();
+ }
+
+ /* Post event to NAT */
+ if (data->iptype == IPA_IP_v4)
+ {
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_iface_up *info;
+
+ info = (ipacm_event_iface_up *)
+ malloc(sizeof(ipacm_event_iface_up));
+ if (info == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+
+ memcpy(info->ifname, dev_name, IF_NAME_LEN);
+ info->ipv4_addr = data->ipv4_addr;
+ info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+ evt_data.event = IPA_HANDLE_LAN_UP;
+ evt_data.evt_data = (void *)info;
+
+ /* Insert IPA_HANDLE_LAN_UP to command queue */
+ IPACMDBG("posting IPA_HANDLE_LAN_UP for IPv4 with below information\n");
+ IPACMDBG("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+ info->ipv4_addr, info->addr_mask);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ }
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+ handle_wan_up();
+ break;
+
+ case IPA_ROUTE_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ /* unicast routing rule add */
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ROUTE_ADD_EVENT\n");
+ handle_route_add_evt(data);
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+ handle_wan_down();
+ break;
+
+ case IPA_ROUTE_DEL_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ /* unicast routing rule del */
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ROUTE_DEL_EVENT\n");
+ handle_route_del_evt(data);
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+ ipacm_event_data_addr *data_addr;
+ 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");
+ return;
+ }
+
+ data_addr->if_index = data->if_index;
+ data_addr->iptype = data->iptype;
+ if (data->iptype == IPA_IP_v4)
+ {
+ data_addr->ipv4_addr = data->ipv4_addr;
+ data_addr->ipv4_addr_mask = 0xFFFFFFFF;
+ }
+ else
+ {
+ memcpy(data_addr->ipv6_addr,
+ data->ipv6_addr,
+ sizeof(data_addr->ipv6_addr));
+ data_addr->ipv6_addr_mask[0] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[1] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[2] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[3] = 0xFFFFFFFF;
+ }
+ handle_route_add_evt(data_addr);
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT\n");
+ ipacm_event_data_addr *data_addr;
+ 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");
+ return;
+ }
+
+ data_addr->if_index = data->if_index;
+ data_addr->iptype = data->iptype;
+ if (data->iptype == IPA_IP_v4)
+ {
+ data_addr->ipv4_addr = data->ipv4_addr;
+ data_addr->ipv4_addr_mask = 0xFFFFFFFF;
+ }
+ else
+ {
+ memcpy(data_addr->ipv6_addr,
+ data->ipv6_addr,
+ sizeof(data_addr->ipv6_addr));
+ data_addr->ipv6_addr_mask[0] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[1] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[2] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[3] = 0xFFFFFFFF;
+ }
+ handle_route_del_evt(data_addr);
+ }
+ }
+ break;
+
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+ /* handle software routing enable event*/
+ handle_software_routing_enable();
+ break;
+
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+ /* handle software routing disable event*/
+ handle_software_routing_disable();
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+/* handle unicast routing rule add event */
+int IPACM_Lan::handle_route_add_evt(ipacm_event_data_addr *data)
+{
+ /* add unicate route for LAN */
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ struct ipa_ioc_get_hdr sRetHeader;
+ uint32_t tx_index;
+
+ IPACMDBG("LAN callback: unicast IPA_ROUTE_ADD_EVENT\n");
+
+ if (num_uni_rt < IPA_MAX_NUM_UNICAST_ROUTE_RULES)
+ {
+ /* unicast RT rule add start */
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ 1 * sizeof(struct ipa_rt_rule_add));
+ if (!rt_rule)
+ {
+ IPACMERR("fail\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)1;
+ rt_rule->ip = data->iptype;
+
+ if (data->iptype == IPA_IP_v4) strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ else strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 1;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (tx_prop->tx[tx_index].hdr_name)
+ {
+ memset(&sRetHeader, 0, sizeof(sRetHeader));
+ strncpy(sRetHeader.name,
+ tx_prop->tx[tx_index].hdr_name,
+ sizeof(tx_prop->tx[tx_index].hdr_name));
+
+ if (false == m_header.GetHeaderHandle(&sRetHeader))
+ {
+ IPACMDBG(" ioctl failed\n");
+ }
+
+ rt_rule_entry->rule.hdr_hdl = sRetHeader.hdl;
+ }
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ if (data->iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = data->ipv4_addr_mask;
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = data->ipv6_addr_mask[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = data->ipv6_addr_mask[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = data->ipv6_addr_mask[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = data->ipv6_addr_mask[3];
+ }
+ IPACMDBG("m_routing = %p\n", &m_routing);
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+ get_rt_ruleptr(route_rule, num_uni_rt)->rt_rule_hdl[tx_index]
+ = rt_rule_entry->rt_rule_hdl;
+ }
+ memcpy(&get_rt_ruleptr(route_rule, num_uni_rt)->rule,
+ &rt_rule_entry->rule.attrib,
+ sizeof(get_rt_ruleptr(route_rule, num_uni_rt)->rule));
+
+ get_rt_ruleptr(route_rule, num_uni_rt)->ip = data->iptype;
+ free(rt_rule);
+ num_uni_rt++;
+ }
+ else
+ {
+ IPACMDBG("unicast rule oversize\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* handle unicast routing rule del event */
+int IPACM_Lan::handle_route_del_evt(ipacm_event_data_addr *data)
+{
+ int i;
+ uint32_t tx_index;
+
+ /* delete 1 unicast RT rule */
+ for (i = 0; i <= num_uni_rt; i++)
+ {
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ if ((data->ipv4_addr == get_rt_ruleptr(route_rule, i)->rule.u.v4.dst_addr) &&
+ (data->ipv4_addr_mask == get_rt_ruleptr(route_rule, i)->rule.u.v4.dst_addr_mask))
+ {
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+ IPA_IP_v4) == false)
+ {
+ IPACMDBG("Routing rule deletion failed!\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ /* remove that delted route rule entry*/
+ for (; i <= num_uni_rt; i++)
+ {
+ get_rt_ruleptr(route_rule, i)->rule = get_rt_ruleptr(route_rule, (i + 1))->rule;
+ get_rt_ruleptr(route_rule, i)->ip = get_rt_ruleptr(route_rule, (i + 1))->ip;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index] = get_rt_ruleptr(route_rule, (i + 1))->rt_rule_hdl[tx_index];
+ }
+ }
+
+ num_uni_rt -= 1;
+ return IPACM_SUCCESS;
+ }
+ }
+ else
+ {
+ if ((data->ipv6_addr[0] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[0]) &&
+ (data->ipv6_addr[1] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[1]) &&
+ (data->ipv6_addr[2] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[2]) &&
+ (data->ipv6_addr[3] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[3]) &&
+ (data->ipv6_addr_mask[0] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[0]) &&
+ (data->ipv6_addr_mask[1] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[1]) &&
+ (data->ipv6_addr_mask[2] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[2]) &&
+ (data->ipv6_addr_mask[3] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[3]))
+ {
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+ IPA_IP_v6) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ /* remove that delted route rule entry*/
+ for (; i <= num_uni_rt; i++)
+ {
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index] = get_rt_ruleptr(route_rule, (i + 1))->rt_rule_hdl[tx_index];
+ }
+ get_rt_ruleptr(route_rule, i)->rule = get_rt_ruleptr(route_rule, (i + 1))->rule;
+ get_rt_ruleptr(route_rule, i)->ip = get_rt_ruleptr(route_rule, (i + 1))->ip;
+ }
+
+ num_uni_rt -= 1;
+ return IPACM_SUCCESS;
+ }
+ }
+ }
+
+ return IPACM_FAILURE;
+}
+
+
+
+
+/* configure filter rule for wan_up event*/
+int IPACM_Lan::handle_wan_up(void)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int len = 0;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("set WAN interface as default filter rule\n");
+
+ len = sizeof(struct ipa_ioc_add_flt_rule) + (1 * sizeof(struct ipa_flt_rule_add));
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (m_pFilteringTable == NULL)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ IPACMDBG("Retrieving routing hanle for table: %s\n",
+ IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
+ &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Routing hanle for table: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl);
+
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x0;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x0;
+
+ memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMDBG("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ perror("Lan: Unable to add filter rule");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[0].flt_rule_hdl,
+ m_pFilteringTable->rules[0].status);
+ }
+
+
+ /* copy filter hdls */
+ lan_wan_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+
+ return IPACM_SUCCESS;
+}
+
+
+/* delete filter rule for wan_down event*/
+int IPACM_Lan::handle_wan_down(void)
+{
+
+ if (m_filtering.DeleteFilteringHdls(&lan_wan_fl_rule_hdl[0],
+ IPA_IP_v4, 1) == false)
+ {
+ IPACMDBG("Error Adding RuleTable(1) to Filtering, aborting...\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* handle new_address event*/
+int IPACM_Lan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ struct ipa_flt_rule_add flt_rule_entry;
+ const int NUM_RULES = 1;
+ int res = IPACM_SUCCESS;
+
+ /* construct ipa_ioc_add_flt_rule with 1 rules */
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("set route/filter rule ip-type: %d \n", data->iptype);
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+ if (rt_rule == NULL)
+ {
+ IPACMERR("fail to allocate ipa_ioc_add_rt_rule \n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = data->iptype;
+
+ if (data->iptype == IPA_IP_v4) strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ else strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 1;
+ rt_rule_entry->rule.dst = IPA_CLIENT_A5_LAN_WAN_CONS; //go to A5
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ }
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ IPACMDBG("rt rule hdl=%x with ip-type: %d\n", rt_rule_entry->rt_rule_hdl, data->iptype);
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+
+ /* initial multicast/broadcast/fragment filter rule */
+ IPACM_Iface::init_fl_rule(data->iptype);
+ }
+ else
+ {
+ if (num_dft_rt == 0)
+ {
+ /* initial multicast/broadcast/fragment filter rule */
+ IPACM_Iface::init_fl_rule(data->iptype);
+
+ /* add default v6 filter rule */
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ IPACMDBG("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_v6);
+ free(m_pFilteringTable);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ free(m_pFilteringTable);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_v6fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+
+ dft_rt_rule_hdl[1 + num_dft_rt] = rt_rule_entry->rt_rule_hdl;
+ num_dft_rt++;
+ }
+
+ IPACMDBG("number of default route rules %d\n", num_dft_rt);
+
+fail:
+ free(rt_rule);
+
+ return res;
+}
+
+/* configure private subnet filter rules*/
+int IPACM_Lan::handle_private_subnet(ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i;
+
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("lan->handle_private_subnet(); set route/filter rule \n");
+
+ if (iptype == IPA_IP_v4)
+ {
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
+ );
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ IPACMERR("LAN m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+ memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACMDBG("Loop %d 5\n", i);
+ }
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMDBG("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ /* copy filter rule hdls */
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
+ {
+
+ private_fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ }
+ free(m_pFilteringTable);
+ }
+ return IPACM_SUCCESS;
+}
+
+
+
+/*handle wlan iface down event*/
+int IPACM_Lan::handle_down_evt()
+{
+ int i;
+ uint32_t tx_index;
+ int res = IPACM_SUCCESS;
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ goto fail;
+ }
+
+ IPACMDBG("lan handle_down_evt\n ");
+
+ if (ip_type != IPA_IP_v6)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* delete default v6 routing rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ /* may have multiple ipv6 iface-RT rules*/
+ for (i = 0; i < num_dft_rt; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[1 + i], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+
+ /* free unicast routing rule */
+ for (i = 0; i < num_uni_rt; i++)
+ {
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+ get_rt_ruleptr(route_rule, i)->ip) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ }
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true)
+ {
+ IPACM_Iface::handle_software_routing_disable();
+ }
+
+
+ /* delete default filter rules */
+ if (ip_type != IPA_IP_v6)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+ IPA_IP_v4,
+ IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Adding Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ /* free private-subnet ipv4 filter rules */
+ if (m_filtering.DeleteFilteringHdls(
+ private_fl_rule_hdl,
+ IPA_IP_v4,
+ IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
+ {
+ IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+
+ if (ip_type != IPA_IP_v4)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+ IPA_IP_v6,
+ (IPV6_DEFAULT_FILTERTING_RULES + IPV6_DEFAULT_LAN_FILTERTING_RULES)) == false)
+ {
+ IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* delete wan filter rule */
+ if (IPACM_Wan::isWanUP())
+ {
+ handle_wan_down();
+ }
+
+fail:
+ free(tx_prop);
+ free(rx_prop);
+ free(iface_query);
+
+ return res;
+}
diff --git a/ipacm/src/IPACM_Log.cpp b/ipacm/src/IPACM_Log.cpp
new file mode 100644
index 0000000..3333358
--- /dev/null
+++ b/ipacm/src/IPACM_Log.cpp
@@ -0,0 +1,68 @@
+/*
+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>
+
+#define FILE_NAME "/usr/ipacm_log.txt"
+
+static FILE *fp = NULL;
+char log_buf[LOG_SIZE];
+
+void logmessage(char *msg)
+{
+ printf("%s\n", msg);
+#if 0
+ if(fp == NULL)
+ {
+ fp = fopen(FILE_NAME, "wb+");
+ if(fp == NULL)
+ {
+ printf("unable to open file\n");
+ return;
+ }
+ }
+
+ fprintf(fp, msg);
+ fflush(fp);
+#endif
+ return;
+}
+
+
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
new file mode 100644
index 0000000..6369e10
--- /dev/null
+++ b/ipacm/src/IPACM_Main.cpp
@@ -0,0 +1,424 @@
+/*
+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. 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
+
+*/
+/******************************************************************************
+
+ IP_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 "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"
+
+#define IPA_DRIVER "/dev/ipa"
+
+#define IPACM_DIR_NAME "/etc"
+#define IPACM_FILE_NAME "mobileap_firewall.xml"
+
+#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
+#define INOTIFY_BUF_LEN (INOTIFY_EVENT_SIZE + 2*sizeof(IPACM_FILE_NAME))
+
+#define IPA_DRIVER_WLAN_EVENT_SIZE (sizeof(struct ipa_wlan_msg))
+#define IPA_DRIVER_WLAN_META_MSG (sizeof(struct ipa_msg_meta))
+#define IPA_DRIVER_WLAN_BUF_LEN (IPA_DRIVER_WLAN_EVENT_SIZE + IPA_DRIVER_WLAN_META_MSG)
+
+//char *log_buf = (char *)malloc(LOG_SIZE);
+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("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;
+
+ inotify_fd = inotify_init();
+ if (inotify_fd < 0)
+ {
+ PERROR("inotify_init");
+ }
+
+ IPACMDBG("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);
+ struct inotify_event *event = (struct inotify_event *)buffer;
+
+ if (length < 0)
+ {
+ IPACMDBG("inotify read() error return length: %d and mask: 0x%x 0x%x\n", length, event->mask, mask);
+ return NULL;
+ }
+
+ if (event->len > 0)
+ {
+ if (event->mask & IN_MODIFY)
+ {
+ if (event->mask & IN_ISDIR)
+ {
+ IPACMDBG("The directory %s was 0x%x\n", event->name, event->mask);
+ }
+ else if (!strncmp(event->name, IPACM_FILE_NAME, event->len))
+ {
+ IPACMDBG("File \"%s\" was 0x%x\n", event->name, event->mask);
+ IPACMDBG("The interested file %s .\n", IPACM_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);
+ }
+ }
+ IPACMDBG("Received monitoring event %s.\n", event->name);
+ }
+ }
+
+ (void)inotify_rm_watch(inotify_fd, wd);
+ (void)close(inotify_fd);
+ return NULL;
+}
+
+
+/* start IPACM WLAN-driver notifier */
+void* ipa_driver_wlan_notifier(void *param)
+{
+ int length, fd;
+ char buffer[IPA_DRIVER_WLAN_BUF_LEN];
+ struct ipa_msg_meta *event_hdr = NULL;
+ struct ipa_wlan_msg *event = NULL;
+
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_mac *data;
+
+ fd = open(IPA_DRIVER, O_RDWR);
+ if (fd == 0)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DRIVER);
+ }
+
+ while (1)
+ {
+ IPACMDBG("Waiting for nofications from IPA driver \n");
+ memset(buffer, 0, sizeof(buffer));
+
+ length = read(fd, buffer, IPA_DRIVER_WLAN_BUF_LEN);
+ if (length < 0)
+ {
+ PERROR("didn't read IPA_driver correctly");
+ return NULL;
+ }
+
+ event_hdr = (struct ipa_msg_meta *)buffer;
+ IPACMDBG("Message type: %d\n", event_hdr->msg_type);
+ IPACMDBG("Event header length received: %d\n",event_hdr->msg_len);
+
+ if (event_hdr->msg_len > 0)
+ {
+ event = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ }
+
+ /* Insert WLAN_DRIVER_EVENT to command queue */
+ data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+ if (data == NULL)
+ {
+ PERROR("unable to allocate memory for event data\n");
+ return NULL;
+ }
+
+ switch (event_hdr->msg_type)
+ {
+
+ case SW_ROUTING_ENABLE:
+ IPACMDBG("Received SW_ROUTING_ENABLE\n");
+ evt_data.event = IPA_SW_ROUTING_ENABLE;
+ evt_data.evt_data = NULL;
+ break;
+
+ case SW_ROUTING_DISABLE:
+ IPACMDBG("Received SW_ROUTING_DISABLE\n");
+ evt_data.event = IPA_SW_ROUTING_DISABLE;
+ evt_data.evt_data = NULL;
+ break;
+
+ case WLAN_CLIENT_CONNECT:
+ IPACMDBG("Received WLAN_CLIENT_CONNECT\n");
+ IPACMDBG("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+ event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
+
+ evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT;
+ evt_data.evt_data = data;
+ ipa_get_if_index(event->name, &(data->if_index));
+ memcpy(data->mac_addr,
+ event->mac_addr,
+ sizeof(event->mac_addr));
+ break;
+
+ case WLAN_CLIENT_DISCONNECT:
+ IPACMDBG("Received WLAN_CLIENT_DISCONNECT\n");
+ IPACMDBG("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+ event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
+
+ memcpy(data->mac_addr,
+ event->mac_addr,
+ sizeof(event->mac_addr));
+ ipa_get_if_index(event->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("Received WLAN_CLIENT_POWER_SAVE_MODE\n");
+ IPACMDBG("Mac Address [0]:%2d [1]:%2d [2]:%2d [3]:%2d [4]:%2d [5]%2d\n",
+ event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+ event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
+
+ ipa_get_if_index(event->name, &(data->if_index));
+
+ evt_data.event = IPA_WLAN_CLIENT_POWER_SAVE_EVENT;
+ evt_data.evt_data = data;
+ memcpy(data->mac_addr,
+ event->mac_addr,
+ sizeof(event->mac_addr));
+
+ break;
+
+ case WLAN_CLIENT_NORMAL_MODE:
+ IPACMDBG("Received WLAN_CLIENT_NORMAL_MODE\n");
+ IPACMDBG("Mac Address [0]:%2d [1]:%2d [2]:%2d [3]:%2d [4]:%2d [5]%2d\n",
+ event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+ event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
+
+ memcpy(data->mac_addr,
+ event->mac_addr,
+ sizeof(event->mac_addr));
+ ipa_get_if_index(event->name, &(data->if_index));
+ evt_data.evt_data = data;
+ evt_data.event = IPA_WLAN_CLIENT_RECOVER_EVENT;
+ break;
+
+ default:
+ IPACMDBG("Invalid message\n");
+ free(data);
+ continue;
+
+ }
+
+ /* finish command queue */
+ if (evt_data.evt_data == NULL)
+ {
+ free(data);
+ }
+
+ IPACMDBG("Posting event:%d\n", evt_data.event);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ (void)close(fd);
+ return NULL;
+}
+
+
+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;
+
+ IPACM_Neighbor *neigh = new IPACM_Neighbor();
+ IPACM_IfaceManager *ifacemgr = new IPACM_IfaceManager();
+
+ IPACMDBG("Staring IPA main\n");
+ IPACMDBG("ipa_cmdq_successful\n");
+
+
+ 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("created command queue thread\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("created netlink thread\n");
+ }
+
+
+ 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("created firewall monitor thread\n");
+ }
+
+ if (IPACM_SUCCESS == ipa_driver_thread)
+ {
+ ret = pthread_create(&ipa_driver_thread, NULL, ipa_driver_wlan_notifier, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to create ipa_driver_wlan thread\n");
+ return ret;
+ }
+ IPACMDBG("created ipa_driver_wlan thread\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_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)strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
+ {
+ PERROR("call_ioctl_on_dev: ioctl failed:");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ *if_index = ifr.ifr_ifindex;
+ close(fd);
+ return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Neighbor.cpp b/ipacm/src/IPACM_Neighbor.cpp
new file mode 100644
index 0000000..327b681
--- /dev/null
+++ b/ipacm/src/IPACM_Neighbor.cpp
@@ -0,0 +1,252 @@
+/*
+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;
+ 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 = 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);
+
+ data = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ memcpy(data, param, sizeof(ipacm_event_data_all));
+
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+ /*No that interface existed in ipa list*/
+ if(ipa_interface_index==-1)
+ return;
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ /* 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;
+
+ memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG("Posted event %d with %s\n", evt_data.event,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+ }
+ else
+ {
+ if ((data->ipv6_addr[0]) || (data->ipv6_addr[1]) || (data->ipv6_addr[2]) || (data->ipv6_addr[3]))
+ {
+ /* check if iface is not bridge0*/
+ if (strcmp(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;
+ //evt_data.evt_data=data;
+ memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* ask for replaced iface name*/
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+ /*No that interface existed in ipa list*/
+ if(ipa_interface_index==-1)
+ return;
+
+ IPACMDBG("Posted event %d, with %s\n",
+ evt_data.event,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+ /* delete that entry*/
+ 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].v6_addr[0] = neighbor_client[i + 1].v6_addr[0];
+ neighbor_client[i].v6_addr[1] = neighbor_client[i + 1].v6_addr[1];
+ neighbor_client[i].v6_addr[2] = neighbor_client[i + 1].v6_addr[2];
+ neighbor_client[i].v6_addr[3] = neighbor_client[i + 1].v6_addr[3];
+ neighbor_client[i].iface_index = neighbor_client[i + 1].iface_index;
+ }
+ num_neighbor_client -= 1;
+ break;
+
+ };
+ }
+
+ /* cannot find neighbor client*/
+ if (i == num_neighbor_client_temp)
+ {
+ IPACMDBG("ipv6 with bridge0 with mac, not seen before\n");
+ 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].v6_addr[0] = data->ipv6_addr[0];
+ neighbor_client[num_neighbor_client_temp].v6_addr[1] = data->ipv6_addr[1];
+ neighbor_client[num_neighbor_client_temp].v6_addr[2] = data->ipv6_addr[2];
+ neighbor_client[num_neighbor_client_temp].v6_addr[3] = data->ipv6_addr[3];
+ IPACMDBG("Copy bridge0 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_temp);
+ num_neighbor_client++;
+ return;
+ }
+ else
+ {
+ IPACMERR("error: neighbor client oversize!");
+ return;
+ }
+ }
+ }
+ 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;
+
+ memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+ //evt_data.evt_data=data;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG("Posted event %d with %s\n",
+ evt_data.event,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+
+ }
+ }
+ else
+ {
+ /*no ipv6 in data 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->ipv6_addr[0] = neighbor_client[i].v6_addr[0];
+ data->ipv6_addr[1] = neighbor_client[i].v6_addr[1];
+ data->ipv6_addr[2] = neighbor_client[i].v6_addr[2];
+ data->ipv6_addr[3] = neighbor_client[i].v6_addr[3];
+
+ /* check if iface is not bridge0*/
+ if (strcmp(IPA_VIRTUAL_IFACE_NAME, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 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;
+ memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG("Posted event %d with %s\n",
+ evt_data.event,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+
+ /* delete that entry*/
+ for (; i <= num_neighbor_client_temp; i++)
+ {
+ memcpy(neighbor_client[i].mac_addr, neighbor_client[i + 1].mac_addr, sizeof(neighbor_client[i].mac_addr));
+ neighbor_client[i].v6_addr[0] = neighbor_client[i + 1].v6_addr[0];
+ neighbor_client[i].v6_addr[1] = neighbor_client[i + 1].v6_addr[1];
+ neighbor_client[i].v6_addr[2] = neighbor_client[i + 1].v6_addr[2];
+ neighbor_client[i].v6_addr[3] = neighbor_client[i + 1].v6_addr[3];
+ neighbor_client[i].iface_index = neighbor_client[i + 1].iface_index;
+ }
+ num_neighbor_client -= 1;
+ };
+ break;
+ };
+ }
+ /* not find client */
+ if (i == num_neighbor_client_temp)
+ {
+ IPACMDBG("ipv6 with bridge0 with mac, not seen before\n");
+ 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;
+ IPACMDBG("Copy wlan-iface 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);
+ num_neighbor_client++;
+ return;
+ }
+ else
+ {
+ IPACMDBG("error: neighbor client oversize!");
+ return;
+ }
+ };
+ }
+ }
+
+ return;
+}
+
diff --git a/ipacm/src/IPACM_Netlink.cpp b/ipacm/src/IPACM_Netlink.cpp
new file mode 100644
index 0000000..eea98ea
--- /dev/null
+++ b/ipacm/src/IPACM_Netlink.cpp
@@ -0,0 +1,1823 @@
+/*
+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_Netlink.cpp
+
+ @brief
+ This file implements the IPAM Netlink Socket Parer functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Netlink.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Log.h"
+
+char dev_pre_name[IF_NAME_LEN];
+struct sockaddr_storage dst_pre_addr;
+
+int ipa_get_if_name(char *if_name, int if_index);
+int find_mask(int ip_v4_last, int *mask_value);
+
+#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+
+/* Opens a netlink socket*/
+static int ipa_nl_open_socket
+(
+ ipa_nl_sk_info_t *sk_info,
+ int protocol,
+ unsigned int grps
+ )
+{
+ int *p_sk_fd;
+ struct sockaddr_nl *p_sk_addr_loc;
+
+ p_sk_fd = &(sk_info->sk_fd);
+ p_sk_addr_loc = &(sk_info->sk_addr_loc);
+
+ /* Open netlink socket for specified protocol */
+ if((*p_sk_fd = socket(AF_NETLINK, SOCK_RAW, protocol)) < 0)
+ {
+ IPACMERR("cannot open netlink socket\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Initialize socket addresses to null */
+ memset(p_sk_addr_loc, 0, sizeof(struct sockaddr_nl));
+
+ /* Populate local socket address using specified groups */
+ p_sk_addr_loc->nl_family = AF_NETLINK;
+ p_sk_addr_loc->nl_pid = getpid();
+ p_sk_addr_loc->nl_groups = grps;
+
+ /* Bind socket to the local address, i.e. specified groups. This ensures
+ that multicast messages for these groups are delivered over this
+ socket. */
+
+ if(bind(*p_sk_fd,
+ (struct sockaddr *)p_sk_addr_loc,
+ sizeof(struct sockaddr_nl)) < 0)
+ {
+ IPACMDBG("Socket bind failed\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Add fd to fdmap array and store read handler function ptr (up to MAX_NUM_OF_FD).*/
+static int ipa_nl_addfd_map
+(
+ ipa_nl_sk_fd_set_info_t *fd_set,
+ int fd,
+ ipa_sock_thrd_fd_read_f read_f
+ )
+{
+ if(fd_set->num_fd < MAX_NUM_OF_FD)
+ {
+ FD_SET(fd, &(fd_set->fdset));
+
+ /* Add fd to fdmap array and store read handler function ptr */
+ fd_set->sk_fds[fd_set->num_fd].sk_fd = fd;
+ fd_set->sk_fds[fd_set->num_fd].read_func = read_f;
+
+ /* Increment number of fds stored in fdmap */
+ fd_set->num_fd++;
+ if(fd_set->max_fd < fd)
+ {
+ fd_set->max_fd = fd;
+ }
+ }
+ else
+ {
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* start socket listener */
+static int ipa_nl_sock_listener_start
+(
+ ipa_nl_sk_fd_set_info_t *sk_fd_set
+ )
+{
+ int i, ret;
+
+ while(true)
+ {
+ if((ret = select(sk_fd_set->max_fd + 1, &(sk_fd_set->fdset), NULL, NULL, NULL)) < 0)
+ {
+ IPACMERR("ipa_nl select failed\n");
+ }
+ else
+ {
+ for(i = 0; i < sk_fd_set->num_fd; i++)
+ {
+
+ if(FD_ISSET(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset)))
+ {
+
+ if(sk_fd_set->sk_fds[i].read_func)
+ {
+ if(IPACM_SUCCESS != ((sk_fd_set->sk_fds[i].read_func)(sk_fd_set->sk_fds[i].sk_fd)))
+ {
+ IPACMERR("Error on read callback[%d] fd=%d\n",
+ i,
+ sk_fd_set->sk_fds[i].sk_fd);
+ }
+ }
+ else
+ {
+ IPACMDBG("No read function\n");
+ }
+ }
+
+ } /* end of for loop*/
+ } /* end of else */
+ } /* end of while */
+
+ return IPACM_SUCCESS;
+}
+
+/* allocate memory for ipa_nl__msg */
+static struct msghdr* ipa_nl_alloc_msg
+(
+ uint32_t msglen
+ )
+{
+ unsigned char *buf = NULL;
+ struct sockaddr_nl *nladdr = NULL;
+ struct iovec *iov = NULL;
+ struct msghdr *msgh = NULL;
+
+ if(IPA_NL_MSG_MAX_LEN < msglen)
+ {
+ IPACMERR("Netlink message exceeds maximum length\n");
+ return NULL;
+ }
+
+ msgh = (struct msghdr *)malloc(sizeof(struct msghdr));
+ if(msgh == NULL)
+ {
+ IPACMERR("Failed malloc for msghdr\n");
+ free(msgh);
+ return NULL;
+ }
+
+ nladdr = (struct sockaddr_nl *)malloc(sizeof(struct sockaddr_nl));
+ if(nladdr == NULL)
+ {
+ IPACMERR("Failed malloc for sockaddr\n");
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ iov = (struct iovec *)malloc(sizeof(struct iovec));
+ if(iov == NULL)
+ {
+ PERROR("Failed malloc for iovec");
+ free(iov);
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ buf = (unsigned char *)malloc(msglen);
+ if(buf == NULL)
+ {
+ IPACMERR("Failed malloc for mglen\n");
+ free(buf);
+ free(iov);
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ memset(nladdr, 0, sizeof(struct sockaddr_nl));
+ nladdr->nl_family = AF_NETLINK;
+
+ memset(msgh, 0x0, sizeof(struct msghdr));
+ msgh->msg_name = nladdr;
+ msgh->msg_namelen = sizeof(struct sockaddr_nl);
+ msgh->msg_iov = iov;
+ msgh->msg_iovlen = 1;
+
+ memset(iov, 0x0, sizeof(struct iovec));
+ iov->iov_base = buf;
+ iov->iov_len = msglen;
+
+ return msgh;
+}
+
+/* release IPA message */
+static void ipa_nl_release_msg
+(
+ struct msghdr *msgh
+ )
+{
+ unsigned char *buf = NULL;
+ struct sockaddr_nl *nladdr = NULL;
+ struct iovec *iov = NULL;
+
+ if(NULL == msgh)
+ {
+ return;
+ }
+
+ nladdr = (struct sockaddr_nl *)msgh->msg_name;
+ iov = msgh->msg_iov;
+ if(msgh->msg_iov)
+ {
+ buf = (unsigned char *)msgh->msg_iov->iov_base;
+ }
+
+ free(buf);
+ free(iov);
+ free(nladdr);
+ free(msgh);
+
+ return;
+}
+
+/* receive and process nl message */
+static int ipa_nl_recv
+(
+ int fd,
+ struct msghdr **msg_pptr,
+ unsigned int *msglen_ptr
+ )
+{
+ struct msghdr *msgh = NULL;
+ int rmsgl;
+
+ msgh = ipa_nl_alloc_msg(IPA_NL_MSG_MAX_LEN);
+ if(NULL == msgh)
+ {
+ IPACMERR("Failed to allocate NL message\n");
+ goto error;
+ }
+
+
+ /* Receive message over the socket */
+ rmsgl = recvmsg(fd, msgh, 0);
+
+ /* Verify that something was read */
+ if(rmsgl <= 0)
+ {
+ PERROR("NL recv error");
+ goto error;
+ }
+
+ /* Verify that NL address length in the received message is expected value */
+ if(sizeof(struct sockaddr_nl) != msgh->msg_namelen)
+ {
+ IPACMERR("rcvd msg with namelen != sizeof sockaddr_nl\n");
+ goto error;
+ }
+
+ /* Verify that message was not truncated. This should not occur */
+ if(msgh->msg_flags & MSG_TRUNC)
+ {
+ IPACMERR("Rcvd msg truncated!\n");
+ goto error;
+ }
+
+ *msg_pptr = msgh;
+ *msglen_ptr = rmsgl;
+
+ return IPACM_SUCCESS;
+
+/* An error occurred while receiving the message. Free all memory before
+ returning. */
+error:
+ ipa_nl_release_msg(msgh);
+ *msg_pptr = NULL;
+ *msglen_ptr = 0;
+
+ return IPACM_FAILURE;
+}
+
+/* decode the rtm netlink message */
+static int ipa_nl_decode_rtm_link
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_link_info_t *link_info
+)
+{
+ struct rtattr *rtah = NULL;
+ /* NL message header */
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+ /* Extract the header data */
+ link_info->metainfo = *(struct ifinfomsg *)NLMSG_DATA(nlh);
+ buflen -= sizeof(struct nlmsghdr);
+ rtah = IFA_RTA(NLMSG_DATA(nlh));
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel address message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_addr
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_addr_info_t *addr_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ addr_info->metainfo = *((struct ifaddrmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ /* Extract the available attributes */
+ addr_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+ rtah = IFA_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case IFA_ADDRESS:
+ addr_info->attr_info.prefix_addr.ss_family = addr_info->metainfo.ifa_family;
+ memcpy(&addr_info->attr_info.prefix_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(addr_info->attr_info.prefix_addr.__ss_padding));
+ addr_info->attr_info.param_mask |= IPA_NLA_PARAM_PREFIXADDR;
+ break;
+
+ default:
+ break;
+
+ }
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel neighbor message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_neigh
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_neigh_info_t *neigh_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ neigh_info->metainfo = *((struct ndmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ /* Extract the available attributes */
+ neigh_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+ rtah = NDA_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case NDA_DST:
+ neigh_info->attr_info.local_addr.ss_family = neigh_info->metainfo.ndm_family;
+ memcpy(&neigh_info->attr_info.local_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(neigh_info->attr_info.local_addr.__ss_padding));
+ break;
+
+ case NDA_LLADDR:
+ memcpy(neigh_info->attr_info.lladdr_hwaddr.sa_data,
+ RTA_DATA(rtah),
+ sizeof(neigh_info->attr_info.lladdr_hwaddr.sa_data));
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel route message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_route
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_route_info_t *route_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ route_info->metainfo = *((struct rtmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ route_info->attr_info.param_mask = IPA_RTA_PARAM_NONE;
+ rtah = RTM_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case RTA_DST:
+ if((route_info->metainfo.rtm_type == RTN_UNICAST) &&
+ (route_info->metainfo.rtm_protocol == RTPROT_BOOT) &&
+ (route_info->metainfo.rtm_scope == RT_SCOPE_LINK) &&
+ (route_info->metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ route_info->metainfo.rtm_type = RTN_BROADCAST;
+ memcpy(&route_info->attr_info.dst_addr.__ss_padding,
+ dst_pre_addr.__ss_padding,
+ sizeof(route_info->attr_info.dst_addr.__ss_padding));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_DST;
+ }
+ else
+ {
+ route_info->attr_info.dst_addr.ss_family = route_info->metainfo.rtm_family;
+ memcpy(&route_info->attr_info.dst_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.dst_addr.__ss_padding));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_DST;
+ }
+ break;
+
+ case RTA_SRC:
+ route_info->attr_info.src_addr.ss_family = route_info->metainfo.rtm_family;
+ memcpy(&route_info->attr_info.src_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.src_addr.__ss_padding));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_SRC;
+ break;
+
+ case RTA_GATEWAY:
+ route_info->attr_info.gateway_addr.ss_family = route_info->metainfo.rtm_family;
+ memcpy(&route_info->attr_info.gateway_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.gateway_addr.__ss_padding));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_GATEWAY;
+ break;
+
+ case RTA_IIF:
+ memcpy(&route_info->attr_info.iif_index,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.iif_index));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_IIF;
+ break;
+
+ case RTA_OIF:
+ memcpy(&route_info->attr_info.oif_index,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.oif_index));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_OIF;
+ break;
+
+ case RTA_PRIORITY:
+ memcpy(&route_info->attr_info.priority,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.priority));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_PRIORITY;
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* decode the ipa nl-message */
+static int ipa_nl_decode_nlmsg
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_msg_t *msg_ptr
+ )
+{
+ char dev_name[IF_NAME_LEN];
+ int ret_val, mask_value, mask_index, mask_value_v6;
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+ uint32_t if_ipv4_addr =0, if_ipipv4_addr_mask =0, temp =0;
+
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_all *data_all;
+ ipacm_event_data_fid *data_fid;
+ ipacm_event_data_addr *data_addr;
+
+
+ while(NLMSG_OK(nlh, buflen))
+ {
+ IPACMDBG("Received msg:%d from netlink\n", nlh->nlmsg_type)
+ switch(nlh->nlmsg_type)
+ {
+ case RTM_NEWLINK:
+ msg_ptr->type = nlh->nlmsg_type;
+ msg_ptr->link_event = true;
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+ {
+ IPACMERR("Failed to decode rtm link message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("Got RTM_NEWLINK with below values\n");
+ IPACMDBG("RTM_NEWLINK, ifi_change:%d\n", msg_ptr->nl_link_info.metainfo.ifi_change);
+ IPACMDBG("RTM_NEWLINK, ifi_flags:%d\n", msg_ptr->nl_link_info.metainfo.ifi_flags);
+ IPACMDBG("RTM_NEWLINK, ifi_index:%d\n", msg_ptr->nl_link_info.metainfo.ifi_index);
+ IPACMDBG("RTM_NEWLINK, family:%d\n", msg_ptr->nl_link_info.metainfo.ifi_family);
+
+ if(IFF_UP & msg_ptr->nl_link_info.metainfo.ifi_change)
+ {
+ IPACMDBG("\n GOT useful newlink event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+ if(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_UP)
+ {
+ IPACMDBG("Interface %s bring up with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* post link up to command queue */
+ evt_data.event = IPA_LINK_UP_EVENT;
+ IPACMDBG("Posting IPA_LINK_UP_EVENT with if index: %d\n",
+ data_fid->if_index);
+ }
+ else
+ {
+ IPACMDBG("Interface %s bring down with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* post link down to command queue */
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ IPACMDBG("Posting IPA_LINK_DOWN_EVENT with if index: %d\n",
+ data_fid->if_index);
+ }
+
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+ }
+ }
+ break;
+
+ case RTM_DELLINK:
+ IPACMDBG("\n GOT dellink event\n");
+ msg_ptr->type = nlh->nlmsg_type;
+ msg_ptr->link_event = true;
+ IPACMDBG("entering rtm decode\n");
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+ {
+ IPACMERR("Failed to decode rtm link message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("Interface %s bring down \n", dev_name);
+
+ /* post link down to command queue */
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ IPACMDBG("posting IPA_LINK_DOWN_EVENT with if idnex:%d\n",
+ data_fid->if_index);
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ break;
+
+ case RTM_NEWADDR:
+ IPACMDBG("\n GOT RTM_NEWADDR event\n");
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_addr(buffer, buflen, &(msg_ptr->nl_addr_info)))
+ {
+ IPACMERR("Failed to decode rtm addr message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_addr_info.metainfo.ifa_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("Interface %s \n", dev_name);
+
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_addr_info.attr_info.prefix_addr.ss_family)
+ {
+ data_addr->iptype = IPA_IP_v6;
+ IPACMDBG("IFA_ADDRESS:IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 48)));
+
+ memcpy(data_addr->ipv6_addr,
+ msg_ptr->nl_addr_info.attr_info.prefix_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+ }
+ else
+ {
+ data_addr->iptype = IPA_IP_v4;
+ IPACMDBG("IFA_ADDRESS:IPV4 %d.%d.%d.%d\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 24));
+
+ memcpy(&data_addr->ipv4_addr,
+ msg_ptr->nl_addr_info.attr_info.prefix_addr.__ss_padding,
+ sizeof(data_addr->ipv4_addr));
+ data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+ }
+
+ evt_data.event = IPA_ADDR_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_addr_info.metainfo.ifa_index;
+
+ IPACMDBG("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv4 addr:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ break;
+
+ case RTM_NEWROUTE:
+
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+ {
+ IPACMERR("Failed to decode rtm route message\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("In case RTM_NEWROUTE\n");
+ IPACMDBG("rtm_type: %d\n", msg_ptr->nl_route_info.metainfo.rtm_type);
+ IPACMDBG("ss_padding: %d\n", ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)));
+ IPACMDBG("rtm_type: %d\n", msg_ptr->nl_route_info.metainfo.rtm_type);
+ IPACMDBG("protocol: %d\n", msg_ptr->nl_route_info.metainfo.rtm_protocol);
+ IPACMDBG("rtm_scope: %d\n", msg_ptr->nl_route_info.metainfo.rtm_scope);
+ IPACMDBG("rtm_table: %d\n", msg_ptr->nl_route_info.metainfo.rtm_table);
+ IPACMDBG("rtm_family: %d\n", msg_ptr->nl_route_info.metainfo.rtm_family);
+ IPACMDBG("param_mask: 0x%x\n", msg_ptr->nl_route_info.attr_info.param_mask);
+
+ /* ipv4 interface route and its subnet mask */
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_BROADCAST) &&
+ ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)) != 0)
+ {
+ if(IPACM_SUCCESS !=
+ find_mask((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24), &mask_value))
+ {
+ IPACMERR("Failed to decode rtm_addroute message\n");
+ }
+ else
+ {
+ IPACMDBG("\n GOT useful RTM_NEWROUTE event\n");
+
+ /* take care of subnet mask */
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACMDBG("DST_ADDRESS:IPV4 %d.%d.%d.0\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16));
+ IPACMDBG("MASK:IPV4 255.255.255.%d\n", mask_value);
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name");
+ }
+ IPACMDBG("RTA_OIF, output Interface %s \n", dev_name);
+ memcpy(&dst_pre_addr.__ss_padding,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(dst_pre_addr.__ss_padding));
+ memcpy(&dev_pre_name,
+ dev_name,
+ sizeof(dev_pre_name));
+ IPACMDBG("save pre_DST_ADDRESS:IPV4 %d.%d.%d.%d %s\n",
+ (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 24), dev_pre_name);
+ }
+
+ 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");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("route add -net %d.%d.%d.0 netmask 255.255.255.%d dev %s metric %d \n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ mask_value,
+ dev_pre_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG("route add -net %d.%d.%d.0 netmask 255.255.255.%d dev %s \n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ mask_value,
+ dev_name);
+ }
+
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ if_ipv4_addr = (if_ipv4_addr << 8) >> 8;
+ temp = (-1) << 8;
+ temp = temp | mask_value;
+
+ /* insert to command queue */
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 address 0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+
+
+ /* take care of route add default route & uniroute */
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_scope == RT_SCOPE_UNIVERSE) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT RTM_NEWROUTE event\n");
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+
+ IPACMDBG("route add -host %d.%d.%d.%d gw %d.%d.%d.%d dev %s\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+ dev_name
+ );
+
+ /* insert to command queue */
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ temp = (-1);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+
+ if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+ {
+ /* insert 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");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("ip -6 route add default dev %s metric %d\n",
+ dev_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG("ip -6 route add default dev %s\n", dev_name);
+ }
+
+ memcpy(data_addr->ipv6_addr,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+
+ memcpy(data_addr->ipv6_addr_mask,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr_mask));
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ }
+ else
+ {
+ IPACMDBG("route add default gw %d.%d.%d.%d dev %s dstIP: %d.%d.%d.%d\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+ dev_name,
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)
+ );
+
+ /* insert 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");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ memcpy(&if_ipipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipipv4_addr_mask));
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 addr:0x%x and maxk: 0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+ }
+
+ /* ipv6 routing table */
+ if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT valid v6-RTM_NEWROUTE event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACMDBG("Route ADD IPV6 DST: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%d, metric %d, dev %s\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 48)),
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(data_addr->ipv6_addr,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+
+ mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+ for(mask_index = 0; mask_index < 4; mask_index++)
+ {
+ if(mask_value_v6 >= 32)
+ {
+ mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 -= 32;
+ }
+ else
+ {
+ mask_v6(mask_value_v6, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 = 0;
+ }
+ }
+
+ IPACMDBG("ADD IPV6 MASK %d: %08x:%08x:%08x:%08x \n",
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ data_addr->ipv6_addr_mask[0],
+ data_addr->ipv6_addr_mask[1],
+ data_addr->ipv6_addr_mask[2],
+ data_addr->ipv6_addr_mask[3]);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 addr\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_GATEWAY)
+ {
+ IPACMDBG("Route ADD ::/0 Next Hop: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, metric %d, dev %s\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 48)),
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert 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");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+ memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr_mask));
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+
+ }
+ break;
+
+ case RTM_DELROUTE:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+ {
+ IPACMDBG("Failed to decode rtm route message\n");
+ return IPACM_FAILURE;
+ }
+
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_BROADCAST) &&
+ ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)) != 0)
+ {
+ if(IPACM_SUCCESS != find_mask((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24), &mask_value))
+ {
+ IPACMERR("Failed to decode rtm_delroute message\n");
+ }
+ else
+ {
+ IPACMDBG("\n GOT useful RTM_DELROUTE event\n");
+
+ /* take care of subnet mask */
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACMDBG("DST_ADDRESS:IPV4 %d.%d.%d.0\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16));
+ IPACMDBG("MASK:IPV4 255.255.255.%d\n", mask_value);
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("RTA_OIF, output Interface %s \n", dev_name);
+ }
+ IPACMDBG("route del -net %d.%d.%d.0 netmask 255.255.255.%d dev %s \n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ mask_value,
+ dev_name);
+
+ /* post 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");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("Priority %d \n",
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else;
+
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ if_ipv4_addr = (if_ipv4_addr << 8) >> 8;
+ temp = (-1) << 8;
+ temp = temp | mask_value;
+ if_ipipv4_addr_mask = ntohl(temp);
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with ifindex:%d, ipv4 address 0x%x, mask:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+
+ /* take care of route delete of default route & uniroute */
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_scope == 0) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("route del -host %d.%d.%d.%d gw %d.%d.%d.%d dev %s\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+ dev_name
+ );
+
+ /* insert 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");
+ return IPACM_FAILURE;
+ }
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ temp = (-1);
+ if_ipipv4_addr_mask = ntohl(temp);
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+
+ /* insert 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");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+ {
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("ip -6 route del default dev %s metric %d\n",
+ dev_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG("ip -6 route del default dev %s\n", dev_name);
+ }
+ memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+ memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr_mask));
+ data_addr->iptype = IPA_IP_v6;
+ }
+ else
+ {
+ IPACMDBG("route del default gw %d.%d.%d.%d dev %s\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+ dev_name);
+
+ memcpy(&data_addr->ipv4_addr,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv4_addr));
+ data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+ memcpy(&data_addr->ipv4_addr_mask,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv4_addr_mask));
+ data_addr->ipv4_addr_mask = ntohl(data_addr->ipv4_addr_mask);
+
+ data_addr->iptype = IPA_IP_v4;
+ }
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+
+ IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with if index:%d\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+
+ /* ipv6 routing table */
+ if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT valid v6-RTM_DELROUTE event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name");
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACMDBG("DEL IPV6 DST: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%d, metric %d, dev %s\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 48)),
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert 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");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+
+ mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+ for(mask_index = 0; mask_index < 4; mask_index++)
+ {
+ IPACMDBG("%dst %d \n",
+ mask_index,
+ mask_value_v6);
+ if(mask_value_v6 >= 32)
+ {
+ mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 -= 32;
+ IPACMDBG("%dst: %08x \n",
+ mask_index,
+ data_addr->ipv6_addr_mask[mask_index]);
+ }
+ else
+ {
+ mask_v6(mask_value_v6, data_addr->ipv6_addr_mask);
+ mask_value_v6 = 0;
+ IPACMDBG("%dst: %08x \n",
+ mask_index,
+ data_addr->ipv6_addr_mask[mask_index]);
+ }
+ }
+
+ IPACMDBG("DEL IPV6 MASK 0st: %08x ",
+ data_addr->ipv6_addr_mask[0]);
+ IPACMDBG("1st: %08x ",
+ data_addr->ipv6_addr_mask[1]);
+ IPACMDBG("2st: %08x ",
+ data_addr->ipv6_addr_mask[2]);
+ IPACMDBG("3st: %08x \n",
+ data_addr->ipv6_addr_mask[3]);
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_GATEWAY)
+ {
+ IPACMDBG("DEL ::/0 Next Hop: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, metric %d, dev %s\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 48)),
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert 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");
+ return IPACM_FAILURE;
+ }
+ memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+ memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr_mask));
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with if index: %d, ipv6 addr\n",
+ data_addr->if_index)
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+
+ }
+ break;
+
+ case RTM_NEWNEIGH:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+ {
+ IPACMERR("Failed to decode rtm neighbor message\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("RTM_NEWNEIGH, ndm_state:0x%x", msg_ptr->nl_neigh_info.metainfo.ndm_state)
+ if((NUD_PERMANENT | NUD_STALE) & (msg_ptr->nl_neigh_info.metainfo.ndm_state))
+ {
+ IPACMDBG("\n GOT RTM_NEWNEIGH event\n");
+ /* insert to command queue */
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if(data_all == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_all\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family)
+ {
+ IPACMDBG("IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 48)));
+
+ memcpy(data_all->ipv6_addr,
+ msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+ sizeof(data_all->ipv6_addr));
+ data_all->iptype = IPA_IP_v6;
+ }
+ else
+ {
+ IPACMDBG("IPV4 %d.%d.%d.%d\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 24));
+
+
+ memcpy(&data_all->ipv4_addr,
+ msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+ sizeof(data_all->ipv4_addr));
+ data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+ data_all->iptype = IPA_IP_v4;
+ }
+
+ memcpy(data_all->mac_addr,
+ msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+ sizeof(data_all->mac_addr));
+ evt_data.event = IPA_NEW_NEIGH_EVENT;
+ data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+
+ IPACMDBG("posting IPA_NEW_NEIGH_EVENT with if index:%d\n",
+ data_all->if_index);
+ evt_data.evt_data = data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface index\n");
+ }
+ else
+ {
+ IPACMDBG("Interface %s \n", dev_name);
+ }
+ }
+ break;
+
+ case RTM_DELNEIGH:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+ {
+ IPACMERR("Failed to decode rtm neighbor message\n");
+ return IPACM_FAILURE;
+ }
+
+ if((NUD_PERMANENT | NUD_STALE) & (msg_ptr->nl_neigh_info.metainfo.ndm_state))
+ {
+ IPACMDBG("\n GOT RTM_DELNEIGH event\n");
+ /* insert to command queue */
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if(data_all == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_all\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family)
+ {
+ IPACMDBG("IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 48)));
+
+ memcpy(data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+ sizeof(data_all->ipv6_addr));
+ data_all->iptype = IPA_IP_v6;
+ }
+ else
+ {
+ IPACMDBG("IPV4 %d.%d.%d.%d\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 24));
+
+
+ memcpy(&data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+ sizeof(data_all->ipv4_addr));
+ data_all->iptype = IPA_IP_v4;
+ }
+
+ memcpy(data_all->mac_addr,
+ msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+ sizeof(data_all->mac_addr));
+ evt_data.event = IPA_DEL_NEIGH_EVENT;
+ data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+
+ IPACMDBG("posting IPA_DEL_NEIGH_EVENT with if index:%d\n",
+ data_all->if_index);
+ evt_data.evt_data = data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ //IPACM_LOG_MSG("Error while getting interface index");
+ }
+ else
+ {
+ IPACMDBG("Interface %s \n", dev_name);
+ }
+ }
+ break;
+
+ default:
+ IPACMDBG(" ignore NL event %d!!!\n ", nlh->nlmsg_type);
+ break;
+
+ }
+ nlh = NLMSG_NEXT(nlh, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+
+/* Virtual function registered to receive incoming messages over the NETLINK routing socket*/
+int ipa_nl_recv_msg(int fd)
+{
+ struct msghdr *msghdr = NULL;
+ //struct sockaddr_nl *nladdr = NULL;
+ struct iovec *iov = NULL;
+ unsigned int msglen = 0;
+ ipa_nl_msg_t *nlmsg = NULL;
+
+ nlmsg = (ipa_nl_msg_t *)malloc(sizeof(ipa_nl_msg_t));
+ if(NULL == nlmsg)
+ {
+ IPACMERR("Failed alloc of nlmsg \n");
+ goto error;
+ }
+ else
+ {
+ if(IPACM_SUCCESS != ipa_nl_recv(fd, &msghdr, &msglen))
+ {
+ IPACMERR("Failed to receive nl message \n");
+ goto error;
+ }
+
+ //nladdr = (struct sockaddr_nl *)msghdr->msg_name;
+ iov = msghdr->msg_iov;
+
+ memset(nlmsg, 0, sizeof(ipa_nl_msg_t));
+ if(IPACM_SUCCESS != ipa_nl_decode_nlmsg((char *)iov->iov_base, msglen, nlmsg))
+ {
+ IPACMERR("Failed to decode nl message \n");
+ goto error;
+ }
+
+ ipa_nl_release_msg(msghdr);
+ free(nlmsg);
+ }
+
+ return IPACM_SUCCESS;
+
+error:
+ if(msghdr)
+ {
+ ipa_nl_release_msg(msghdr);
+ }
+ if(nlmsg)
+ {
+ free(nlmsg);
+ }
+
+ return IPACM_FAILURE;
+}
+
+/* get ipa interface name */
+int ipa_get_if_name
+(
+ char *if_name,
+ int if_index
+ )
+{
+ int fd;
+ struct ifreq ifr;
+
+ if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ IPACMERR("get interface name socket create failed \n");
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ ifr.ifr_ifindex = if_index;
+ IPACMDBG("Interface index %d\n", if_index);
+
+ if(ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+ {
+ IPACMERR("call_ioctl_on_dev: ioctl failed:\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ (void)strncpy(if_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+ IPACMDBG("interface name %s\n", ifr.ifr_name);
+ close(fd);
+
+ return IPACM_SUCCESS;
+}
+
+/* Initialization routine for listener on NetLink sockets interface */
+int ipa_nl_listener_init
+(
+ unsigned int nl_type,
+ unsigned int nl_groups,
+ ipa_nl_sk_fd_set_info_t *sk_fdset,
+ ipa_sock_thrd_fd_read_f read_f
+ )
+{
+ ipa_nl_sk_info_t sk_info, sk_info2;
+ int ret_val;
+
+ memset(&sk_info, 0, sizeof(ipa_nl_sk_info_t));
+ IPACMDBG("Entering IPA NL listener init\n");
+
+ if(ipa_nl_open_socket(&sk_info, nl_type, nl_groups) == IPACM_SUCCESS)
+ {
+ IPACMDBG("IPA Open netlink socket succeeds\n");
+ }
+ else
+ {
+ IPACMERR("Netlink socket open failed\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Add NETLINK socket to the list of sockets that the listener
+ thread should listen on. */
+
+ if(ipa_nl_addfd_map(sk_fdset, sk_info.sk_fd, read_f) != IPACM_SUCCESS)
+ {
+ IPACMERR("cannot add nl routing sock for reading\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Start the socket listener thread */
+ ret_val = ipa_nl_sock_listener_start(sk_fdset);
+
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Failed to start NL listener\n");
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* find the newroute subnet mask */
+int find_mask(int ip_v4_last, int *mask_value)
+{
+
+ switch(ip_v4_last)
+ {
+
+ case 3:
+ *mask_value = 252;
+ return IPACM_SUCCESS;
+ break;
+
+ case 7:
+ *mask_value = 248;
+ return IPACM_SUCCESS;
+ break;
+
+ case 15:
+ *mask_value = 240;
+ return IPACM_SUCCESS;
+ break;
+
+ case 31:
+ *mask_value = 224;
+ return IPACM_SUCCESS;
+ break;
+
+ case 63:
+ *mask_value = 192;
+ return IPACM_SUCCESS;
+ break;
+
+ case 127:
+ *mask_value = 128;
+ return IPACM_SUCCESS;
+ break;
+
+ case 255:
+ *mask_value = 0;
+ return IPACM_SUCCESS;
+ break;
+
+ default:
+ return IPACM_FAILURE;
+ break;
+
+ }
+}
+
+/* map mask value for ipv6 */
+int mask_v6(int index, uint32_t *mask)
+{
+ switch(index)
+ {
+
+ case 0:
+ *mask = 0x00000000;
+ return IPACM_SUCCESS;
+ break;
+ case 4:
+ *mask = 0xf0000000;
+ return IPACM_SUCCESS;
+ break;
+ case 8:
+ *mask = 0xff000000;
+ return IPACM_SUCCESS;
+ break;
+ case 12:
+ *mask = 0xfff00000;
+ return IPACM_SUCCESS;
+ break;
+ case 16:
+ *mask = 0xffff0000;
+ return IPACM_SUCCESS;
+ break;
+ case 20:
+ *mask = 0xfffff000;
+ return IPACM_SUCCESS;
+ break;
+ case 24:
+ *mask = 0xffffff00;
+ return IPACM_SUCCESS;
+ break;
+ case 28:
+ *mask = 0xfffffff0;
+ return IPACM_SUCCESS;
+ break;
+ case 32:
+ *mask = 0xffffffff;
+ return IPACM_SUCCESS;
+ break;
+ default:
+ return IPACM_FAILURE;
+ break;
+
+ }
+}
+
+
diff --git a/ipacm/src/IPACM_Routing.cpp b/ipacm/src/IPACM_Routing.cpp
new file mode 100644
index 0000000..1351fbe
--- /dev/null
+++ b/ipacm/src/IPACM_Routing.cpp
@@ -0,0 +1,226 @@
+/*
+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)
+ {
+ IPACMDBG("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;
+
+ if (!DeviceNodeIsOpened())
+ {
+ IPACMDBG("Device is not opened\n");
+ return false;
+ }
+
+ retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
+ if (retval)
+ {
+ IPACMERR("Failed adding routing rule %p\n", ruleTable);
+ return false;
+ }
+
+ IPACMDBG("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("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("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("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("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
+ 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("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("Invalid route handle passed. Ignoring it\n");
+ return false;
+ }
+
+ 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("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;
+}
+
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
new file mode 100644
index 0000000..1a45dc5
--- /dev/null
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -0,0 +1,1249 @@
+/*
+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_Wan.cpp
+
+ @brief
+ This file implements the WAN iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Xml.h>
+#include <IPACM_Log.h>
+#include "IPACM_EvtDispatcher.h"
+#include <IPACM_IfaceManager.h>
+
+bool IPACM_Wan::wan_up = false;
+
+IPACM_Wan::IPACM_Wan(int iface_index) : IPACM_Iface(iface_index)
+{
+ num_firewall_v4 = 0;
+ num_firewall_v6 = 0;
+ num_dft_rt = 0;
+
+ wan_route_rule_v4_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+ wan_route_rule_v6_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+
+ active_v4 = false;
+ active_v6 = false;
+
+ IPACMDBG(" IPACM->IPACM_Wan(%d) constructor: Tx:%d\n", ipa_if_num, iface_query->num_tx_props);
+ return;
+}
+
+IPACM_Wan::~IPACM_Wan()
+{
+ IPACM_EvtDispatcher::deregistr(this);
+ IPACM_IfaceManager::deregistr(this);
+ return;
+}
+
+/* handle new_address event */
+int IPACM_Wan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ const int NUM_RULES = 1;
+ int res = IPACM_SUCCESS;
+
+ /* initial multicast/broadcast/fragment filter rule */
+ init_fl_rule(data->iptype);
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = data->iptype;
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ }
+ else
+ {
+ strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+ }
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 1;
+ rt_rule_entry->rule.dst = IPA_CLIENT_A5_LAN_WAN_CONS; //go to A5
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+
+ if (data->iptype == IPA_IP_v6)
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ }
+ else
+ {
+ /* still need setup v4 default routing rule to A5*/
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+ wan_v4_addr = data->ipv4_addr;
+ IPACMDBG("Receved wan address:0x%x\n", wan_v4_addr);
+ }
+
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ IPACMDBG("rt rule hdl=%x with ip-type: %d\n", rt_rule_entry->rt_rule_hdl, data->iptype);
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG("ipv4 wan rt rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
+ }
+ else
+ {
+ dft_rt_rule_hdl[1 + num_dft_rt] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG("ipv6 wan rt rule hdl1=0x%x\n", dft_rt_rule_hdl[1 + num_dft_rt]);
+ num_dft_rt++;
+ }
+
+
+fail:
+ free(rt_rule);
+
+ return res;
+}
+
+void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param)
+{
+ int ipa_interface_index;
+
+ switch (event)
+ {
+
+ case IPA_LINK_DOWN_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ delete this;
+ return;
+ }
+ }
+ break;
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+ {
+ IPACMDBG("Received IPA_ADDR_ADD_EVENT\n");
+ handle_addr_evt(data);
+ }
+ }
+ }
+ break;
+
+ case IPA_ROUTE_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ROUTE_ADD_EVENT\n");
+ IPACMDBG("ipv4 addr 0x%x\n", data->ipv4_addr);
+ IPACMDBG("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
+
+ /* The special below condition is to handle default gateway */
+ if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask))
+ {
+ IPACMDBG("adding routing table\n");
+ handle_route_add_evt(data);
+ IPACM_Wan::wan_up = true;
+ active_v4 = true;
+ config_dft_firewall_rules(IPA_IP_v4);
+ }
+ else if ((data->iptype == IPA_IP_v6) &&
+ (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]))
+ {
+ IPACMDBG("\n get default v6 route (dst:00.00.00.00)\n");
+ IPACMDBG(" IPV6 value: %08x:%08x:%08x:%08x \n",
+ data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+ handle_route_add_evt(data);
+ active_v6 = true;
+ config_dft_firewall_rules(IPA_IP_v6);
+ }
+ }
+ }
+ break;
+
+ case IPA_ROUTE_DEL_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ROUTE_DEL_EVENT\n");
+ if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask))
+ {
+ IPACMDBG("get del default v4 route (dst:0.0.0.0)\n");
+ del_dft_firewall_rules(IPA_IP_v4);
+ handle_route_del_evt(data->iptype);
+ IPACM_Wan::wan_up = false;
+ }
+ else if ((data->iptype == IPA_IP_v6) && (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]))
+ {
+ IPACMDBG("get del default v6 route (dst:00.00.00.00)\n");
+ del_dft_firewall_rules(IPA_IP_v6);
+ handle_route_del_evt(data->iptype);
+ }
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+ IPACMDBG("I'm in the WAN\n");
+ handle_header_add_evt(data->mac_addr);
+ }
+ }
+ break;
+
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+ /* handle software routing enable event */
+ handle_software_routing_enable();
+ break;
+
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+ /* handle software routing disable event */
+ handle_software_routing_disable();
+ break;
+
+ case IPA_FIREWALL_CHANGE_EVENT:
+ IPACMDBG("Received IPA_FIREWALL_CHANGE_EVENT\n");
+ /* handle software routing enable event */
+ if (active_v4)
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ config_dft_firewall_rules(IPA_IP_v4);
+ }
+
+ if (active_v6)
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ config_dft_firewall_rules(IPA_IP_v6);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+/* wan default route/filter rule configuration */
+int IPACM_Wan::handle_route_add_evt(ipacm_event_data_addr *data)
+{
+
+ /* add default WAN route */
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ struct ipa_ioc_get_hdr sRetHeader;
+ uint32_t tx_index;
+ const int NUM = 1;
+ ipacm_cmd_q_data evt_data;
+
+ IPACMDBG(" ip-type:%d\n", data->iptype);
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)NUM;
+ rt_rule->ip = data->iptype;
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+ }
+ else
+ {
+ strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+ }
+
+ IPACMDBG(" WAN table created %s \n", rt_rule->rt_tbl_name);
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 1;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (data->iptype != tx_prop->tx[tx_index].ip)
+ {
+ continue;
+ }
+
+ if (tx_prop->tx[tx_index].hdr_name != NULL)
+ {
+ IPACMDBG(" TX- header hdl %s \n", tx_prop->tx[tx_index].hdr_name);
+ memset(&sRetHeader, 0, sizeof(sRetHeader));
+ strncpy(sRetHeader.name,
+ tx_prop->tx[tx_index].hdr_name,
+ sizeof(tx_prop->tx[tx_index].hdr_name));
+ if (false == m_header.GetHeaderHandle(&sRetHeader))
+
+ {
+ IPACMERR("\n ioctl failed\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ rt_rule_entry->rule.hdr_hdl = sRetHeader.hdl;
+ }
+
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ if (data->iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = data->ipv4_addr_mask;
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = data->ipv6_addr_mask[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = data->ipv6_addr_mask[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = data->ipv6_addr_mask[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = data->ipv6_addr_mask[3];
+ }
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ wan_route_rule_v4_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG("Got ipv4 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+ wan_route_rule_v4_hdl[tx_index],
+ tx_index,
+ data->iptype);
+ }
+ else
+ {
+ wan_route_rule_v6_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG("Got ipv6 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+ wan_route_rule_v6_hdl[tx_index],
+ tx_index,
+ data->iptype);
+ }
+ }
+ free(rt_rule);
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ ipacm_event_iface_up *wanup_data;
+
+ wanup_data =
+ (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+ if (wanup_data == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
+ wanup_data->ipv4_addr = wan_v4_addr;
+ IPACMDBG("Posting IPA_HANDLE_WAN_UP with below information:\n");
+ IPACMDBG("if_name:%s, ipv4_address:0x%x\n",
+ wanup_data->ifname, wanup_data->ipv4_addr);
+
+ evt_data.event = IPA_HANDLE_WAN_UP;
+ evt_data.evt_data = (void *)wanup_data;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* wan default route/filter rule delete */
+int IPACM_Wan::handle_route_del_evt(ipa_ip_type iptype)
+{
+ uint32_t tx_index;
+ ipacm_cmd_q_data evt_data;
+
+ IPACMDBG("got handle_route_del_evt with ip-family:%d \n", iptype);
+
+ if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
+ ((iptype == IPA_IP_v6) && (active_v6 == true)))
+ {
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype == IPA_IP_v4)
+ {
+
+ if (m_routing.DeleteRoutingHdl(wan_route_rule_v4_hdl[tx_index], IPA_IP_v4)
+ == false)
+ {
+ IPACMDBG("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v4, wan_route_rule_v4_hdl[tx_index], tx_index);
+ return IPACM_FAILURE;
+ }
+
+ }
+ else
+ {
+ if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl[tx_index], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v6, wan_route_rule_v6_hdl[tx_index], tx_index);
+ return IPACM_FAILURE;
+ }
+ }
+
+ }
+
+ if (iptype == IPA_IP_v4)
+ {
+
+ uint32_t *wan_ip_addr = (uint32_t *)malloc(sizeof(uint32_t));
+ if (wan_ip_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory\n");
+ return IPACM_FAILURE;
+ }
+
+ *wan_ip_addr = wan_v4_addr;
+ evt_data.event = IPA_HANDLE_WAN_DOWN;
+ evt_data.evt_data = (void *)wan_ip_addr;
+ /* Insert IPA_HANDLE_WAN_DOWN to command queue */
+ IPACMDBG("posting IPA_HANDLE_WAN_DOWN for IPv4 \n");
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACM_Wan::wan_up = false;
+ active_v4 = false;
+ }
+ else
+ {
+ active_v6 = false;
+ }
+ }
+ else
+ {
+ IPACMDBG(" The default WAN routing rules are deleted already \n");
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* construct complete ethernet header */
+int IPACM_Wan::handle_header_add_evt(uint8_t mac_addr[6])
+{
+ char index[2];
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+ uint32_t tx_index;
+ int len = 0;
+
+ IPACMDBG("construct header\n");
+
+ /* start of add header */
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ /* add header to IPA */
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (!pHeaderDescriptor)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+
+ /* copy partial header */
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name, tx_prop->tx[tx_index].hdr_name,
+ sizeof(tx_prop->tx[tx_index].hdr_name));
+
+ IPACMDBG("header name: %s\n", sCopyHeader.name);
+ if (false == m_header.CopyHeader(&sCopyHeader))
+ {
+ IPACMERR("ioctl copy header failed\n");
+ free(pHeaderDescriptor);
+ return IPACM_FAILURE;
+ };
+
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ free(pHeaderDescriptor);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr, sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[IPA_WLAN_PARTIAL_HDR_OFFSET], mac_addr,
+ IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+ sprintf(index, "%d", ipa_if_num);
+ strncpy(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+ strncat(pHeaderDescriptor->hdr[0].name, IPA_WLAN_PARTIAL_HDR_NAME, sizeof(IPA_WLAN_PARTIAL_HDR_NAME));
+ strncat(pHeaderDescriptor->hdr[0].name, "tx", sizeof("tx"));
+ sprintf(index, "%d", tx_index);
+ strncat(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+ pHeaderDescriptor->hdr[0].hdr_len = sizeof(sCopyHeader.hdr_len);
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = false;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (false == m_header.AddHeader(pHeaderDescriptor))
+ {
+ IPACMERR("ioctl add header failed\n");
+ free(pHeaderDescriptor);
+ return IPACM_FAILURE;
+ }
+
+ memcpy(tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].name,
+ sizeof(tx_prop->tx[tx_index].hdr_name));
+ IPACMDBG("add full header name: %s (%x)\n", tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].hdr_hdl);
+
+
+ free(pHeaderDescriptor);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* configure the initial firewall filter rules */
+int IPACM_Wan::config_dft_firewall_rules(ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i, rule_v4 = 0, rule_v6 = 0;
+
+ IPACMDBG("ip-family: %d; \n", iptype);
+ memset(&firewall_config, 0, sizeof(firewall_config));
+ strncpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
+
+ if (firewall_config.firewall_config_file)
+ {
+ IPACMDBG("Firewall XML file is %s \n", firewall_config.firewall_config_file);
+ if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
+ {
+ IPACMDBG("QCMAP Firewall XML read OK \n");
+ }
+ else
+ {
+ IPACMERR("QCMAP Firewall XML read failed \n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMERR("No firewall xml mentioned \n");
+ return IPACM_FAILURE;
+ }
+
+ /* find the number of v4/v6 firewall rules */
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+ {
+ rule_v4++;
+ }
+ else
+ {
+ rule_v6++;
+ }
+ }
+
+ IPACMDBG("firewall rule v4:%d v6:%d total:%d\n", rule_v4, rule_v6, firewall_config.num_extd_firewall_entries);
+
+ /* construct ipa_ioc_add_flt_rule with N firewall rules */
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ if (iptype == IPA_IP_v4)
+ {
+ if (rule_v4 == 0)
+ {
+ 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->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_lan_v4) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+ else
+ {
+ 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 == NULL)
+ {
+ 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 = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ IPACMDBG("Retreiving Routing handle for routing table name:%s\n",
+ IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(&rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Routing handle for wan routing table:0x%x\n", IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl);
+
+ rule_v4 = 0;
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION; //Matched the firewall rule, go exception
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &firewall_config.extd_firewall_entries[i].attrib,
+ sizeof(struct ipa_rule_attrib));
+
+ IPACMDBG("rx property attrib mask: 0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ /* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
+ if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol
+ == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+ {
+ /* insert TCP rule*/
+ flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v4 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+
+ /* insert UDP rule*/
+ flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v4 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+ }
+ else
+ {
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v4 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+ }
+ }
+ } /* end of firewall ipv4 filter rule add for loop*/
+
+ /* configure default filter rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+
+ }
+ else
+ {
+ if (rule_v6 == 0)
+ {
+ 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->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_v6) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+ else
+ {
+ 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)
+ {
+ IPACMDBG("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_v6) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ rule_v6 = 0;
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &firewall_config.extd_firewall_entries[i].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ /* check if the rule is define as TCP/UDP */
+ if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+ {
+ /* insert TCP rule*/
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v4 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+
+ /* insert UDP rule*/
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v6 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+ }
+ else
+ {
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v6 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+ }
+ }
+ } /* end of firewall ipv6 filter rule add for loop*/
+
+ /* setup default wan filter rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+ /* copy filter hdls*/
+ dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+
+
+/*handle wan-iface down event */
+int IPACM_Wan::handle_down_evt()
+{
+ int res = IPACM_SUCCESS;
+ int i;
+
+ IPACMDBG(" wan handle_down_evt \n");
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ goto fail;
+ }
+
+ /* make sure default routing rules and firewall rules are deleted*/
+ if (ip_type != IPA_IP_v6)
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ handle_route_del_evt(IPA_IP_v4);
+ }
+
+ if (ip_type != IPA_IP_v4)
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ handle_route_del_evt(IPA_IP_v6);
+ }
+
+ /* Delete default v4 RT rule */
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG("Delete default v4 routing rules\n");
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+ == false)
+ {
+ IPACMDBG("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* delete default v6 RT rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ IPACMDBG("Delete default v6 routing rules\n");
+ /* May have multiple ipv6 iface-routing rules*/
+ for (i = 0; i < num_dft_rt; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[1 + i], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ IPACMDBG("finished delete default v6 RT rules\n ");
+ }
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true)
+ {
+ IPACM_Iface::handle_software_routing_disable();
+ handle_software_routing_disable();
+ }
+
+ /* free filter rule handlers */
+ if (ip_type != IPA_IP_v6)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+ IPA_IP_v4,
+ IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Delete Filtering rules, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("finished delete default v4 filtering rules\n ");
+ }
+
+
+ if (ip_type != IPA_IP_v4)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+ IPA_IP_v6,
+ IPV6_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("ErrorDeleting Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("finished delete default v6 filtering rules\n ");
+ }
+
+fail:
+ free(tx_prop);
+ free(rx_prop);
+ free(iface_query);
+
+ return res;
+}
+
+/*clean firewall filter rules */
+int IPACM_Wan::del_dft_firewall_rules(ipa_ip_type iptype)
+{
+ /* free v4 firewall filter rule */
+ if ((iptype == IPA_IP_v4) && (active_v4 == true))
+ {
+ if (num_firewall_v4 != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(firewall_hdl_v4,
+ IPA_IP_v4, num_firewall_v4) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMDBG("No ipv4 firewall rules, no need deleted\n");
+ }
+
+ if (m_filtering.DeleteFilteringHdls(dft_wan_fl_hdl,
+ IPA_IP_v4, 1) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+
+ num_firewall_v4 = 0;
+ }
+
+ /* free v6 firewall filter rule */
+ if ((iptype == IPA_IP_v6) && (active_v6 == true))
+ {
+ if (num_firewall_v6 != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(firewall_hdl_v6,
+ IPA_IP_v6, num_firewall_v6) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMDBG("No ipv6 firewall rules, no need deleted\n");
+ }
+
+ if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[1],
+ IPA_IP_v6, 1) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ num_firewall_v6 = 0;
+ }
+
+ return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
new file mode 100644
index 0000000..0160406
--- /dev/null
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -0,0 +1,1421 @@
+/*
+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_Wlan.cpp
+
+@brief
+This file implements the WLAN iface functionality.
+
+@Author
+Skylar Chang
+
+*/
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wlan.h>
+#include <IPACM_Netlink.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Lan.h>
+#include <IPACM_IfaceManager.h>
+
+/* static member to store the number of total wifi clients within all APs*/
+int IPACM_Wlan::total_num_wifi_clients = 0;
+
+IPACM_Wlan::IPACM_Wlan(int iface_index) : IPACM_Lan(iface_index)
+{
+#define WLAN_AMPDU_DEFAULT_FILTER_RULES 3
+
+ num_wifi_client = 0;
+ header_name_count = 0;
+
+ /* one for WAN and two for Soft-routing */
+ wlan_ampdu_flt_rule.num_rules = WLAN_AMPDU_DEFAULT_FILTER_RULES;
+
+ wlan_ampdu_flt_rule.hdl[0] = 0; /* for WAN */
+ wlan_ampdu_flt_rule.ip[0] = IPA_IP_v4; /* for WAN */
+
+ wlan_ampdu_flt_rule.hdl[1] = 0; /* for Soft-routing */
+ wlan_ampdu_flt_rule.ip[1] = IPA_IP_v4; /* for Soft-routing */
+
+ wlan_ampdu_flt_rule.hdl[2] = 0; /* for Soft-routing */
+ wlan_ampdu_flt_rule.ip[2] = IPA_IP_v6; /* for Soft-routing */
+
+ wlan_client_len = (sizeof(ipa_wlan_client)) + (iface_query->num_tx_props * sizeof(wlan_client_rt_hdl));
+ wlan_client = (ipa_wlan_client *)calloc(IPA_MAX_NUM_WIFI_CLIENTS, wlan_client_len);
+ if (wlan_client == NULL)
+ {
+ IPACMERR("unable to allocate memory\n");
+ return;
+ }
+
+ IPACMDBG("index:%d constructor: Tx properties:%d\n", iface_index, iface_query->num_tx_props);
+ return;
+}
+
+
+IPACM_Wlan::~IPACM_Wlan()
+{
+ IPACM_EvtDispatcher::deregistr(this);
+ IPACM_IfaceManager::deregistr(this);
+ return;
+}
+
+void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param)
+{
+ int ipa_interface_index;
+
+ switch (event)
+ {
+
+ case IPA_LINK_DOWN_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ IPACMDBG("ipa_WLAN (%s):ipa_index (%d) instance close \n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ delete this;
+ return;
+ }
+ }
+ break;
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ if (ipa_interface_index == ipa_if_num)
+ {
+ if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+ {
+ /* Post event to NAT */
+ if (data->iptype == IPA_IP_v4)
+ {
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_iface_up *info;
+
+ info = (ipacm_event_iface_up *)
+ malloc(sizeof(ipacm_event_iface_up));
+ if (info == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+
+ memcpy(info->ifname, dev_name, IF_NAME_LEN);
+ info->ipv4_addr = data->ipv4_addr;
+ info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+ evt_data.event = IPA_HANDLE_WLAN_UP;
+ evt_data.evt_data = (void *)info;
+
+ /* Insert IPA_HANDLE_WLAN_UP to command queue */
+ IPACMDBG("posting IPA_HANDLE_WLAN_UP for IPv4 with below information\n");
+ IPACMDBG("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+ info->ipv4_addr, info->addr_mask);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ IPACM_Lan::handle_addr_evt(data);
+ handle_addr_evt(data);
+
+ IPACM_Lan::handle_private_subnet(data->iptype);
+ handle_private_subnet(data->iptype);
+
+ if (IPACM_Wan::isWanUP() && (data->iptype == IPA_IP_v4))
+ {
+ IPACM_Lan::handle_wan_up();
+ handle_wan_up();
+ }
+
+ IPACMDBG("posting IPA_HANDLE_WLAN_UP:Finished checking wan_up\n");
+ }
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+ IPACM_Lan::handle_wan_up();
+ handle_wan_up();
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+ IPACM_Lan::handle_wan_down();
+ handle_wan_down();
+ break;
+
+ case IPA_WLAN_CLIENT_ADD_EVENT:
+ {
+ ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
+ handle_wlan_client_init(data->mac_addr);
+ }
+ }
+ break;
+
+ case IPA_WLAN_CLIENT_DEL_EVENT:
+ {
+ ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_WLAN_CLIENT_DEL_EVENT\n");
+ handle_wlan_client_down_evt(data->mac_addr);
+ }
+ }
+ break;
+
+ case IPA_WLAN_CLIENT_POWER_SAVE_EVENT:
+ {
+ ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_WLAN_CLIENT_POWER_SAVE_EVENT\n");
+ handle_wlan_client_pwrsave(data->mac_addr);
+ }
+ }
+ break;
+
+ case IPA_WLAN_CLIENT_RECOVER_EVENT:
+ {
+ ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_WLAN_CLIENT_RECOVER_EVENT\n");
+ if (ip_type != IPA_IP_v6) /* for ipv4 */
+ {
+ handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v4);
+ }
+
+ if (ip_type != IPA_IP_v4) /* for ipv6 */
+ {
+ handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v6);
+ }
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+ if (handle_wlan_client_ipaddr(data) == IPACM_FAILURE)
+ {
+ return;
+ }
+ handle_wlan_client_route_rule(data->mac_addr, data->iptype);
+ }
+ }
+ break;
+
+ /* handle software routing enable event*/
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+ IPACM_Iface::handle_software_routing_enable();
+ handle_software_routing_enable();
+ break;
+
+ /* handle software routing disable event*/
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+ IPACM_Iface::handle_software_routing_disable();
+ handle_software_routing_disable();
+ break;
+
+ default:
+ break;
+ }
+ return;
+}
+
+/* handle wifi client initial,copy all partial headers (tx property) */
+int IPACM_Wlan::handle_wlan_client_init(uint8_t *mac_addr)
+{
+
+#define WLAN_IFACE_INDEX_LEN 2
+
+ int res = IPACM_SUCCESS, len = 0;
+ char index[WLAN_IFACE_INDEX_LEN];
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+
+ /* start of adding header */
+ if ((num_wifi_client >= IPA_MAX_NUM_WIFI_CLIENTS) ||
+ (IPACM_Wlan::total_num_wifi_clients >= IPA_MAX_NUM_WIFI_CLIENTS))
+ {
+ IPACMERR("Reached maximum number of wlan clients\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("Wifi client number: %d\n", num_wifi_client);
+
+ IPACMDBG("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ memcpy(get_client_memptr(wlan_client, num_wifi_client)->mac,
+ mac_addr,
+ sizeof(get_client_memptr(wlan_client, num_wifi_client)->mac));
+
+ IPACMDBG("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wlan_client, num_wifi_client)->mac[0],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[1],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[2],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[3],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[4],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[5]);
+
+ /* add header to IPA */
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+
+ /* copy partial header */
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[0].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG("header name: %s\n", sCopyHeader.name);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr,
+ sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[IPA_WLAN_PARTIAL_HDR_OFFSET],
+ get_client_memptr(wlan_client, num_wifi_client)->mac,
+ IPA_MAC_ADDR_SIZE);
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ sprintf(index, "%d", ipa_if_num);
+ strncpy(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+ strncat(pHeaderDescriptor->hdr[0].name,
+ IPA_WLAN_PARTIAL_HDR_NAME,
+ sizeof(IPA_WLAN_PARTIAL_HDR_NAME));
+
+ sprintf(index, "%d", header_name_count);
+ strncat(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+ pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = 0;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ pHeaderDescriptor->hdr[0].status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl = pHeaderDescriptor->hdr[0].hdr_hdl;
+ IPACMDBG("client(%d) full header name:%s header handle:(0x%x)\n",
+ num_wifi_client,
+ pHeaderDescriptor->hdr[0].name,
+ get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl);
+ /* initialize wifi client*/
+ get_client_memptr(wlan_client, num_wifi_client)->route_rule_set_v4 = false;
+ get_client_memptr(wlan_client, num_wifi_client)->route_rule_set_v6 = false;
+ get_client_memptr(wlan_client, num_wifi_client)->ipv4_set = false;
+ get_client_memptr(wlan_client, num_wifi_client)->ipv6_set = false;
+
+ num_wifi_client++;
+ header_name_count++; //keep increasing header_name_count
+ IPACM_Wlan::total_num_wifi_clients++;
+ res = IPACM_SUCCESS;
+
+ IPACMDBG("Wifi client number: %d\n", num_wifi_client);
+
+fail:
+ free(pHeaderDescriptor);
+
+ return res;
+}
+
+/*handle wifi client */
+int IPACM_Wlan::handle_wlan_client_ipaddr(ipacm_event_data_all *data)
+{
+ int clnt_indx;
+
+ IPACMDBG("number of wifi clients: %d\n", num_wifi_client);
+ IPACMDBG(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->mac_addr[0],
+ data->mac_addr[1],
+ data->mac_addr[2],
+ data->mac_addr[3],
+ data->mac_addr[4],
+ data->mac_addr[5]);
+
+ clnt_indx = get_wlan_client_index(data->mac_addr);
+ if (clnt_indx == IPACM_INVALID_INDEX)
+ {
+ if (clnt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG("wlan client not found/attached \n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ IPACMDBG("Ip type received %d\n", data->iptype);
+ if (data->iptype == IPA_IP_v4)
+ {
+ IPACMDBG("Ipv4 with ipv4 address: 0x%x\n", data->ipv4_addr);
+ if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+ {
+ if (get_client_memptr(wlan_client, clnt_indx)->ipv4_set == false)
+ {
+ get_client_memptr(wlan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+ get_client_memptr(wlan_client, clnt_indx)->ipv4_set = true;
+ }
+ else
+ {
+ IPACMDBG("Already setup ipv4 addr for client:%d\n", clnt_indx);
+ }
+ }
+ }
+ else
+ {
+ if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+ (data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0)) /* check if all 0 not valid ipv6 address */
+ {
+ if (get_client_memptr(wlan_client, clnt_indx)->ipv6_set == false)
+ {
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[0] = data->ipv6_addr[0];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[1] = data->ipv6_addr[1];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[2] = data->ipv6_addr[2];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[3] = data->ipv6_addr[3];
+ get_client_memptr(wlan_client, clnt_indx)->ipv6_set = true;
+ }
+ else
+ {
+ IPACMDBG("Already setup ipv6 addr for client:%d\n", clnt_indx);
+ }
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle wifi client routing rule*/
+int IPACM_Wlan::handle_wlan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ uint32_t tx_index;
+ int wlan_index;
+
+ IPACMDBG("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ wlan_index = get_wlan_client_index(mac_addr);
+ if (wlan_index == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG("wlan client not found/attached \n");
+ return IPACM_SUCCESS;
+ }
+
+ IPACMDBG("wlan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wlan_index, iptype,
+ get_client_memptr(wlan_client, wlan_index)->ipv4_set,
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4);
+ /* Add default 4 Qos routing rules if not set yet */
+ if ((iptype == IPA_IP_v4
+ && get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false
+ && get_client_memptr(wlan_client, wlan_index)->ipv4_set == true)
+ || (iptype == IPA_IP_v6
+ && get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 == false
+ && get_client_memptr(wlan_client, wlan_index)->ipv6_set == true))
+ {
+ IPACMDBG("client index(%d):ipv4 address: 0x%x\n", wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+ IPACMDBG("client(%d): header handle:(0x%x), num of rules: %d\n",
+ wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->hdr_hdl,
+ iface_query->num_tx_props);
+
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ (iface_query->num_tx_props * sizeof(struct ipa_rt_rule_add)));
+
+ if (rt_rule == NULL)
+ {
+ PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = iface_query->num_tx_props;
+ rt_rule->ip = iptype;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype == IPA_IP_v4)
+ {
+ strncpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
+ sizeof(rt_rule->rt_tbl_name));
+ }
+ else
+ {
+ strncpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+ sizeof(rt_rule->rt_tbl_name));
+ }
+
+ rt_rule_entry = &rt_rule->rules[tx_index];
+ rt_rule_entry->at_rear = 0;
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl;
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+ if (iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wlan_client, wlan_index)->v4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+ }
+ else if (iptype == IPA_IP_v6)
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ }
+ } /* end of for loop */
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype == IPA_IP_v4)
+ {
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+ rt_rule->rules[tx_index].rt_rule_hdl;
+ IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
+ }
+ else if (iptype == IPA_IP_v6)
+ {
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6 =
+ rt_rule->rules[tx_index].rt_rule_hdl;
+ IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6, iptype);
+ }
+ }
+
+ free(rt_rule);
+
+ if (iptype == IPA_IP_v4)
+ {
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 = true;
+ }
+ else
+ {
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 = true;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle wifi client power-save mode*/
+int IPACM_Wlan::handle_wlan_client_pwrsave(uint8_t *mac_addr)
+{
+ int clt_indx;
+ IPACMDBG("wlan->handle_wlan_client_pwrsave();\n");
+
+ clt_indx = get_wlan_client_index(mac_addr);
+ if (clt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG("wlan client not attached\n");
+ return IPACM_SUCCESS;
+ }
+
+ /*check if got duplicate power-save mode*/
+ if ((ip_type != IPA_IP_v6 && get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 == true)
+ || (ip_type != IPA_IP_v4 && get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 == true))
+ {
+ return delete_default_qos_rtrules(clt_indx);
+ }
+ else
+ {
+ IPACMDBG("wlan client already in power-save mode\n");
+ return IPACM_SUCCESS;
+ }
+}
+
+/*handle wifi client del mode*/
+int IPACM_Wlan::handle_wlan_client_down_evt(uint8_t *mac_addr)
+{
+ int clt_indx;
+ uint32_t tx_index;
+ int num_wifi_client_tmp = num_wifi_client;
+
+ IPACMDBG("total client: %d\n", num_wifi_client_tmp);
+
+ clt_indx = get_wlan_client_index(mac_addr);
+ if (clt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG("wlan client not attached\n");
+ return IPACM_SUCCESS;
+ }
+
+ if (delete_default_qos_rtrules(clt_indx))
+ {
+ IPACMDBG("unbale to delete default qos route rules\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Delete wlan client header */
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, clt_indx)->hdr_hdl)
+ == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ /* Reset ip_set to 0*/
+ get_client_memptr(wlan_client, clt_indx)->ipv4_set = false;
+ get_client_memptr(wlan_client, clt_indx)->ipv6_set = false;
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = false;
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = false;
+
+ for (; clt_indx < num_wifi_client_tmp - 1; clt_indx++)
+ {
+ memcpy(get_client_memptr(wlan_client, clt_indx)->mac,
+ get_client_memptr(wlan_client, (clt_indx + 1))->mac,
+ sizeof(get_client_memptr(wlan_client, clt_indx)->mac));
+
+ get_client_memptr(wlan_client, clt_indx)->hdr_hdl = get_client_memptr(wlan_client, (clt_indx + 1))->hdr_hdl;
+ get_client_memptr(wlan_client, clt_indx)->v4_addr = get_client_memptr(wlan_client, (clt_indx + 1))->v4_addr;
+
+ get_client_memptr(wlan_client, clt_indx)->ipv4_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv4_set;
+ get_client_memptr(wlan_client, clt_indx)->ipv6_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv6_set;
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = get_client_memptr(wlan_client, (clt_indx + 1))->route_rule_set_v4;
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = get_client_memptr(wlan_client, (clt_indx + 1))->route_rule_set_v6;
+
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[0] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[0];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[1] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[1];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[2] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[2];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[3] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[3];
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+ get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+ get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6 =
+ get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6;
+ }
+ }
+
+ IPACMDBG(" %d wifi client deleted successfully \n", num_wifi_client);
+ num_wifi_client = num_wifi_client - 1;
+ IPACM_Wlan::total_num_wifi_clients = IPACM_Wlan::total_num_wifi_clients - 1;
+ IPACMDBG(" Number of wifi client: %d\n", num_wifi_client);
+
+ return IPACM_SUCCESS;
+}
+
+/* duplicate ampdu filter rules for wan_up event */
+int IPACM_Wlan::handle_wan_up(void)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ IPACMDBG("Wlan->handle_wan_up(); \n");
+
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+ {
+ IPACMDBG("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+ return IPACM_FAILURE;
+ }
+
+ memset(&flt_rule_entry, 0, sizeof(ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ /* Match-all rule */
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+ if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
+ {
+ IPACMDBG("Error Adding Filtering Rule, aborting...\n");
+ perror("Wlan: Unable to add filtering table");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+
+ return IPACM_SUCCESS;
+}
+
+
+/*delete ampdu filter rules for wan_down event*/
+int IPACM_Wlan::handle_wan_down(void)
+{
+ IPACMDBG("\n");
+
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[0],
+ IPA_IP_v4, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ wlan_ampdu_flt_rule.hdl[0] = 0;
+
+ return IPACM_SUCCESS;
+}
+
+/*duplicate ampdu filter rules for software_routing event*/
+int IPACM_Wlan::handle_software_routing_enable(void)
+{
+
+ struct ipa_flt_rule_add flt_rule_entry;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+ int res = IPACM_SUCCESS;
+
+ IPACMDBG("\n");
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ 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;
+ 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))
+ {
+ PERROR("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;
+ }
+
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+
+
+ /* handle v6*/
+ m_pFilteringTable->ip = IPA_IP_v6;
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("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;
+ }
+
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+ }
+ 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))
+ {
+ PERROR("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;
+ }
+
+ 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) wlan_ampdu_flt_rule.hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ else wlan_ampdu_flt_rule.hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+
+fail:
+ free(m_pFilteringTable);
+
+ return res;
+
+}
+
+/*delete ampdu filter rules for disabling software_routing event*/
+int IPACM_Wlan::handle_software_routing_disable(void)
+{
+
+ if (ip_type == IPA_IP_MAX)
+ {
+ /* ipv4 case */
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[1],
+ IPA_IP_v4, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ /* ipv6 case */
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[2],
+ IPA_IP_v6, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ }
+ else
+ {
+ if (ip_type == IPA_IP_v4)
+ {
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[1],
+ IPA_IP_v4, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ else if (ip_type == IPA_IP_v6)
+ {
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[2],
+ IPA_IP_v6, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+
+/*duplicate ampdu filter rules for initial iface configuration*/
+int IPACM_Wlan::init_fl_rule(ipa_ip_type iptype)
+{
+ int res = IPACM_SUCCESS;
+ struct ipa_flt_rule_add flt_rule_entry;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("ip-type: %d\n", iptype);
+
+ if (iptype == IPA_IP_v4)
+ {
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV4_DEFAULT_FILTERTING_RULES;
+
+ /* Configuring Fragment Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_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; /* DST_IP == 224.0.0.0 */
+ 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; /* Filter DST_IP == 127.0.0.1 */
+ memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding RuleTable(2) to Filtering, aborting...\n");
+ res = IPACM_FAILURE;
+ }
+ else
+ {
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 1] = m_pFilteringTable->rules[1].flt_rule_hdl;
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 2] = m_pFilteringTable->rules[2].flt_rule_hdl;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v4;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 1] = IPA_IP_v4;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 2] = IPA_IP_v4;
+ wlan_ampdu_flt_rule.num_rules += IPV4_DEFAULT_FILTERTING_RULES;
+ }
+ }
+ else
+ {
+ /* IPv6 filter rule configuration */
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
+
+ /* Configuring Fragment Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.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;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ }
+ else
+ {
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ //wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 1] = m_pFilteringTable->rules[1].flt_rule_hdl;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v6;
+ //wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 1] = IPA_IP_v6;
+ wlan_ampdu_flt_rule.num_rules += IPV6_DEFAULT_FILTERTING_RULES;
+ }
+ }
+
+ free(m_pFilteringTable);
+ return res;
+}
+
+
+/*duplicate ampdu filter rules for new_address event*/
+int IPACM_Wlan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+ struct ipa_flt_rule_add flt_rule_entry;
+ int NUM_RULES = 1;
+
+ IPACMDBG(" set route/filter rule ip-type: %d \n", data->iptype);
+ if (data->iptype == IPA_IP_v6)
+ {
+ if (num_dft_rt == 1) /*LAN handle_addr_evt will update this to 1*/
+ {
+ /* configure ampdu multicast/broadcast/fragment filter rule */
+ init_fl_rule(data->iptype);
+
+ /* add default v6 filter rule */
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ NUM_RULES * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)NUM_RULES;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ PERROR("m_routing.GetRoutingTable() Failed.\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v6;
+ wlan_ampdu_flt_rule.num_rules++;
+ free(m_pFilteringTable);
+ }
+ }
+ else
+ {
+ init_fl_rule(data->iptype);
+ }
+ return IPACM_SUCCESS;
+}
+
+/*duplicate ampdu filter rules for private subnet configuration*/
+int IPACM_Wlan::handle_private_subnet(ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i;
+
+ IPACMDBG("wlan->handle_private_subnet(); set route/filter rule \n");
+
+ if (iptype == IPA_IP_v4)
+ {
+ /* construct ipa_ioc_add_flt_rule with 1 rules */
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ PERROR("WLAN m_routing.GetRoutingTable(IPACM_Iface::ipacmcfg->rt_tbl_lan_v4) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+ memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ }
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ };
+
+
+ /* copy filter hdls */
+ for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+ {
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + i] = IPA_IP_v4;
+ }
+ wlan_ampdu_flt_rule.num_rules += IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+ IPACMDBG("wlan handle private ok~\n");
+ free(m_pFilteringTable);
+ }
+ return IPACM_SUCCESS;
+}
+
+
+/*handle wlan iface down event*/
+int IPACM_Wlan::handle_down_evt()
+{
+ IPACMDBG("ip-type: %d \n", ip_type);
+ uint32_t tx_index, rt_hdl;
+ ipa_ip_type ip;
+ int res = IPACM_SUCCESS, i;
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ IPACMERR("Invalid iptype: 0x%x\n", ip_type);
+ return IPACM_FAILURE;
+ }
+
+ /* Delete v6 filtering rules */
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG("Delete default v4 filter rules\n");
+ /* delete default filter rules */
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+ IPA_IP_v4,
+ IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("Delete private v4 filter rules\n");
+ /* free private-ipv4 filter rules */
+ if (m_filtering.DeleteFilteringHdls(
+ private_fl_rule_hdl,
+ IPA_IP_v4,
+ IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* Delete v4 filtering rules */
+ if (ip_type != IPA_IP_v4)
+ {
+ IPACMDBG("Delete default %d v6 filter rules\n", IPV6_DEFAULT_FILTERTING_RULES);
+ /* delete default filter rules */
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+ IPA_IP_v6,
+ IPV6_DEFAULT_FILTERTING_RULES) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ IPACMDBG("finished delte default filtering rules\n ");
+
+ /* delete WLAN IPA_CLIENT_A5_WLAN_AMPDU_PROD filter rules*/
+ for (i = 3; i < wlan_ampdu_flt_rule.num_rules; i++)
+ {
+ IPACMDBG("Delete WLAN IPA_CLIENT_A5_WLAN_AMPDU_PROD filter rules\n");
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[i],
+ wlan_ampdu_flt_rule.ip[i], 1) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ IPACMDBG("finished delte AMPDU filtering rules\n ");
+
+
+ /* Delete default v4 RT rule */
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG("Delete default v4 routing rules\n");
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* Delete default v6 RT rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ IPACMDBG("Delete default v6 routing rules\n");
+ /* May have multiple ipv6 iface-RT rules */
+ for (i = 0; i < num_dft_rt; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[i + 1], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+ IPACMDBG("finished deleting default RT rules\n ");
+
+
+ /* delete wan filter rule */
+ if (IPACM_Wan::isWanUP())
+ {
+ IPACMDBG("Delete wan filtering rules\n");
+
+ IPACM_Lan::handle_wan_down();
+ handle_wan_down();
+ }
+ IPACMDBG("finished deleting wan filtering rules\n ");
+
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true)
+ {
+ IPACMDBG("Delete sw routing filtering rules\n");
+ IPACM_Iface::handle_software_routing_disable();
+ handle_software_routing_disable();
+ }
+ IPACMDBG("finished delete software-routing filtering rules\n ");
+
+
+ /* clean wifi-client header, routing rules */
+ /* clean wifi client rule*/
+ IPACMDBG("left %d wifi clients need to be deleted \n ", num_wifi_client);
+ for (i = 0; i < num_wifi_client; i++)
+ {
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (ip_type != IPA_IP_v6) /* for ipv4 */
+ {
+ rt_hdl = get_client_memptr(wlan_client, i)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+ ip = IPA_IP_v4;
+ }
+ else if (ip_type != IPA_IP_v4) /* for ipv6 */
+ {
+ rt_hdl = get_client_memptr(wlan_client, i)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6;
+ ip = IPA_IP_v6;
+ }
+
+ IPACMDBG("Delete %d client route rule %d\n", num_wifi_client, tx_index);
+ if (m_routing.DeleteRoutingHdl(rt_hdl, ip) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ } /* end of tx-index for loop*/
+
+ IPACMDBG("Delete %d client header\n", num_wifi_client);
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, i)->hdr_hdl)
+ == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ } /* end of for loop */
+
+ /* free the wlan clients cache */
+ IPACMDBG("Free wlan clients cache\n");
+
+fail:
+ free(wlan_client);
+ free(tx_prop);
+ free(rx_prop);
+ free(iface_query);
+
+ return res;
+}
diff --git a/ipacm/src/IPACM_Xml.cpp b/ipacm/src/IPACM_Xml.cpp
new file mode 100644
index 0000000..8871b1d
--- /dev/null
+++ b/ipacm/src/IPACM_Xml.cpp
@@ -0,0 +1,1090 @@
+/*
+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_Xml.cpp
+
+ @brief
+ This file implements the XML specific parsing functionality.
+
+ @Author
+ Skylar Chang/Shihuan Liu
+*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "IPACM_Xml.h"
+#include "IPACM_Log.h"
+#include "IPACM_Netlink.h"
+
+static char* IPACM_read_content_element
+(
+ xmlNode* element
+);
+
+static int32_t IPACM_util_icmp_string
+(
+ const char* xml_str,
+ const char* str
+);
+
+static int ipacm_cfg_xml_parse_tree
+(
+ xmlNode* xml_node,
+ IPACM_conf_t *config
+);
+
+static int IPACM_firewall_xml_parse_tree
+(
+ xmlNode* xml_node,
+ IPACM_firewall_conf_t *config
+);
+
+/*Reads content (stored as child) of the element */
+static char* IPACM_read_content_element
+(
+ xmlNode* element
+)
+{
+ xmlNode* child_ptr;
+
+ for (child_ptr = element->children;
+ child_ptr != NULL;
+ child_ptr = child_ptr->next)
+ {
+ if (child_ptr->type == XML_TEXT_NODE)
+ {
+ return (char*)child_ptr->content;
+ }
+ }
+ return NULL;
+}
+
+/* insensitive comparison of a libxml's string (xml_str) and a regular string (str)*/
+static int32_t IPACM_util_icmp_string
+(
+ const char* xml_str,
+ const char* str
+)
+{
+ int32_t ret = -1;
+
+ if (NULL != xml_str && NULL != str)
+ {
+ uint32_t len1 = strlen(str);
+ uint32_t len2 = strlen(xml_str);
+ /* If the lengths match, do the string comparison */
+ if (len1 == len2)
+ {
+ ret = strncasecmp(xml_str, str, len1);
+ }
+ }
+
+ return ret;
+}
+
+/* This function read IPACM XML and populate the IPA CM Cfg */
+int ipacm_read_cfg_xml(char *xml_file, IPACM_conf_t *config)
+{
+ xmlDocPtr doc = NULL;
+ xmlNode* root = NULL;
+ int ret_val;
+
+ /* Invoke the XML parser and obtain the parse tree */
+ doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+ if (doc == NULL) {
+ IPACMDBG("IPACM_xml_parse: libxml returned parse error!\n");
+ return IPACM_FAILURE;
+ }
+
+ /*Get the root of the tree*/
+ root = xmlDocGetRootElement(doc);
+
+ memset(config, 0, sizeof(IPACM_conf_t));
+
+ /* parse the xml tree returned by libxml */
+ ret_val = ipacm_cfg_xml_parse_tree(root, config);
+
+ if (ret_val != IPACM_SUCCESS)
+ IPACMDBG("IPACM_xml_parse: ipacm_cfg_xml_parse_tree returned parse error!\n");
+
+ /* Free up the libxml's parse tree */
+ xmlFreeDoc(doc);
+ //xmlCleanupParser();
+
+ return ret_val;
+}
+
+/* This function traverses the xml tree*/
+static int ipacm_cfg_xml_parse_tree
+(
+ xmlNode* xml_node,
+ IPACM_conf_t *config
+)
+{
+ int32_t ret_val = IPACM_SUCCESS;
+ int str_size;
+ char* content;
+ char content_buf[MAX_XML_STR_LEN];
+
+ if (NULL == xml_node)
+ return ret_val;
+
+ while ( xml_node != NULL &&
+ ret_val == IPACM_SUCCESS)
+ {
+ switch (xml_node->type)
+ {
+ case XML_ELEMENT_NODE:
+ {
+ if (IPACM_util_icmp_string((char*)xml_node->name,
+ system_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMCFG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMIFACECFG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IFACE_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMPRIVATESUBNETCFG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ SUBNET_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMALG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ ALG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMNat_TAG) == 0)
+ {
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IFACE_TAG))
+ {
+ /* increase iface entry number */
+ config->iface_config.num_iface_entries++;
+ }
+
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ SUBNET_TAG))
+ {
+ /* increase iface entry number */
+ config->private_subnet_config.num_subnet_entries++;
+ }
+
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ ALG_TAG))
+ {
+ /* increase iface entry number */
+ config->alg_config.num_alg_entries++;
+ }
+ /* go to child */
+ ret_val = ipacm_cfg_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ NAME_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ strncpy(config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name, content_buf, str_size);
+ IPACMDBG("Name %s\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name);
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ CATEGORY_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if (0 == strncasecmp(content_buf, WANIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = WAN_IF;
+ IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, LANIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = LAN_IF;
+ IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, WLANIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = WLAN_IF;
+ IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, VIRTUALIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = VIRTUAL_IF;
+ IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ SUBNETADDRESS_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("subnet_addr: %s \n", content_buf);
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ SUBNETMASK_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("subnet_mask: %s \n", content_buf);
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ Protocol_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+
+ if (0 == strncasecmp(content_buf, TCP_PROTOCOL_TAG, str_size))
+ {
+ config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol = IPPROTO_TCP;
+ IPACMDBG("Protocol %s: %d\n", content_buf, config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol);
+ }
+ else if (0 == strncasecmp(content_buf, UDP_PROTOCOL_TAG, str_size))
+ {
+ config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol = IPPROTO_UDP;
+ IPACMDBG("Protocol %s: %d\n", content_buf, config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol);
+ }
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ Port_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].port
+ = atoi(content_buf);
+ IPACMDBG("port %d\n", config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].port);
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ NAT_MaxEntries_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->nat_max_entries = atoi(content_buf);
+ IPACMDBG("Nat Table Max Entries %d\n", config->nat_max_entries);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ /* go to sibling */
+ xml_node = xml_node->next;
+ } /* end while */
+ return ret_val;
+}
+
+/* This function read QCMAP CM Firewall XML and populate the QCMAP CM Cfg */
+int IPACM_read_firewall_xml(char *xml_file, IPACM_firewall_conf_t *config)
+{
+ xmlDocPtr doc = NULL;
+ xmlNode* root = NULL;
+ int ret_val;
+
+ IPACM_ASSERT(xml_file != NULL);
+ IPACM_ASSERT(config != NULL);
+
+ /* invoke the XML parser and obtain the parse tree */
+ doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+ if (doc == NULL) {
+ IPACMDBG("IPACM_xml_parse: libxml returned parse error\n");
+ return IPACM_FAILURE;
+ }
+ /*get the root of the tree*/
+ root = xmlDocGetRootElement(doc);
+
+ /* parse the xml tree returned by libxml*/
+ ret_val = IPACM_firewall_xml_parse_tree(root, config);
+
+ if (ret_val != IPACM_SUCCESS)
+ IPACMDBG("IPACM_xml_parse: ipacm_firewall_xml_parse_tree returned parse error!\n");
+
+ /* free the tree */
+ xmlFreeDoc(doc);
+
+ return ret_val;
+}
+
+
+/* This function traverses the firewall xml tree */
+static int IPACM_firewall_xml_parse_tree
+(
+ xmlNode* xml_node,
+ IPACM_firewall_conf_t *config
+)
+{
+ int mask_value_v6, mask_index;
+ int32_t ret_val = IPACM_SUCCESS;
+ char *content;
+ int str_size;
+ char content_buf[MAX_XML_STR_LEN];
+ struct in6_addr ip6_addr;
+
+ IPACM_ASSERT(config != NULL);
+
+ if (NULL == xml_node)
+ return ret_val;
+
+ while ( xml_node != NULL &&
+ ret_val == IPACM_SUCCESS)
+ {
+ switch (xml_node->type)
+ {
+
+ case XML_ELEMENT_NODE:
+ {
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ system_TAG) ||
+ 0 == IPACM_util_icmp_string((char*)xml_node->name,
+ MobileAPFirewallCfg_TAG) ||
+ 0 == IPACM_util_icmp_string((char*)xml_node->name,
+ Firewall_TAG)
+ )
+ {
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ Firewall_TAG))
+ {
+ /* increase firewall entry num */
+ config->num_extd_firewall_entries++;
+ }
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPFamily_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].ip_vsn
+ = (firewall_ip_version_enum)atoi(content_buf);
+ IPACMDBG("\n IP family type is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].ip_vsn);
+
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4SourceAddress_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4SourceIPAddress_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("IPv4 source address is: %s \n", content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4SourceSubnetMask_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("IPv4 source subnet mask is: %s \n", content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4DestinationAddress_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4DestinationIPAddress_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("IPv4 destination address is: %s \n", content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4DestinationSubnetMask_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("IPv4 destination subnet mask is: %s \n", content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4TypeOfService_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TOS;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TOSValue_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos
+ = atoi(content_buf);
+
+ IPACMDBG("\n IPV4 TOS val is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TOSMask_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos
+ &= atoi(content_buf);
+
+ IPACMDBG("\n IPv4 TOS mask is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4NextHeaderProtocol_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.protocol = atoi(content_buf);
+
+ IPACMDBG("\n IPv4 next header prot is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.protocol);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6SourceAddress_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |=
+ IPA_FLT_SRC_ADDR;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6SourceIPAddress_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ inet_pton(AF_INET6, content_buf, &ip6_addr);
+ memcpy(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr,
+ ip6_addr.s6_addr, IPACM_IPV6_ADDR_LEN * sizeof(uint8_t));
+
+ IPACMDBG("\n ipv6 source addr is %d \n ",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[0]);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6SourcePrefix_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ mask_value_v6 = atoi(content_buf);
+ for (mask_index = 0; mask_index < 4; mask_index++)
+ {
+ if (mask_value_v6 >= 32)
+ {
+ mask_v6(32, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr_mask[mask_index]));
+ mask_value_v6 -= 32;
+ }
+ else
+ {
+ mask_v6(mask_value_v6, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr_mask[mask_index]));
+ mask_value_v6 = 0;
+ }
+ }
+ IPACMDBG("\n ipv6 source prefix is %d \n",
+ atoi(content_buf));
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6DestinationAddress_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |=
+ IPA_FLT_DST_ADDR;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6DestinationIPAddress_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ inet_pton(AF_INET6, content_buf, &ip6_addr);
+
+ memcpy(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr,
+ ip6_addr.s6_addr, IPACM_IPV6_ADDR_LEN * sizeof(uint8_t));
+ IPACMDBG("\n ipv6 dest addr is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[0]);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6DestinationPrefix_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ mask_value_v6 = atoi(content_buf);
+ for (mask_index = 0; mask_index < 4; mask_index++)
+ {
+ if (mask_value_v6 >= 32)
+ {
+ mask_v6(32, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr_mask[mask_index]));
+ mask_value_v6 -= 32;
+ }
+ else
+ {
+ mask_v6(mask_value_v6, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr_mask[mask_index]));
+ mask_value_v6 = 0;
+ }
+ }
+ IPACMDBG("\n ipv6 dest prefix is %d \n",
+ atoi(content_buf));
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6TrafficClass_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TC;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TrfClsValue_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc
+ = atoi(content_buf);
+ IPACMDBG("\n ipv6 trf class val is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TrfClsMask_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc
+ &= atoi(content_buf);
+
+ IPACMDBG("\n ipv6 trf class mask is %d \n",
+ atoi(content_buf));
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6NextHeaderProtocol_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.next_hdr
+ = atoi(content_buf);
+ IPACMDBG("\n ipv6 next header protocol is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.next_hdr);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPSource_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPSourcePort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPSourceRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if (atoi(content_buf) != 0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = 0;
+ IPACMDBG("\n tcp source port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+ IPACMDBG("\n tcp source port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPDestination_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPDestinationPort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPDestinationRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = 0;
+ IPACMDBG("\n tcp dest port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+ IPACMDBG("\n tcp dest port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPSource_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPSourcePort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPSourceRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = 0;
+ IPACMDBG("\n udp source port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+ IPACMDBG("\n udp source port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPDestination_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPDestinationPort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPDestinationRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = 0;
+ IPACMDBG("\n UDP dest port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+ IPACMDBG("\n UDP dest port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ ICMPType_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.type = atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TYPE;
+ IPACMDBG("\n icmp type is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.type);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ ICMPCode_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.code = atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_CODE;
+ IPACMDBG("\n icmp code is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.code);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ ESPSPI_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.spi = atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SPI;
+ IPACMDBG("\n esp spi is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.spi);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPSource_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPSourcePort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content,str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPSourceRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = 0;
+ IPACMDBG("\n tcp_udp source port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+ IPACMDBG("\n tcp_udp source port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPDestination_TAG))
+ {
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPDestinationPort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPDestinationRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = 0;
+ IPACMDBG("\n tcp_udp dest port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+ IPACMDBG("\n tcp_udp dest port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ /* go to sibling */
+ xml_node = xml_node->next;
+ } /* end while */
+ return ret_val;
+}
+
+
diff --git a/ipacm/src/IPACM_cfg.xml b/ipacm/src/IPACM_cfg.xml
new file mode 100644
index 0000000..06f20b6
--- /dev/null
+++ b/ipacm/src/IPACM_cfg.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ipacm_cfg.xsd">
+ <IPACM>
+ <IPACMIface>
+ <Iface>
+ <Name>rmnet0</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>rmnet1</Name>
+ <Category>LAN</Category>
+ </Iface>
+ <Iface>
+ <Name>wlan0</Name>
+ <Category>WLAN</Category>
+ </Iface>
+ <Iface>
+ <Name>bridge0</Name>
+ <Category>VIRTUAL</Category>
+ </Iface>
+ </IPACMIface>
+ <IPACMPrivateSubnet>
+ <Subnet>
+ <SubnetAddress>192.168.1.0</SubnetAddress>
+ <SubnetMask>255.255.255.0</SubnetMask>
+ </Subnet>
+ </IPACMPrivateSubnet>
+ <IPACMALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>23</Port>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>250</Port>
+ </ALG>
+ </IPACMALG>
+ <IPACMNAT>
+ <MaxNatEntries>100</MaxNatEntries>
+ </IPACMNAT>
+ </IPACM>
+</system>
diff --git a/ipacm/src/Makefile.am b/ipacm/src/Makefile.am
new file mode 100644
index 0000000..22fa657
--- /dev/null
+++ b/ipacm/src/Makefile.am
@@ -0,0 +1,41 @@
+EXTRA_CPPFLAGS = -DDEBUG
+
+AM_CPPFLAGS = -I./../inc -I$(WORKSPACE)/data-ipa/ipanat/inc -I$(WORKSPACE)/kernel/include -I/usr/include/libxml2
+AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
+
+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
+
+bin_PROGRAMS = ipacm
+
+requiredlibs = -lxml2 -lpthread -lnetfilter_conntrack -lnfnetlink\
+ ../../ipanat/src/libipanat.la
+
+ipacm_LDADD = $(requiredlibs)
+
+LOCAL_MODULE := libipanat
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
+
+etcdir = ${sysconfdir}
+etc_SCRIPTS = IPACM_cfg.xml mobileap_firewall.xml
+
+init_ddir = ${sysconfdir}/init.d
+init_d_SCRIPTS = start_ipacm_le
diff --git a/ipacm/src/mobileap_firewall.xml b/ipacm/src/mobileap_firewall.xml
new file mode 100644
index 0000000..c722511
--- /dev/null
+++ b/ipacm/src/mobileap_firewall.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="mobileap_firewall_cfg.xsd">
+ <MobileAPFirewallCfg>
+ </MobileAPFirewallCfg>
+</system>
diff --git a/ipacm/src/start_ipacm_le b/ipacm/src/start_ipacm_le
new file mode 100755
index 0000000..3541a0b
--- /dev/null
+++ b/ipacm/src/start_ipacm_le
@@ -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