summaryrefslogtreecommitdiff
path: root/data-ipa-cfg-mgr/ipacm
diff options
context:
space:
mode:
authorIsaac Chen <isaacchen@isaacchen.cn>2018-07-13 10:13:25 +0800
committerIsaac Chen <isaacchen@isaacchen.cn>2018-07-13 00:03:17 +0000
commit2c422cb5c2bd2b93ec56ed970df0051be54f2039 (patch)
tree2ad31de70b24fbe3dcfe10de8e951b8694aaee9b /data-ipa-cfg-mgr/ipacm
parent6a15b2379f90ba4f9222fea0a5f8c12e8cecbae5 (diff)
wayne: Import IPACM
* QC Tag: LA.UM.6.2.r1-06100-sdm660.0 Change-Id: I8209c81b5c05f618450248e88226d216935a8bcd Signed-off-by: Isaac Chen <isaacchen@isaacchen.cn>
Diffstat (limited to 'data-ipa-cfg-mgr/ipacm')
-rw-r--r--data-ipa-cfg-mgr/ipacm/Android.mk1
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_CmdQueue.h109
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Config.h359
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_ConntrackClient.h111
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_ConntrackListener.h123
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Conntrack_NATApp.h133
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Defs.h381
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_EvtDispatcher.h76
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Filtering.h76
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Header.h70
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Iface.h153
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_IfaceManager.h90
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Lan.h438
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_LanToLan.h282
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Listener.h54
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Log.h102
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Neighbor.h83
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Netlink.h223
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_OffloadManager.h123
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Routing.h78
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Wan.h574
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Wlan.h240
-rw-r--r--data-ipa-cfg-mgr/ipacm/inc/IPACM_Xml.h303
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/Android.mk120
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_CmdQueue.cpp207
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Config.cpp849
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_ConntrackClient.cpp741
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_ConntrackListener.cpp1203
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Conntrack_NATApp.cpp1022
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_EvtDispatcher.cpp214
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Filtering.cpp535
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Header.cpp236
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Iface.cpp1029
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_IfaceManager.cpp579
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Lan.cpp5568
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_LanToLan.cpp2081
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Log.cpp102
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Main.cpp1050
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Neighbor.cpp580
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp1775
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp764
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Routing.cpp276
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Wan.cpp6232
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Wlan.cpp2228
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Xml.cpp1173
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_cfg.xml175
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/Makefile.am55
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/mobileap_firewall.xml7
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/start_ipacm_le57
49 files changed, 33040 insertions, 0 deletions
diff --git a/data-ipa-cfg-mgr/ipacm/Android.mk b/data-ipa-cfg-mgr/ipacm/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_CmdQueue.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_CmdQueue.h
new file mode 100644
index 0000000..27d7c8b
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_CmdQueue.h
@@ -0,0 +1,109 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_CmdQueue.h
+
+ @brief
+ This file implements the IPAM Comment Queue definitions
+
+ @Author
+
+*/
+#ifndef IPA_CONNTRACK_MESSAGE_H
+#define IPA_CONNTRACK_MESSAGE_H
+
+#include <pthread.h>
+#include "IPACM_Defs.h"
+
+
+
+/*---------------------------------------------------------------------------
+ Event data required by IPA_CM
+---------------------------------------------------------------------------*/
+
+
+typedef struct _ipacm_cmd_q_data {
+ ipa_cm_event_id event;
+ void *evt_data;
+}ipacm_cmd_q_data;
+
+typedef struct cmd_s
+{
+ void (*callback_ptr)(ipacm_cmd_q_data *);
+ ipacm_cmd_q_data data;
+}cmd_t;
+
+class Message
+{
+private:
+ Message *m_next;
+
+public:
+ cmd_t evt;
+
+ Message()
+ {
+ m_next = NULL;
+ evt.callback_ptr = NULL;
+ }
+ ~Message() { }
+ void setnext(Message *item) { m_next = item; }
+ Message* getnext() { return m_next; }
+};
+
+class MessageQueue
+{
+
+private:
+ Message *Head;
+ Message *Tail;
+ Message* dequeue(void);
+ static MessageQueue *inst_internal;
+ static MessageQueue *inst_external;
+
+ MessageQueue()
+ {
+ Head = NULL;
+ Tail = NULL;
+ }
+
+public:
+
+ ~MessageQueue() { }
+ void enqueue(Message *item);
+
+ static void* Process(void *);
+ static MessageQueue* getInstanceInternal();
+ static MessageQueue* getInstanceExternal();
+
+};
+
+#endif /* IPA_CONNTRACK_MESSAGE_H */
+
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Config.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Config.h
new file mode 100644
index 0000000..1aeeec5
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Config.h
@@ -0,0 +1,359 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Config.h
+
+ @brief
+ This file implements the IPACM Configuration from XML file
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPACM_CONFIG_H
+#define IPACM_CONFIG_H
+
+#include "IPACM_Defs.h"
+#include "IPACM_Xml.h"
+#include "IPACM_EvtDispatcher.h"
+
+typedef struct
+{
+ char iface_name[IPA_IFACE_NAME_LEN];
+}NatIfaces;
+
+/* for IPACM rm dependency use*/
+typedef struct _ipa_rm_client
+{
+ ipa_rm_resource_name producer_rm1;
+ ipa_rm_resource_name consumer_rm1;
+ ipa_rm_resource_name producer_rm2;
+ ipa_rm_resource_name consumer_rm2;
+ bool producer1_up; /* only monitor producer_rm1, not monitor producer_rm2 */
+ bool consumer1_up; /* only monitor consumer_rm1, not monitor consumer_rm2 */
+ bool rm_set; /* once producer1_up and consumer1_up, will add bi-directional dependency */
+ bool rx_bypass_ipa; /* support WLAN may not register RX-property, should not add dependency */
+}ipa_rm_client;
+
+#define MAX_NUM_EXT_PROPS 25
+
+/* used to hold extended properties */
+typedef struct
+{
+ uint8_t num_ext_props;
+ ipa_ioc_ext_intf_prop prop[MAX_NUM_EXT_PROPS];
+} ipacm_ext_prop;
+
+/* iface */
+class IPACM_Config
+{
+public:
+
+ /* IPACM ipa_client map to rm_resource*/
+ ipa_rm_resource_name ipa_client_rm_map_tbl[IPA_CLIENT_MAX];
+
+ /* IPACM monitored rm_depency table */
+ ipa_rm_client ipa_rm_tbl[IPA_MAX_RM_ENTRY];
+
+ /* IPACM rm_depency a2 endpoint check*/
+ int ipa_rm_a2_check;
+
+ /* Store interested interface and their configuration from XML file */
+ ipa_ifi_dev_name_t *iface_table;
+
+ /* Store interested ALG port from XML file */
+ ipacm_alg *alg_table;
+
+ /* Store private subnet configuration from XML file */
+ ipa_private_subnet private_subnet_table[IPA_MAX_PRIVATE_SUBNET_ENTRIES];
+
+ /* Store the non nat iface names */
+ NatIfaces *pNatIfaces;
+
+ /* Store the bridge iface names */
+ char ipa_virtual_iface_name[IPA_IFACE_NAME_LEN];
+
+ /* Store the number of interface IPACM read from XML file */
+ int ipa_num_ipa_interfaces;
+
+ int ipa_num_private_subnet;
+
+ int ipa_num_alg_ports;
+
+ int ipa_nat_max_entries;
+
+ bool ipacm_odu_router_mode;
+
+ bool ipacm_odu_enable;
+
+ bool ipacm_odu_embms_enable;
+
+ bool ipacm_ip_passthrough_mode;
+
+ int ipa_nat_iface_entries;
+
+ /* Store the total number of wlan guest ap configured */
+ int ipa_num_wlan_guest_ap;
+
+ /* Max valid rm entry */
+ int ipa_max_valid_rm_entry;
+
+ /* Store SW-enable or not */
+ bool ipa_sw_rt_enable;
+
+ /* Store bridge mode or not */
+ bool ipa_bridge_enable;
+
+ /* Store bridge netdev mac */
+ uint8_t bridge_mac[IPA_MAC_ADDR_SIZE];
+
+ /* Store the flt rule count for each producer client*/
+ int flt_rule_count_v4[IPA_CLIENT_MAX];
+ int flt_rule_count_v6[IPA_CLIENT_MAX];
+
+ /* IPACM routing table name for v4/v6 */
+ struct ipa_ioc_get_rt_tbl rt_tbl_lan_v4, rt_tbl_wan_v4, rt_tbl_default_v4, rt_tbl_v6, rt_tbl_wan_v6;
+ struct ipa_ioc_get_rt_tbl rt_tbl_wan_dl;
+ struct ipa_ioc_get_rt_tbl rt_tbl_odu_v4, rt_tbl_odu_v6;
+
+ bool isMCC_Mode;
+
+ /* To return the instance */
+ static IPACM_Config* GetInstance();
+
+ const char* getEventName(ipa_cm_event_id event_id);
+
+ inline void increaseFltRuleCount(int index, ipa_ip_type iptype, int increment)
+ {
+ if((index >= IPA_CLIENT_MAX) || (index < 0))
+ {
+ IPACMERR("Index is out of range: %d.\n", index);
+ return;
+ }
+ if(iptype == IPA_IP_v4)
+ {
+ flt_rule_count_v4[index] += increment;
+ IPACMDBG_H("Now num of v4 flt rules on client %d is %d.\n", index, flt_rule_count_v4[index]);
+ }
+ else
+ {
+ flt_rule_count_v6[index] += increment;
+ IPACMDBG_H("Now num of v6 flt rules on client %d is %d.\n", index, flt_rule_count_v6[index]);
+ }
+ return;
+ }
+
+ inline void decreaseFltRuleCount(int index, ipa_ip_type iptype, int decrement)
+ {
+ if((index >= IPA_CLIENT_MAX) || (index < 0))
+ {
+ IPACMERR("Index is out of range: %d.\n", index);
+ return;
+ }
+ if(iptype == IPA_IP_v4)
+ {
+ flt_rule_count_v4[index] -= decrement;
+ IPACMDBG_H("Now num of v4 flt rules on client %d is %d.\n", index, flt_rule_count_v4[index]);
+ }
+ else
+ {
+ flt_rule_count_v6[index] -= decrement;
+ IPACMDBG_H("Now num of v6 flt rules on client %d is %d.\n", index, flt_rule_count_v6[index]);
+ }
+ return;
+ }
+
+ inline int getFltRuleCount(int index, ipa_ip_type iptype)
+ {
+ if((index >= IPA_CLIENT_MAX) || (index < 0))
+ {
+ IPACMERR("Index is out of range: %d.\n", index);
+ return -1;
+ }
+ if(iptype == IPA_IP_v4)
+ {
+ return flt_rule_count_v4[index];
+ }
+ else
+ {
+ return flt_rule_count_v6[index];
+ }
+ }
+
+ inline int GetAlgPortCnt()
+ {
+ return ipa_num_alg_ports;
+ }
+
+ int GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts);
+
+ inline int GetNatMaxEntries(void)
+ {
+ return ipa_nat_max_entries;
+ }
+
+ inline int GetNatIfacesCnt()
+ {
+ return ipa_nat_iface_entries;
+ }
+ int GetNatIfaces(int nPorts, NatIfaces *ifaces);
+
+ /* for IPACM resource manager dependency usage */
+ void AddRmDepend(ipa_rm_resource_name rm1,bool rx_bypass_ipa);
+
+ void DelRmDepend(ipa_rm_resource_name rm1);
+
+ int AddNatIfaces(char *dev_name);
+
+ int DelNatIfaces(char *dev_name);
+
+ int CheckNatIfaces(const char *dev_name);
+
+ inline void SetQmapId(uint8_t id)
+ {
+ qmap_id = id;
+ }
+
+ inline uint8_t GetQmapId()
+ {
+ return qmap_id;
+ }
+
+ int SetExtProp(ipa_ioc_query_intf_ext_props *prop);
+
+ ipacm_ext_prop* GetExtProp(ipa_ip_type ip_type);
+
+ int DelExtProp(ipa_ip_type ip_type);
+
+ int Init(void);
+
+ inline bool isPrivateSubnet(uint32_t ip_addr)
+ {
+ for(int cnt=0; cnt<ipa_num_private_subnet; cnt++)
+ {
+ if(private_subnet_table[cnt].subnet_addr ==
+ (private_subnet_table[cnt].subnet_mask & ip_addr))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+#ifdef FEATURE_IPA_ANDROID
+ inline bool AddPrivateSubnet(uint32_t ip_addr, int ipa_if_index)
+ {
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_fid *data_fid;
+ uint32_t subnet_mask = ~0;
+ for(int cnt=0; cnt<ipa_num_private_subnet; cnt++)
+ {
+ if(private_subnet_table[cnt].subnet_addr == ip_addr)
+ {
+ IPACMDBG("Already has private subnet_addr as: 0x%x in entry(%d) \n", ip_addr, cnt);
+ return true;
+ }
+ }
+
+ if(ipa_num_private_subnet < IPA_MAX_PRIVATE_SUBNET_ENTRIES)
+ {
+ IPACMDBG("Add IPACM private subnet_addr as: 0x%x in entry(%d) \n", ip_addr, ipa_num_private_subnet);
+ private_subnet_table[ipa_num_private_subnet].subnet_addr = ip_addr;
+ private_subnet_table[ipa_num_private_subnet].subnet_mask = (subnet_mask >> 8) << 8;
+ ipa_num_private_subnet++;
+
+ /* IPACM private subnet set changes */
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = ipa_if_index; // already ipa index, not fid index
+ evt_data.event = IPA_PRIVATE_SUBNET_CHANGE_EVENT;
+ evt_data.evt_data = data_fid;
+
+ /* Insert IPA_PRIVATE_SUBNET_CHANGE_EVENT to command queue */
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ return true;
+ }
+ IPACMERR("IPACM private subnet_addr overflow, total entry(%d)\n", ipa_num_private_subnet);
+ return false;
+ }
+
+ inline bool DelPrivateSubnet(uint32_t ip_addr, int ipa_if_index)
+ {
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_fid *data_fid;
+ for(int cnt=0; cnt<ipa_num_private_subnet; cnt++)
+ {
+ if(private_subnet_table[cnt].subnet_addr == ip_addr)
+ {
+ IPACMDBG("Found private subnet_addr as: 0x%x in entry(%d) \n", ip_addr, cnt);
+ for (; cnt < ipa_num_private_subnet - 1; cnt++)
+ {
+ private_subnet_table[cnt].subnet_addr = private_subnet_table[cnt+1].subnet_addr;
+ }
+ ipa_num_private_subnet = ipa_num_private_subnet - 1;
+
+ /* IPACM private subnet set changes */
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = ipa_if_index; // already ipa index, not fid index
+ evt_data.event = IPA_PRIVATE_SUBNET_CHANGE_EVENT;
+ evt_data.evt_data = data_fid;
+
+ /* Insert IPA_PRIVATE_SUBNET_CHANGE_EVENT to command queue */
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ return true;
+ }
+ }
+ IPACMDBG("can't find private subnet_addr as: 0x%x \n", ip_addr);
+ return false;
+ }
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+ static const char *DEVICE_NAME_ODU;
+
+private:
+ static IPACM_Config *pInstance;
+ static const char *DEVICE_NAME;
+ IPACM_Config(void);
+ int m_fd; /* File descriptor of the IPA device node /dev/ipa */
+ uint8_t qmap_id;
+ ipacm_ext_prop ext_prop_v4;
+ ipacm_ext_prop ext_prop_v6;
+};
+
+#endif /* IPACM_CONFIG */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_ConntrackClient.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_ConntrackClient.h
new file mode 100644
index 0000000..16d5b9c
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_ConntrackClient.h
@@ -0,0 +1,111 @@
+/*
+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.
+*/
+
+#ifndef IPACM_CONNTRACK_FILTER_H
+#define IPACM_CONNTRACK_FILTER_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Defs.h"
+
+#ifndef IPACM_DEBUG
+#define IPACM_DEBUG
+#endif
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+#include <sys/inotify.h>
+}
+
+using namespace std;
+
+#define UDP_TIMEOUT_UPDATE 20
+#define BROADCAST_IPV4_ADDR 0xFFFFFFFF
+
+class IPACM_ConntrackClient
+{
+
+private:
+ static IPACM_ConntrackClient *pInstance;
+
+ struct nfct_handle *tcp_hdl;
+ struct nfct_handle *udp_hdl;
+ struct nfct_filter *tcp_filter;
+ struct nfct_filter *udp_filter;
+ static int IPA_Conntrack_Filters_Ignore_Local_Addrs(struct nfct_filter *filter);
+ static int IPA_Conntrack_Filters_Ignore_Bridge_Addrs(struct nfct_filter *filter);
+ static int IPA_Conntrack_Filters_Ignore_Local_Iface(struct nfct_filter *, ipacm_event_iface_up *);
+ IPACM_ConntrackClient();
+
+public:
+ static int IPAConntrackEventCB(enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ void *data);
+
+ static int IPA_Conntrack_UDP_Filter_Init(void);
+ static int IPA_Conntrack_TCP_Filter_Init(void);
+ static void* TCPRegisterWithConnTrack(void *);
+ static void* UDPRegisterWithConnTrack(void *);
+ static void* UDPConnTimeoutUpdate(void *);
+
+ static void UpdateUDPFilters(void *, bool);
+ static void UpdateTCPFilters(void *, bool);
+ static void Read_TcpUdp_Timeout(char *in, int len);
+
+ static IPACM_ConntrackClient* GetInstance();
+
+ static void UNRegisterWithConnTrack(void);
+ int fd_tcp;
+ int fd_udp;
+
+ unsigned int subscrips_tcp;
+ unsigned int subscrips_udp;
+
+#ifdef IPACM_DEBUG
+#define iptodot(X,Y) \
+ IPACMLOG(" %s(0x%x): %d.%d.%d.%d\n", X, Y, ((Y>>24) & 0xFF), ((Y>>16) & 0xFF), ((Y>>8) & 0xFF), (Y & 0xFF));
+#endif
+
+#define log_nat(A,B,C,D,E,F) \
+ IPACMDBG_H("protocol %d Private IP: %d.%d.%d.%d\t Target IP: %d.%d.%d.%d\t private port: %d public port: %d %s",A,((B>>24) & 0xFF), ((B>>16) & 0xFF), ((B>>8) & 0xFF), (B & 0xFF), ((C>>24) & 0xFF), ((C>>16) & 0xFF),((C>>8) & 0xFF),(C & 0xFF),D,E,F);
+
+};
+
+#endif /* IPACM_CONNTRACK_FILTER_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_ConntrackListener.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_ConntrackListener.h
new file mode 100644
index 0000000..d965cf7
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_ConntrackListener.h
@@ -0,0 +1,123 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef IPACM_CONNTRACK_LISTENER
+#define IPACM_CONNTRACK_LISTENER
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_Listener.h"
+#ifdef CT_OPT
+#include "IPACM_LanToLan.h"
+#endif
+
+#define MAX_IFACE_ADDRESS 50
+#define MAX_STA_CLNT_IFACES 10
+#define STA_CLNT_SUBNET_MASK 0xFFFFFF00
+
+using namespace std;
+
+typedef struct _nat_entry_bundle
+{
+ struct nf_conntrack *ct;
+ enum nf_conntrack_msg_type type;
+ nat_table_entry *rule;
+ bool isTempEntry;
+
+}nat_entry_bundle;
+
+class IPACM_ConntrackListener : public IPACM_Listener
+{
+
+private:
+ bool isCTReg;
+ bool isNatThreadStart;
+ bool WanUp;
+ NatApp *nat_inst;
+
+ int NatIfaceCnt;
+ int StaClntCnt;
+ NatIfaces *pNatIfaces;
+ uint32_t nat_iface_ipv4_addr[MAX_IFACE_ADDRESS];
+ uint32_t nonnat_iface_ipv4_addr[MAX_IFACE_ADDRESS];
+ uint32_t sta_clnt_ipv4_addr[MAX_STA_CLNT_IFACES];
+ IPACM_Config *pConfig;
+#ifdef CT_OPT
+ IPACM_LanToLan *p_lan2lan;
+#endif
+
+ void ProcessCTMessage(void *);
+ void ProcessTCPorUDPMsg(struct nf_conntrack *,
+ enum nf_conntrack_msg_type, u_int8_t);
+ void TriggerWANUp(void *);
+ void TriggerWANDown(uint32_t);
+ int CreateNatThreads(void);
+ bool AddIface(nat_table_entry *, bool *);
+ void AddORDeleteNatEntry(const nat_entry_bundle *);
+ void PopulateTCPorUDPEntry(struct nf_conntrack *, uint32_t, nat_table_entry *);
+ void CheckSTAClient(const nat_table_entry *, bool *);
+ int CheckNatIface(ipacm_event_data_all *, bool *);
+ void HandleNonNatIPAddr(void *, bool);
+
+#ifdef CT_OPT
+ void ProcessCTV6Message(void *);
+ void HandleLan2Lan(struct nf_conntrack *,
+ enum nf_conntrack_msg_type, nat_table_entry* );
+#endif
+
+public:
+ char wan_ifname[IPA_IFACE_NAME_LEN];
+ uint32_t wan_ipaddr;
+ bool isStaMode;
+ IPACM_ConntrackListener();
+ void event_callback(ipa_cm_event_id, void *data);
+ inline bool isWanUp()
+ {
+ return WanUp;
+ }
+
+ void HandleNeighIpAddrAddEvt(ipacm_event_data_all *);
+ void HandleNeighIpAddrDelEvt(uint32_t);
+ void HandleSTAClientAddEvt(uint32_t);
+ void HandleSTAClientDelEvt(uint32_t);
+ int CreateConnTrackThreads(void);
+};
+
+extern IPACM_ConntrackListener *CtList;
+
+#endif /* IPACM_CONNTRACK_LISTENER */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Conntrack_NATApp.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Conntrack_NATApp.h
new file mode 100644
index 0000000..e50b316
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -0,0 +1,133 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef IPACM_CONNTRACK_NATAPP_H
+#define IPACM_CONNTRACK_NATAPP_H
+
+#include <string.h> /* for stderror */
+#include <stdlib.h>
+#include <cstdio> /* for perror */
+
+#include "IPACM_Config.h"
+#include "IPACM_Xml.h"
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <ipa_nat_drv.h>
+}
+
+#define MAX_TEMP_ENTRIES 25
+
+#define IPACM_TCP_FULL_FILE_NAME "/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established"
+#define IPACM_UDP_FULL_FILE_NAME "/proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream"
+
+typedef struct _nat_table_entry
+{
+ uint32_t private_ip;
+ uint16_t private_port;
+
+ uint32_t target_ip;
+ uint16_t target_port;
+
+ uint32_t public_ip;
+ uint16_t public_port;
+
+ u_int8_t protocol;
+ uint32_t timestamp;
+
+ bool dst_nat;
+ bool enabled;
+ uint32_t rule_hdl;
+
+}nat_table_entry;
+
+#define CHK_TBL_HDL() if(nat_table_hdl == 0){ return -1; }
+
+class NatApp
+{
+private:
+
+ static NatApp *pInstance;
+
+ nat_table_entry *cache;
+ nat_table_entry temp[MAX_TEMP_ENTRIES];
+ uint32_t pub_ip_addr;
+ uint32_t pub_ip_addr_pre;
+ uint32_t nat_table_hdl;
+
+ int curCnt, max_entries;
+
+ ipacm_alg *pALGPorts;
+ uint16_t nALGPort;
+
+ uint32_t tcp_timeout;
+ uint32_t udp_timeout;
+
+ uint32_t PwrSaveIfs[IPA_MAX_NUM_WIFI_CLIENTS];
+
+ struct nf_conntrack *ct;
+ struct nfct_handle *ct_hdl;
+
+ NatApp();
+ int Init();
+
+ void UpdateCTUdpTs(nat_table_entry *, uint32_t);
+ bool ChkForDup(const nat_table_entry *);
+ bool isAlgPort(uint8_t, uint16_t);
+ void Reset();
+ bool isPwrSaveIf(uint32_t);
+
+public:
+ static NatApp* GetInstance();
+
+ int AddTable(uint32_t);
+ uint32_t GetTableHdl(uint32_t);
+ int DeleteTable(uint32_t);
+
+ int AddEntry(const nat_table_entry *);
+ int DeleteEntry(const nat_table_entry *);
+
+ void UpdateUDPTimeStamp();
+
+ int UpdatePwrSaveIf(uint32_t);
+ int ResetPwrSaveIf(uint32_t);
+ int DelEntriesOnClntDiscon(uint32_t);
+ int DelEntriesOnSTAClntDiscon(uint32_t);
+
+ void Read_TcpUdp_Timeout(void);
+
+ void AddTempEntry(const nat_table_entry *);
+ void CacheEntry(const nat_table_entry *);
+ void DeleteTempEntry(const nat_table_entry *);
+ void FlushTempEntries(uint32_t, bool, bool isDummy = false);
+};
+
+
+
+#endif /* IPACM_CONNTRACK_NATAPP_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Defs.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Defs.h
new file mode 100644
index 0000000..bd47e02
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Defs.h
@@ -0,0 +1,381 @@
+/*
+Copyright (c) 2013-2017, 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_Defs.h
+
+ @brief
+ This file implements the common definitions amon all ifaces.
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPA_CM_DEFS_H
+#define IPA_CM_DEFS_H
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Log.h"
+
+#ifdef USE_GLIB
+#include <glib.h>
+#define strlcpy g_strlcpy
+#define strlcat g_strlcat
+#endif
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+}
+
+#define IF_NAME_LEN 16
+#define IPA_MAX_FILE_LEN 64
+#define IPA_IFACE_NAME_LEN 16
+#define IPA_ALG_PROTOCOL_NAME_LEN 10
+
+#define IPA_WLAN_PARTIAL_HDR_OFFSET 0 // dst mac first then src mac
+#define IPA_ODU_PARTIAL_HDR_OFFSET 8 // dst mac first then src mac
+#define IPA_WLAN_PARTIAL_HDR_NAME_v4 "IEEE802_3_v4"
+#define IPA_WLAN_PARTIAL_HDR_NAME_v6 "IEEE802_3_v6"
+#define IPA_DUMMY_ETH_HDR_NAME_v6 "ETH_dummy_v6"
+#define IPA_WAN_PARTIAL_HDR_NAME_v4 "IEEE802_3_STA_v4"
+#define IPA_WAN_PARTIAL_HDR_NAME_v6 "IEEE802_3_STA_v6"
+#define IPA_ETH_HDR_NAME_v4 "IPACM_ETH_v4"
+#define IPA_ETH_HDR_NAME_v6 "IPACM_ETH_v6"
+#define IPA_ODU_HDR_NAME_v4 "IPACM_ODU_v4"
+#define IPA_ODU_HDR_NAME_v6 "IPACM_ODU_v6"
+
+
+#define IPA_MAX_IFACE_ENTRIES 20
+#define IPA_MAX_PRIVATE_SUBNET_ENTRIES 3
+#define IPA_MAX_ALG_ENTRIES 20
+#define IPA_MAX_RM_ENTRY 6
+
+#define IPV4_ADDR_LINKLOCAL 0xA9FE0000
+#define IPV4_ADDR_LINKLOCAL_MASK 0xFFFF0000
+
+#define V4_DEFAULT_ROUTE_TABLE_NAME "ipa_dflt_rt"
+#define V4_LAN_ROUTE_TABLE_NAME "COMRTBLLANv4"
+#define V4_WAN_ROUTE_TABLE_NAME "WANRTBLv4"
+#define WAN_DL_ROUTE_TABLE_NAME "ipa_dflt_wan_rt"
+#define V6_COMMON_ROUTE_TABLE_NAME "COMRTBLv6"
+#define V6_WAN_ROUTE_TABLE_NAME "WANRTBLv6"
+#define V4_ODU_ROUTE_TABLE_NAME "ODURTBLv4"
+#define V6_ODU_ROUTE_TABLE_NAME "ODURTBLv6"
+
+#define WWAN_QMI_IOCTL_DEVICE_NAME "/dev/wwan_ioctl"
+#define IPA_DEVICE_NAME "/dev/ipa"
+#define MAX_NUM_PROP 2
+
+#ifndef FEATURE_IPA_V3
+#define IPA_MAX_FLT_RULE 50
+#else
+#define IPA_MAX_FLT_RULE 100
+#endif
+
+#define TCP_FIN_SHIFT 16
+#define TCP_SYN_SHIFT 17
+#define TCP_RST_SHIFT 18
+#define NUM_IPV6_PREFIX_FLT_RULE 1
+
+/*---------------------------------------------------------------------------
+ Return values indicating error status
+---------------------------------------------------------------------------*/
+
+#define IPACM_SUCCESS 0 /* Successful operation */
+#define IPACM_FAILURE -1 /* Unsuccessful operation */
+
+#define IPACM_IP_NULL (ipa_ip_type)0xFF
+#define IPACM_INVALID_INDEX (ipa_ip_type)0xFF
+
+#define IPA_MAX_NUM_WIFI_CLIENTS 32
+#define IPA_MAX_NUM_WAN_CLIENTS 10
+#define IPA_MAX_NUM_ETH_CLIENTS 15
+#define IPA_MAX_NUM_AMPDU_RULE 15
+#define IPA_MAC_ADDR_SIZE 6
+
+/*===========================================================================
+ GLOBAL DEFINITIONS AND DECLARATIONS
+===========================================================================*/
+typedef enum
+{
+ IPA_CFG_CHANGE_EVENT, /* NULL */
+ IPA_PRIVATE_SUBNET_CHANGE_EVENT, /* ipacm_event_data_fid */
+ IPA_FIREWALL_CHANGE_EVENT, /* NULL */
+ IPA_LINK_UP_EVENT, /* ipacm_event_data_fid */
+ IPA_LINK_DOWN_EVENT, /* ipacm_event_data_fid */
+ IPA_USB_LINK_UP_EVENT, /* ipacm_event_data_fid */
+ IPA_BRIDGE_LINK_UP_EVENT, /* ipacm_event_data_all */
+ IPA_WAN_EMBMS_LINK_UP_EVENT, /* ipacm_event_data_mac */
+ IPA_ADDR_ADD_EVENT, /* ipacm_event_data_addr */
+ IPA_ADDR_DEL_EVENT, /* no use */
+ IPA_ROUTE_ADD_EVENT, /* ipacm_event_data_addr */
+ IPA_ROUTE_DEL_EVENT, /* ipacm_event_data_addr */
+ IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, /* ipacm_event_data_fid */
+ IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, /* ipacm_event_data_fid */
+ IPA_WLAN_AP_LINK_UP_EVENT, /* ipacm_event_data_mac */
+ IPA_WLAN_STA_LINK_UP_EVENT, /* ipacm_event_data_mac */
+ IPA_WLAN_LINK_DOWN_EVENT, /* ipacm_event_data_mac */
+ IPA_WLAN_CLIENT_ADD_EVENT, /* ipacm_event_data_mac */
+ IPA_WLAN_CLIENT_ADD_EVENT_EX, /* ipacm_event_data_wlan_ex */
+ IPA_WLAN_CLIENT_DEL_EVENT, /* ipacm_event_data_mac */
+ IPA_WLAN_CLIENT_POWER_SAVE_EVENT, /* ipacm_event_data_mac */
+ IPA_WLAN_CLIENT_RECOVER_EVENT, /* ipacm_event_data_mac */
+ IPA_NEW_NEIGH_EVENT, /* ipacm_event_data_all */
+ IPA_DEL_NEIGH_EVENT, /* ipacm_event_data_all */
+ IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, /* ipacm_event_data_all */
+ IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, /* ipacm_event_data_all */
+ IPA_SW_ROUTING_ENABLE, /* NULL */
+ IPA_SW_ROUTING_DISABLE, /* NULL */
+ IPA_PROCESS_CT_MESSAGE, /* ipacm_ct_evt_data */
+ IPA_PROCESS_CT_MESSAGE_V6, /* ipacm_ct_evt_data */
+ IPA_LAN_TO_LAN_NEW_CONNECTION, /* ipacm_event_connection */
+ IPA_LAN_TO_LAN_DEL_CONNECTION, /* ipacm_event_connection */
+ IPA_WLAN_SWITCH_TO_SCC, /* No Data */
+ IPA_WLAN_SWITCH_TO_MCC, /* No Data */
+ IPA_CRADLE_WAN_MODE_SWITCH, /* ipacm_event_cradle_wan_mode */
+ IPA_WAN_XLAT_CONNECT_EVENT, /* ipacm_event_data_fid */
+ IPA_TETHERING_STATS_UPDATE_EVENT, /* ipacm_event_data_fid */
+ IPA_NETWORK_STATS_UPDATE_EVENT, /* ipacm_event_data_fid */
+ IPA_DOWNSTREAM_ADD, /* ipacm_event_ipahal_stream */
+ IPA_DOWNSTREAM_DEL, /* ipacm_event_ipahal_stream */
+
+ IPA_EXTERNAL_EVENT_MAX,
+
+ IPA_HANDLE_WAN_UP, /* ipacm_event_iface_up */
+ IPA_HANDLE_WAN_DOWN, /* ipacm_event_iface_up */
+ IPA_HANDLE_WAN_UP_V6, /* ipacm_event_iface_up */
+ IPA_HANDLE_WAN_DOWN_V6, /* NULL */
+ IPA_HANDLE_WAN_UP_TETHER, /* ipacm_event_iface_up_tehter */
+ IPA_HANDLE_WAN_DOWN_TETHER, /* ipacm_event_iface_up_tehter */
+ IPA_HANDLE_WAN_UP_V6_TETHER, /* ipacm_event_iface_up_tehter */
+ IPA_HANDLE_WAN_DOWN_V6_TETHER, /* ipacm_event_iface_up_tehter */
+ IPA_HANDLE_WLAN_UP, /* ipacm_event_iface_up */
+ IPA_HANDLE_LAN_UP, /* ipacm_event_iface_up */
+ IPA_ETH_BRIDGE_IFACE_UP, /* ipacm_event_eth_bridge*/
+ IPA_ETH_BRIDGE_IFACE_DOWN, /* ipacm_event_eth_bridge*/
+ IPA_ETH_BRIDGE_CLIENT_ADD, /* ipacm_event_eth_bridge */
+ IPA_ETH_BRIDGE_CLIENT_DEL, /* ipacm_event_eth_bridge*/
+ IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH, /* ipacm_event_eth_bridge*/
+ IPA_SSR_NOTICE, /* NULL*/
+#ifdef FEATURE_L2TP
+ IPA_ADD_VLAN_IFACE, /* ipa_ioc_vlan_iface_info */
+ IPA_DEL_VLAN_IFACE, /* ipa_ioc_vlan_iface_info */
+ IPA_ADD_L2TP_VLAN_MAPPING, /* ipa_ioc_l2tp_vlan_mapping_info */
+ IPA_DEL_L2TP_VLAN_MAPPING, /* ipa_ioc_l2tp_vlan_mapping_info */
+ IPA_HANDLE_VLAN_CLIENT_INFO, /* ipacm_event_data_all */
+ IPA_HANDLE_VLAN_IFACE_INFO, /* ipacm_event_data_all */
+#endif
+ IPA_LAN_DELETE_SELF, /* ipacm_event_data_fid */
+ IPACM_EVENT_MAX
+} ipa_cm_event_id;
+
+typedef struct
+{
+ uint8_t num_rule;
+ uint32_t rule_hdl[MAX_NUM_PROP];
+} lan_to_lan_rt_rule_hdl;
+
+typedef enum
+{
+ LAN_IF = 0,
+ WLAN_IF,
+ WAN_IF,
+ VIRTUAL_IF,
+ ETH_IF,
+ EMBMS_IF,
+ ODU_IF,
+ UNKNOWN_IF
+} ipacm_iface_type;
+
+typedef enum
+{
+ ROUTER = 0,
+ BRIDGE
+} ipacm_cradle_iface_mode;
+
+typedef enum
+{
+ FULL,
+ INTERNET
+} ipacm_wlan_access_mode;
+
+typedef struct
+{
+ struct nf_conntrack *ct;
+ enum nf_conntrack_msg_type type;
+}ipacm_ct_evt_data;
+
+typedef struct
+{
+ char iface_name[IPA_IFACE_NAME_LEN];
+ ipacm_iface_type if_cat;
+ ipacm_cradle_iface_mode if_mode;
+ ipacm_wlan_access_mode wlan_mode;
+ int netlink_interface_index;
+} ipa_ifi_dev_name_t;
+
+typedef struct
+{
+ uint32_t subnet_addr;
+ uint32_t subnet_mask;
+} ipa_private_subnet;
+
+
+typedef struct _ipacm_event_data_all
+{
+ enum ipa_ip_type iptype;
+ int if_index;
+ uint32_t ipv4_addr;
+ uint32_t ipv6_addr[4];
+ uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
+ char iface_name[IPA_IFACE_NAME_LEN];
+} ipacm_event_data_all;
+
+class IPACM_Lan;
+
+typedef struct
+{
+ ipacm_cradle_iface_mode cradle_wan_mode;
+} ipacm_event_cradle_wan_mode;
+
+typedef struct
+{
+ IPACM_Lan *p_iface;
+ ipa_ip_type iptype;
+ uint8_t mac_addr[6];
+ char iface_name[IPA_IFACE_NAME_LEN];
+} ipacm_event_eth_bridge;
+
+typedef struct
+{
+ enum ipa_ip_type iptype;
+ uint32_t src_ipv4_addr;
+ uint32_t dst_ipv4_addr;
+ uint32_t src_ipv6_addr[4];
+ uint32_t dst_ipv6_addr[4];
+} ipacm_event_connection;
+
+typedef struct _ipacm_event_data_fid
+{
+ int if_index;
+} ipacm_event_data_fid;
+
+typedef struct
+{
+ ipacm_iface_type if_cat;
+} ipacm_event_data_if_cat;
+
+typedef struct _ipacm_event_data_iptype
+{
+ int if_index;
+ int if_index_tether;
+ enum ipa_ip_type iptype;
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+ uint32_t ipv4_addr_gw;
+ uint32_t ipv6_addr_gw[4];
+#endif
+} ipacm_event_data_iptype;
+
+
+typedef struct _ipacm_event_data_addr
+{
+ enum ipa_ip_type iptype;
+ char iface_name[IPA_IFACE_NAME_LEN];
+ int if_index;
+ uint32_t ipv4_addr_gw;
+ uint32_t ipv4_addr;
+ uint32_t ipv4_addr_mask;
+ uint32_t ipv6_addr[4];
+ uint32_t ipv6_addr_mask[4];
+ uint32_t ipv6_addr_gw[4];
+} ipacm_event_data_addr;
+
+typedef struct _ipacm_event_data_mac
+{
+ int if_index;
+ int ipa_if_cate;
+ uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
+} ipacm_event_data_mac;
+
+typedef struct
+{
+ int if_index;
+ uint8_t num_of_attribs;
+ struct ipa_wlan_hdr_attrib_val attribs[0];
+} ipacm_event_data_wlan_ex;
+
+typedef struct _ipacm_event_iface_up
+{
+ char ifname[IPA_IFACE_NAME_LEN];
+ uint32_t ipv4_addr;
+ uint32_t addr_mask;
+ uint32_t ipv6_prefix[2];
+ bool is_sta;
+ uint8_t xlat_mux_id;
+}ipacm_event_iface_up;
+
+typedef struct _ipacm_event_iface_up_tether
+{
+ uint32_t if_index_tether;
+ uint32_t ipv6_prefix[2];
+ bool is_sta;
+}ipacm_event_iface_up_tehter;
+
+typedef enum
+{
+ Q6_WAN = 0,
+ WLAN_WAN,
+ ECM_WAN
+} ipacm_wan_iface_type;
+
+typedef struct _ipacm_ifacemgr_data
+{
+ int if_index;
+ ipacm_wan_iface_type if_type;
+ uint8_t mac_addr[IPA_MAC_ADDR_SIZE];
+}ipacm_ifacemgr_data;
+
+typedef struct _ipacm_offload_prefix {
+ enum ipa_ip_type iptype;
+ uint32_t v4Addr;
+ uint32_t v4Mask;
+ uint32_t v6Addr[4];
+ uint32_t v6Mask[4];
+} ipacm_offload_prefix;
+
+typedef struct {
+ int if_index;
+ _ipacm_offload_prefix prefix;
+} ipacm_event_ipahal_stream;
+
+#endif /* IPA_CM_DEFS_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_EvtDispatcher.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_EvtDispatcher.h
new file mode 100644
index 0000000..550f4d4
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_EvtDispatcher.h
@@ -0,0 +1,76 @@
+/*
+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.h
+
+ @brief
+ This file implements the IPAM event dispatcher definitions
+
+ @Author
+
+*/
+#ifndef IPACM_EvtDispatcher_H
+#define IPACM_EvtDispatcher_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include "IPACM_Defs.h"
+#include "IPACM_Listener.h"
+
+/* queue */
+typedef struct _cmd_evts
+{
+ ipa_cm_event_id event;
+ IPACM_Listener *obj;
+ //int ipa_interface_index;
+ _cmd_evts *next;
+} cmd_evts;
+
+
+
+class IPACM_EvtDispatcher
+{
+public:
+
+ /* api for all iface instances to register events */
+ static int registr(ipa_cm_event_id event, IPACM_Listener *obj);
+
+ /* api for all iface instances to de-register events */
+ static int deregistr(IPACM_Listener *obj);
+
+ static int PostEvt(ipacm_cmd_q_data *);
+ static void ProcessEvt(ipacm_cmd_q_data *);
+
+private:
+ static cmd_evts *head;
+};
+
+#endif /* IPACM_EvtDispatcher_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Filtering.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Filtering.h
new file mode 100644
index 0000000..9bb8247
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Filtering.h
@@ -0,0 +1,76 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*!
+ @file
+ IPACM_Filtering.h
+
+ @brief
+ This file implements the IPACM filtering definitions
+
+ @Author
+ Skylar Chang
+
+*/
+
+#ifndef IPACM_FILTERING_H
+#define IPACM_FILTERING_H
+
+#include <stdint.h>
+#include <linux/msm_ipa.h>
+#include <IPACM_Defs.h>
+#include <linux/rmnet_ipa_fd_ioctl.h>
+
+class IPACM_Filtering
+{
+public:
+ IPACM_Filtering();
+ ~IPACM_Filtering();
+ bool AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable);
+ bool AddFilteringRuleAfter(struct ipa_ioc_add_flt_rule_after const *ruleTable);
+ bool DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable);
+ bool Commit(enum ipa_ip_type ip);
+ bool Reset(enum ipa_ip_type ip);
+ bool DeviceNodeIsOpened();
+ bool DeleteFilteringHdls(uint32_t *flt_rule_hdls,
+ ipa_ip_type ip,
+ uint8_t num_rules);
+
+ bool AddWanDLFilteringRule(struct ipa_ioc_add_flt_rule const *rule_table_v4, struct ipa_ioc_add_flt_rule const * rule_table_v6, uint8_t mux_id);
+ bool SendFilteringRuleIndex(struct ipa_fltr_installed_notif_req_msg_v01* table);
+ bool ModifyFilteringRule(struct ipa_ioc_mdfy_flt_rule* ruleTable);
+ ipa_filter_action_enum_v01 GetQmiFilterAction(ipa_flt_action action);
+
+private:
+ static const char *DEVICE_NAME;
+ int fd; /* File descriptor of the IPA device node /dev/ipa */
+};
+
+#endif //IPACM_FILTERING_H
+
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Header.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Header.h
new file mode 100644
index 0000000..027c8ff
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Header.h
@@ -0,0 +1,70 @@
+/*
+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_Header.h
+ *
+ * Created on: Jun 20, 2012
+ * Author: tatias
+ */
+
+//////////////////////////////////////////////////////////////////////////////////
+
+#ifndef IPACM_HEADER_H
+#define IPACM_HEADER_H
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+
+//////////////////////////////////////////////////////////////////////////////////
+
+class IPACM_Header
+{
+private:
+ int m_fd;
+public:
+ bool AddHeader(struct ipa_ioc_add_hdr *pHeaderTable);
+ bool DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTable);
+ bool GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct);
+ bool CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct);
+ bool Commit();
+ bool Reset();
+ bool DeleteHeaderHdl(uint32_t hdr_hdl);
+ bool AddHeaderProcCtx(struct ipa_ioc_add_hdr_proc_ctx* pHeader);
+ bool DeleteHeaderProcCtx(uint32_t hdl);
+
+ IPACM_Header();
+ ~IPACM_Header();
+ bool DeviceNodeIsOpened();
+};
+
+
+#endif
+
+
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Iface.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Iface.h
new file mode 100644
index 0000000..2e18f51
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Iface.h
@@ -0,0 +1,153 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_iface.h
+
+ @brief
+ This file implements the basis Iface definitions.
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPACM_IFACE_H
+#define IPACM_IFACE_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Header.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Xml.h"
+#include "IPACM_Log.h"
+#include "IPACM_Config.h"
+#include "IPACM_Defs.h"
+#include <string.h>
+
+/* current support 2 ipv6-address*/
+#define MAX_DEFAULT_v4_ROUTE_RULES 1
+#define MAX_DEFAULT_v6_ROUTE_RULES 2
+#define IPV4_DEFAULT_FILTERTING_RULES 3
+
+#ifdef FEATURE_IPA_ANDROID
+#define IPV6_DEFAULT_FILTERTING_RULES 7
+#else
+#define IPV6_DEFAULT_FILTERTING_RULES 4
+#endif
+
+#define IPV6_DEFAULT_LAN_FILTERTING_RULES 1
+#define IPV6_NUM_ADDR 3
+#define MAX_SOFTWAREROUTING_FILTERTING_RULES 2
+#define INVALID_IFACE -1
+
+/* iface */
+class IPACM_Iface :public IPACM_Listener
+{
+public:
+
+ /* Static class for reading IPACM configuration from XML file*/
+ static IPACM_Config *ipacmcfg;
+
+ /* IPACM interface id */
+ int ipa_if_num;
+
+ /* IPACM interface category */
+ ipacm_iface_type ipa_if_cate;
+
+ /* IPACM interface name */
+ char dev_name[IF_NAME_LEN];
+
+ /* IPACM interface iptype v4, v6 or both */
+ ipa_ip_type ip_type;
+
+ /* IPACM interface v6 ip-address*/
+ uint32_t ipv6_addr[MAX_DEFAULT_v6_ROUTE_RULES][4];
+
+ uint32_t software_routing_fl_rule_hdl[MAX_SOFTWAREROUTING_FILTERTING_RULES];
+
+ bool softwarerouting_act;
+
+ /* IPACM number of default route rules for ipv6*/
+ uint32_t num_dft_rt_v6;
+
+ uint32_t dft_v4fl_rule_hdl[IPV4_DEFAULT_FILTERTING_RULES];
+ uint32_t dft_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES + IPV6_DEFAULT_LAN_FILTERTING_RULES];
+ /* create additional set of v6 RT-rules in Wanv6RT table*/
+ uint32_t dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+2*MAX_DEFAULT_v6_ROUTE_RULES];
+
+ ipa_ioc_query_intf *iface_query;
+ ipa_ioc_query_intf_tx_props *tx_prop;
+ ipa_ioc_query_intf_rx_props *rx_prop;
+
+ virtual int handle_down_evt() = 0;
+
+ virtual int handle_addr_evt(ipacm_event_data_addr *data) = 0;
+
+ IPACM_Iface(int iface_index);
+
+ virtual void event_callback(ipa_cm_event_id event,
+ void *data) = 0;
+
+ /* Query ipa_interface_index by given linux interface_index */
+ static int iface_ipa_index_query(int interface_index);
+
+ /* Query ipa_interface ipv4_addr by given linux interface_index */
+ static void iface_addr_query(int interface_index);
+
+ /*Query the IPA endpoint property */
+ int query_iface_property(void);
+
+ /*Configure the initial filter rules */
+ virtual int init_fl_rule(ipa_ip_type iptype);
+
+ /* Change IP Type.*/
+ void config_ip_type(ipa_ip_type iptype);
+
+ /* Get interface index */
+ virtual int ipa_get_if_index(char * if_name, int * if_index);
+
+ static IPACM_Routing m_routing;
+ static IPACM_Filtering m_filtering;
+ static IPACM_Header m_header;
+
+ /* software routing enable */
+ virtual int handle_software_routing_enable(void);
+
+ /* software routing disable */
+ virtual int handle_software_routing_disable(void);
+
+private:
+
+ static const char *DEVICE_NAME;
+};
+
+#endif /* IPACM_IFACE_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_IfaceManager.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_IfaceManager.h
new file mode 100644
index 0000000..c7184f2
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_IfaceManager.h
@@ -0,0 +1,90 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_IfaceManager.h
+
+ @brief
+ This file implements the IPAM iface_manager definitions
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPACM_IFACEMANAGER_H
+#define IPACM_IFACEMANAGER_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Listener.h"
+#include "IPACM_Iface.h"
+
+#define IPA_INSTANCE_NOT_FOUND 0
+#define IPA_INSTANCE_FOUND 1
+
+/* queue */
+typedef struct _iface_instances
+{
+ /* Linux interface id */
+ int ipa_if_index;
+ IPACM_Listener *obj;
+ _iface_instances *next;
+} iface_instances;
+
+
+class IPACM_IfaceManager : public IPACM_Listener
+{
+
+public:
+
+ IPACM_IfaceManager();
+
+ void event_callback(ipa_cm_event_id event,
+ void *data);
+
+ /* api for all iface instances to de-register instances */
+ static int deregistr(IPACM_Listener *param);
+
+
+private:
+ int create_iface_instance(ipacm_ifacemgr_data *);
+
+ /* api to register instances */
+ int registr(int ipa_if_index, IPACM_Listener *obj);
+
+ int SearchInstance(int ipa_if_index);
+
+ static iface_instances *head;
+
+};
+
+#endif /* IPACM_IFACEMANAGER_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Lan.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Lan.h
new file mode 100644
index 0000000..f27cb82
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Lan.h
@@ -0,0 +1,438 @@
+/*
+Copyright (c) 2013-2017, 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.h
+
+ @brief
+ This file implements the LAN iface definitions
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPACM_LAN_H
+#define IPACM_LAN_H
+
+#include <stdio.h>
+#include <linux/msm_ipa.h>
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Config.h"
+#include "IPACM_Conntrack_NATApp.h"
+
+#define IPA_WAN_DEFAULT_FILTER_RULE_HANDLES 1
+#define IPA_PRIV_SUBNET_FILTER_RULE_HANDLES 3
+#define IPA_NUM_ODU_ROUTE_RULES 2
+#define MAX_WAN_UL_FILTER_RULES MAX_NUM_EXT_PROPS
+#define NUM_IPV4_ICMP_FLT_RULE 1
+#define NUM_IPV6_ICMP_FLT_RULE 1
+
+/* ndc bandwidth ipatetherstats <ifaceIn> <ifaceOut> */
+/* <in->out_bytes> <in->out_pkts> <out->in_bytes> <out->in_pkts */
+
+#define PIPE_STATS "%s %s %llu %llu %llu %llu"
+#define IPA_PIPE_STATS_FILE_NAME "/data/misc/ipa/tether_stats"
+
+/* store each lan-iface unicast routing rule and its handler*/
+struct ipa_lan_rt_rule
+{
+ ipa_ip_type ip;
+ uint32_t v4_addr;
+ uint32_t v4_addr_mask;
+ uint32_t v6_addr[4];
+ uint32_t rt_rule_hdl[0];
+};
+
+/* Support multiple eth client */
+typedef struct _eth_client_rt_hdl
+{
+ uint32_t eth_rt_rule_hdl_v4;
+ uint32_t eth_rt_rule_hdl_v6[IPV6_NUM_ADDR];
+ uint32_t eth_rt_rule_hdl_v6_wan[IPV6_NUM_ADDR];
+}eth_client_rt_hdl;
+
+typedef struct _ipa_eth_client
+{
+ uint8_t mac[IPA_MAC_ADDR_SIZE];
+ uint32_t v4_addr;
+ uint32_t v6_addr[IPV6_NUM_ADDR][4];
+ uint32_t hdr_hdl_v4;
+ uint32_t hdr_hdl_v6;
+ bool route_rule_set_v4;
+ int route_rule_set_v6;
+ bool ipv4_set;
+ int ipv6_set;
+ bool ipv4_header_set;
+ bool ipv6_header_set;
+ eth_client_rt_hdl eth_rt_hdl[0]; /* depends on number of tx properties */
+}ipa_eth_client;
+
+
+/* lan iface */
+class IPACM_Lan : public IPACM_Iface
+{
+public:
+
+ IPACM_Lan(int iface_index);
+ ~IPACM_Lan();
+
+ /* store lan's wan-up filter rule handlers */
+ uint32_t lan_wan_fl_rule_hdl[IPA_WAN_DEFAULT_FILTER_RULE_HANDLES];
+
+ /* store private-subnet filter rule handlers */
+ uint32_t private_fl_rule_hdl[IPA_MAX_PRIVATE_SUBNET_ENTRIES];
+
+ /* LAN-iface's callback function */
+ void event_callback(ipa_cm_event_id event, void *data);
+
+ virtual int handle_wan_up(ipa_ip_type ip_type);
+
+ /* configure filter rule for wan_up event*/
+ virtual int handle_wan_up_ex(ipacm_ext_prop* ext_prop, ipa_ip_type iptype, uint8_t xlat_mux_id);
+
+ /* delete filter rule for wan_down event*/
+ virtual int handle_wan_down(bool is_sta_mode);
+
+ /* delete filter rule for wan_down event*/
+ virtual int handle_wan_down_v6(bool is_sta_mode);
+
+ /* configure private subnet filter rules*/
+ virtual int handle_private_subnet(ipa_ip_type iptype);
+
+ /* handle new_address event*/
+ int handle_addr_evt(ipacm_event_data_addr *data);
+
+ int handle_addr_evt_odu_bridge(ipacm_event_data_addr* data);
+
+ int handle_del_ipv6_addr(ipacm_event_data_all *data);
+
+ static bool odu_up;
+
+ /* install UL filter rule from Q6 */
+ virtual int handle_uplink_filter_rule(ipacm_ext_prop* prop, ipa_ip_type iptype, uint8_t xlat_mux_id);
+
+ int handle_cradle_wan_mode_switch(bool is_wan_bridge_mode);
+
+ int install_ipv4_icmp_flt_rule();
+
+
+ /* add header processing context and return handle to lan2lan controller */
+ int eth_bridge_add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_hdr_type, uint32_t *hdl);
+
+ /* add routing rule and return handle to lan2lan controller */
+ int eth_bridge_add_rt_rule(uint8_t *mac, char *rt_tbl_name, uint32_t hdr_proc_ctx_hdl,
+ ipa_hdr_l2_type peer_l2_hdr_type, ipa_ip_type iptype, uint32_t *rt_rule_hdl, int *rt_rule_count);
+
+ /* modify routing rule*/
+ int eth_bridge_modify_rt_rule(uint8_t *mac, uint32_t hdr_proc_ctx_hdl,
+ ipa_hdr_l2_type peer_l2_hdr_type, ipa_ip_type iptype, uint32_t *rt_rule_hdl, int rt_rule_count);
+
+ /* add filtering rule and return handle to lan2lan controller */
+ int eth_bridge_add_flt_rule(uint8_t *mac, uint32_t rt_tbl_hdl, ipa_ip_type iptype, uint32_t *flt_rule_hdl);
+
+ /* delete filtering rule */
+ int eth_bridge_del_flt_rule(uint32_t flt_rule_hdl, ipa_ip_type iptype);
+
+ /* delete routing rule */
+ int eth_bridge_del_rt_rule(uint32_t rt_rule_hdl, ipa_ip_type iptype);
+
+ /* delete header processing context */
+ int eth_bridge_del_hdr_proc_ctx(uint32_t hdr_proc_ctx_hdl);
+
+#ifdef FEATURE_L2TP
+ /* add l2tp rt rule for l2tp client */
+ int add_l2tp_rt_rule(ipa_ip_type iptype, uint8_t *dst_mac, ipa_hdr_l2_type peer_l2_hdr_type,
+ uint32_t l2tp_session_id, uint32_t vlan_id, uint8_t *vlan_client_mac, uint32_t *vlan_iface_ipv6_addr,
+ uint32_t *vlan_client_ipv6_addr, uint32_t *first_pass_hdr_hdl, uint32_t *first_pass_hdr_proc_ctx_hdl,
+ uint32_t *second_pass_hdr_hdl, int *num_rt_hdl, uint32_t *first_pass_rt_rule_hdl, uint32_t *second_pass_rt_rule_hdl);
+
+ /* delete l2tp rt rule for l2tp client */
+ int del_l2tp_rt_rule(ipa_ip_type iptype, uint32_t first_pass_hdr_hdl, uint32_t first_pass_hdr_proc_ctx_hdl,
+ uint32_t second_pass_hdr_hdl, int num_rt_hdl, uint32_t *first_pass_rt_rule_hdl, uint32_t *second_pass_rt_rule_hdl);
+
+ /* add l2tp rt rule for non l2tp client */
+ int add_l2tp_rt_rule(ipa_ip_type iptype, uint8_t *dst_mac, uint32_t *hdr_proc_ctx_hdl,
+ int *num_rt_hdl, uint32_t *rt_rule_hdl);
+
+ /* delete l2tp rt rule for non l2tp client */
+ int del_l2tp_rt_rule(ipa_ip_type iptype, int num_rt_hdl, uint32_t *rt_rule_hdl);
+
+ /* add l2tp flt rule on l2tp interface */
+ int add_l2tp_flt_rule(uint8_t *dst_mac, uint32_t *flt_rule_hdl);
+
+ /* delete l2tp flt rule on l2tp interface */
+ int del_l2tp_flt_rule(uint32_t flt_rule_hdl);
+
+ /* add l2tp flt rule on non l2tp interface */
+ int add_l2tp_flt_rule(ipa_ip_type iptype, uint8_t *dst_mac, uint32_t *vlan_client_ipv6_addr,
+ uint32_t *first_pass_flt_rule_hdl, uint32_t *second_pass_flt_rule_hdl);
+
+ /* delete l2tp flt rule on non l2tp interface */
+ int del_l2tp_flt_rule(ipa_ip_type iptype, uint32_t first_pass_flt_rule_hdl, uint32_t second_pass_flt_rule_hdl);
+#endif
+
+protected:
+
+ int each_client_rt_rule_count[IPA_IP_MAX];
+
+ uint32_t eth_bridge_flt_rule_offset[IPA_IP_MAX];
+
+ /* mac address has to be provided for client related events */
+ void eth_bridge_post_event(ipa_cm_event_id evt, ipa_ip_type iptype, uint8_t *mac,
+ uint32_t *ipv6_addr, char *iface_name);
+
+#ifdef FEATURE_L2TP
+ /* check if the event is associated with vlan interface */
+ bool is_vlan_event(char *event_iface_name);
+ /* check if the event is associated with l2tp interface */
+ bool is_l2tp_event(char *event_iface_name);
+
+ /* check if the IPv6 address is unique local address */
+ bool is_unique_local_ipv6_addr(uint32_t *ipv6_addr);
+
+#endif
+ virtual int add_dummy_private_subnet_flt_rule(ipa_ip_type iptype);
+
+ int handle_private_subnet_android(ipa_ip_type iptype);
+
+ int reset_to_dummy_flt_rule(ipa_ip_type iptype, uint32_t rule_hdl);
+
+ virtual int install_ipv6_prefix_flt_rule(uint32_t* prefix);
+
+ virtual void delete_ipv6_prefix_flt_rule();
+
+ int install_ipv6_icmp_flt_rule();
+
+ void post_del_self_evt();
+
+ /* handle tethering stats */
+ int handle_tethering_stats_event(ipa_get_data_stats_resp_msg_v01 *data);
+
+ /* handle tethering client */
+ int handle_tethering_client(bool reset, ipacm_client_enum ipa_client);
+
+ /* store ipv4 UL filter rule handlers from Q6*/
+ uint32_t wan_ul_fl_rule_hdl_v4[MAX_WAN_UL_FILTER_RULES];
+
+ /* store ipv6 UL filter rule handlers from Q6*/
+ uint32_t wan_ul_fl_rule_hdl_v6[MAX_WAN_UL_FILTER_RULES];
+
+ uint32_t ipv4_icmp_flt_rule_hdl[NUM_IPV4_ICMP_FLT_RULE];
+
+ uint32_t ipv6_prefix_flt_rule_hdl[NUM_IPV6_PREFIX_FLT_RULE];
+ uint32_t ipv6_icmp_flt_rule_hdl[NUM_IPV6_ICMP_FLT_RULE];
+
+ int num_wan_ul_fl_rule_v4;
+ int num_wan_ul_fl_rule_v6;
+
+ bool is_active;
+ bool modem_ul_v4_set;
+ uint8_t v4_mux_id;
+ bool modem_ul_v6_set;
+ uint8_t v6_mux_id;
+
+ bool sta_ul_v4_set;
+ bool sta_ul_v6_set;
+
+ uint32_t if_ipv4_subnet;
+
+ uint32_t ipv6_prefix[2];
+
+ bool is_upstream_set[IPA_IP_MAX];
+ bool is_downstream_set[IPA_IP_MAX];
+ _ipacm_offload_prefix prefix[IPA_IP_MAX];
+
+private:
+
+ /* get hdr proc ctx type given source and destination l2 hdr type */
+ ipa_hdr_proc_type eth_bridge_get_hdr_proc_type(ipa_hdr_l2_type t1, ipa_hdr_l2_type t2);
+
+ /* get partial header (header template of hdr proc ctx) */
+ int eth_bridge_get_hdr_template_hdl(uint32_t* hdr_hdl);
+
+
+ /* dynamically allocate lan iface's unicast routing rule structure */
+
+ bool is_mode_switch; /* indicate mode switch, need post internal up event */
+
+ int eth_client_len;
+
+ ipa_eth_client *eth_client;
+
+ int header_name_count;
+
+ uint32_t num_eth_client;
+
+ NatApp *Nat_App;
+
+ int ipv6_set;
+
+ uint32_t ODU_hdr_hdl_v4, ODU_hdr_hdl_v6;
+
+ uint32_t *odu_route_rule_v4_hdl;
+
+ uint32_t *odu_route_rule_v6_hdl;
+
+ bool ipv4_header_set;
+
+ bool ipv6_header_set;
+
+ inline ipa_eth_client* get_client_memptr(ipa_eth_client *param, int cnt)
+ {
+ char *ret = ((char *)param) + (eth_client_len * cnt);
+ return (ipa_eth_client *)ret;
+ }
+
+ inline int get_eth_client_index(uint8_t *mac_addr)
+ {
+ int cnt;
+ int num_eth_client_tmp = num_eth_client;
+
+ IPACMDBG_H("Passed 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]);
+
+ for(cnt = 0; cnt < num_eth_client_tmp; cnt++)
+ {
+ IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(eth_client, cnt)->mac[0],
+ get_client_memptr(eth_client, cnt)->mac[1],
+ get_client_memptr(eth_client, cnt)->mac[2],
+ get_client_memptr(eth_client, cnt)->mac[3],
+ get_client_memptr(eth_client, cnt)->mac[4],
+ get_client_memptr(eth_client, cnt)->mac[5]);
+
+ if(memcmp(get_client_memptr(eth_client, cnt)->mac,
+ mac_addr,
+ sizeof(get_client_memptr(eth_client, cnt)->mac)) == 0)
+ {
+ IPACMDBG_H("Matched client index: %d\n", cnt);
+ return cnt;
+ }
+ }
+
+ return IPACM_INVALID_INDEX;
+ }
+
+ inline int delete_eth_rtrules(int clt_indx, ipa_ip_type iptype)
+ {
+ uint32_t tx_index;
+ uint32_t rt_hdl;
+ int num_v6;
+
+ if(iptype == IPA_IP_v4)
+ {
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if((tx_prop->tx[tx_index].ip == IPA_IP_v4) && (get_client_memptr(eth_client, clt_indx)->route_rule_set_v4==true)) /* for ipv4 */
+ {
+ IPACMDBG_H("Delete client index %d ipv4 RT-rules for tx:%d\n",clt_indx,tx_index);
+ rt_hdl = get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4;
+
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v4) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ } /* end of for loop */
+
+ /* clean the ipv4 RT rules for eth-client:clt_indx */
+ if(get_client_memptr(eth_client, clt_indx)->route_rule_set_v4==true) /* for ipv4 */
+ {
+ get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = false;
+ }
+ }
+
+ if(iptype == IPA_IP_v6)
+ {
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 != 0)) /* for ipv6 */
+ {
+ for(num_v6 =0;num_v6 < get_client_memptr(eth_client, clt_indx)->route_rule_set_v6;num_v6++)
+ {
+ IPACMDBG_H("Delete client index %d ipv6 RT-rules for %d-st ipv6 for tx:%d\n", clt_indx,num_v6,tx_index);
+ rt_hdl = get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6];
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ rt_hdl = get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6];
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ }
+ } /* end of for loop */
+
+ /* clean the ipv6 RT rules for eth-client:clt_indx */
+ if(get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 != 0) /* for ipv6 */
+ {
+ get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = 0;
+ }
+ }
+
+ return IPACM_SUCCESS;
+ }
+
+ /* handle eth client initial, construct full headers (tx property) */
+ int handle_eth_hdr_init(uint8_t *mac_addr);
+
+ /* handle eth client ip-address */
+ int handle_eth_client_ipaddr(ipacm_event_data_all *data);
+
+ /* handle eth client routing rule*/
+ int handle_eth_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype);
+
+ /*handle eth client del mode*/
+ int handle_eth_client_down_evt(uint8_t *mac_addr);
+
+ /* handle odu client initial, construct full headers (tx property) */
+ int handle_odu_hdr_init(uint8_t *mac_addr);
+
+ /* handle odu default route rule configuration */
+ int handle_odu_route_add();
+
+ /* handle odu default route rule deletion */
+ int handle_odu_route_del();
+
+ /*handle lan iface down event*/
+ int handle_down_evt();
+
+ /*handle reset usb-client rt-rules */
+ int handle_lan_client_reset_rt(ipa_ip_type iptype);
+};
+
+#endif /* IPACM_LAN_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_LanToLan.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_LanToLan.h
new file mode 100644
index 0000000..e517e97
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_LanToLan.h
@@ -0,0 +1,282 @@
+/*
+Copyright (c) 2014-2017, 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_LanToLan.h
+ *
+ * Created on: Mar 4th, 2014
+ * Author: Shihuan Liu
+ */
+
+#ifndef IPACM_LANTOLAN_H
+#define IPACM_LANTOLAN_H
+
+#include <stdint.h>
+#include "linux/msm_ipa.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Lan.h"
+
+#ifdef FEATURE_IPA_ANDROID
+#include <libxml/list.h>
+#else/* defined(FEATURE_IPA_ANDROID) */
+#include <list>
+#endif /* ndefined(FEATURE_IPA_ANDROID)*/
+
+#define MAX_NUM_CACHED_CLIENT_ADD_EVENT 10
+#define MAX_NUM_IFACE 10
+#define MAX_NUM_CLIENT 16
+
+struct vlan_iface_info
+{
+ char vlan_iface_name[IPA_RESOURCE_NAME_MAX];
+ uint8_t vlan_id;
+ uint32_t vlan_iface_ipv6_addr[4];
+ uint8_t vlan_client_mac[6];
+ uint32_t vlan_client_ipv6_addr[4];
+};
+
+struct l2tp_vlan_mapping_info
+{
+ /* the following are l2tp iface info (name, session id) */
+ char l2tp_iface_name[IPA_RESOURCE_NAME_MAX];
+ uint8_t l2tp_session_id;
+ /* the following are mdm vlan iface info (name, vlan id, ipv6 addr) */
+ char vlan_iface_name[IPA_RESOURCE_NAME_MAX];
+ uint8_t vlan_id;
+ uint32_t vlan_iface_ipv6_addr[4];
+ /* the following are MIB3 vlan client info (mac, ipv6 addr) */
+ uint8_t vlan_client_mac[6];
+ uint32_t vlan_client_ipv6_addr[4];
+ /* the following is MIB3 l2tp client info (mac) */
+ uint8_t l2tp_client_mac[6];
+};
+
+struct rt_rule_info
+{
+ int num_hdl[IPA_IP_MAX]; /* one client may need more than one routing rules on the same routing table depending on tx_prop */
+ uint32_t rule_hdl[IPA_IP_MAX][MAX_NUM_PROP];
+};
+
+struct l2tp_rt_rule_info
+{
+ uint32_t first_pass_hdr_hdl; /* first pass hdr template (IPv4 and IPv6 use the same hdr template) */
+ uint32_t first_pass_hdr_proc_ctx_hdl[IPA_IP_MAX]; /* first pass hdr proc ctx */
+ uint32_t second_pass_hdr_hdl; /* second pass hdr template (IPv4 and IPv6 use the same hdr template) */
+ int num_rt_hdl[IPA_IP_MAX]; /* number of TX properties for IPv4 and IPv6 respectively */
+ uint32_t first_pass_rt_rule_hdl[IPA_IP_MAX][MAX_NUM_PROP]; /* first pass routing rule */
+ uint32_t second_pass_rt_rule_hdl[MAX_NUM_PROP]; /*second pass routing rule (only ipv6 rt rule is needed) */
+};
+
+struct client_info
+{
+ uint8_t mac_addr[6];
+ rt_rule_info inter_iface_rt_rule_hdl[IPA_HDR_L2_MAX]; /* routing rule handles of inter interface communication based on source l2 header type */
+ rt_rule_info intra_iface_rt_rule_hdl; /* routing rule handles of inter interface communication */
+ bool is_l2tp_client;
+ l2tp_vlan_mapping_info *mapping_info;
+ l2tp_rt_rule_info l2tp_rt_rule_hdl[IPA_HDR_L2_MAX];
+};
+
+struct flt_rule_info
+{
+ client_info *p_client;
+ uint32_t flt_rule_hdl[IPA_IP_MAX];
+ uint32_t l2tp_first_pass_flt_rule_hdl[IPA_IP_MAX]; /* L2TP filtering rules are destination MAC based */
+ uint32_t l2tp_second_pass_flt_rule_hdl;
+};
+
+struct peer_iface_info
+{
+ class IPACM_LanToLan_Iface *peer;
+ char rt_tbl_name_for_rt[IPA_IP_MAX][IPA_RESOURCE_NAME_MAX];
+ char rt_tbl_name_for_flt[IPA_IP_MAX][IPA_RESOURCE_NAME_MAX];
+ list<flt_rule_info> flt_rule;
+};
+
+class IPACM_LanToLan_Iface
+{
+public:
+ IPACM_LanToLan_Iface(IPACM_Lan *p_iface);
+ ~IPACM_LanToLan_Iface();
+
+ void add_client_rt_rule_for_new_iface();
+
+ void add_all_inter_interface_client_flt_rule(ipa_ip_type iptype);
+
+ void add_all_intra_interface_client_flt_rule(ipa_ip_type iptype);
+
+ void handle_down_event();
+
+ void handle_wlan_scc_mcc_switch();
+
+ void handle_intra_interface_info();
+
+ void handle_new_iface_up(char rt_tbl_name_for_flt[][IPA_RESOURCE_NAME_MAX], char rt_tbl_name_for_rt[][IPA_RESOURCE_NAME_MAX],
+ IPACM_LanToLan_Iface *peer_iface);
+
+ void handle_client_add(uint8_t *mac, bool is_l2tp_client, l2tp_vlan_mapping_info *mapping_info);
+
+ void handle_client_del(uint8_t *mac);
+
+ void print_data_structure_info();
+
+ IPACM_Lan* get_iface_pointer();
+
+ bool get_m_is_ip_addr_assigned(ipa_ip_type iptype);
+
+ void set_m_is_ip_addr_assigned(ipa_ip_type iptype, bool value);
+
+ bool get_m_support_inter_iface_offload();
+
+ bool get_m_support_intra_iface_offload();
+
+ void increment_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type);
+
+ void decrement_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type);
+#ifdef FEATURE_L2TP
+ void switch_to_l2tp_iface();
+
+ bool set_l2tp_iface(char *vlan_iface_name);
+
+ bool is_l2tp_iface();
+
+ void handle_l2tp_enable();
+
+ void handle_l2tp_disable();
+#endif
+private:
+
+ IPACM_Lan *m_p_iface;
+ bool m_is_ip_addr_assigned[IPA_IP_MAX];
+ bool m_support_inter_iface_offload;
+ bool m_support_intra_iface_offload;
+ bool m_is_l2tp_iface;
+
+ int ref_cnt_peer_l2_hdr_type[IPA_HDR_L2_MAX]; /* reference count of l2 header type of peer interfaces */
+ uint32_t hdr_proc_ctx_for_inter_interface[IPA_HDR_L2_MAX];
+ uint32_t hdr_proc_ctx_for_intra_interface;
+ uint32_t hdr_proc_ctx_for_l2tp; /* uc needs to remove 62 bytes IPv6 + L2TP + inner Ethernet header */
+
+ list<client_info> m_client_info; /* client list */
+ list<peer_iface_info> m_peer_iface_info; /* peer information list */
+
+ /* The following members are for intra-interface communication*/
+ peer_iface_info m_intra_interface_info;
+
+ void add_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client);
+
+ void add_client_flt_rule(peer_iface_info *peer, client_info *client, ipa_ip_type iptype);
+
+ void del_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client);
+
+ void del_client_flt_rule(peer_iface_info *peer, client_info *client);
+
+ void add_client_rt_rule(peer_iface_info *peer, client_info *client);
+
+ void del_client_rt_rule(peer_iface_info *peer, client_info *client);
+
+ void add_l2tp_client_rt_rule(peer_iface_info *peer, client_info *client);
+
+ void clear_all_flt_rule_for_one_peer_iface(peer_iface_info *peer);
+
+ void clear_all_rt_rule_for_one_peer_iface(peer_iface_info *peer);
+
+ void add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type);
+
+ void del_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type);
+
+ void print_peer_info(peer_iface_info *peer_info);
+
+};
+
+class IPACM_LanToLan : public IPACM_Listener
+{
+
+public:
+
+ static IPACM_LanToLan* p_instance;
+ static IPACM_LanToLan* get_instance();
+#ifdef FEATURE_L2TP
+ bool has_l2tp_iface();
+#endif
+
+private:
+
+ IPACM_LanToLan();
+
+ ~IPACM_LanToLan();
+
+ bool m_has_l2tp_iface;
+
+ list<class IPACM_LanToLan_Iface> m_iface;
+
+ list<ipacm_event_eth_bridge> m_cached_client_add_event;
+
+ list<vlan_iface_info> m_vlan_iface;
+
+ list<l2tp_vlan_mapping_info> m_l2tp_vlan_mapping;
+
+ void handle_iface_up(ipacm_event_eth_bridge *data);
+
+ void handle_iface_down(ipacm_event_eth_bridge *data);
+
+ void handle_client_add(ipacm_event_eth_bridge *data);
+
+ void handle_client_del(ipacm_event_eth_bridge *data);
+
+ void handle_wlan_scc_mcc_switch(ipacm_event_eth_bridge *data);
+
+#ifdef FEATURE_L2TP
+ void handle_add_vlan_iface(ipa_ioc_vlan_iface_info *data);
+
+ void handle_del_vlan_iface(ipa_ioc_vlan_iface_info *data);
+
+ void handle_add_l2tp_vlan_mapping(ipa_ioc_l2tp_vlan_mapping_info *data);
+
+ void handle_del_l2tp_vlan_mapping(ipa_ioc_l2tp_vlan_mapping_info *data);
+
+ void handle_vlan_client_info(ipacm_event_data_all *data);
+
+ void handle_vlan_iface_info(ipacm_event_data_all *data);
+#endif
+
+ void handle_new_iface_up(IPACM_LanToLan_Iface *new_iface, IPACM_LanToLan_Iface *exist_iface);
+
+ void event_callback(ipa_cm_event_id event, void* param);
+
+ void handle_cached_client_add_event(IPACM_Lan *p_iface);
+
+ void clear_cached_client_add_event(IPACM_Lan *p_iface);
+
+ void print_data_structure_info();
+
+};
+
+#endif
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Listener.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Listener.h
new file mode 100644
index 0000000..9d774fe
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Listener.h
@@ -0,0 +1,54 @@
+/*
+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_Listener.h
+
+ @brief
+ This file implements the abstract class notifier.
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPACM_LISTENER_H
+#define IPACM_LISTENER_H
+
+#include "IPACM_Defs.h"
+#include "IPACM_CmdQueue.h"
+
+/* abstract class notifier */
+class IPACM_Listener
+{
+public:
+ virtual void event_callback(ipa_cm_event_id event, void *data) = 0;
+ virtual ~IPACM_Listener(void) {};
+};
+
+#endif /* IPACM_LISTENER_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Log.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Log.h
new file mode 100644
index 0000000..dab0280
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Log.h
@@ -0,0 +1,102 @@
+/*
+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.h
+
+ @brief
+ This file implements the IPAM log functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+
+#ifndef IPACM_LOG_H
+#define IPACM_LOG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#define MAX_BUF_LEN 256
+
+#ifdef FEATURE_IPA_ANDROID
+#define IPACMLOG_FILE "/dev/socket/ipacm_log_file"
+#else/* defined(FEATURE_IPA_ANDROID) */
+#define IPACMLOG_FILE "/etc/ipacm_log_file"
+#endif /* defined(NOT FEATURE_IPA_ANDROID)*/
+
+typedef struct ipacm_log_buffer_s {
+ char user_data[MAX_BUF_LEN];
+} ipacm_log_buffer_t;
+
+void ipacm_log_send( void * user_data);
+
+static char buffer_send[MAX_BUF_LEN];
+static char dmesg_cmd[MAX_BUF_LEN];
+
+#define IPACMDBG_DMESG(fmt, ...) memset(buffer_send, 0, MAX_BUF_LEN);\
+ snprintf(buffer_send,MAX_BUF_LEN,"%s:%d %s: " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);\
+ ipacm_log_send (buffer_send);\
+ printf("%s:%d %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
+ memset(dmesg_cmd, 0, MAX_BUF_LEN);\
+ snprintf(dmesg_cmd, MAX_BUF_LEN, "echo %s > /dev/kmsg", buffer_send);\
+ system(dmesg_cmd);
+#ifdef DEBUG
+#define PERROR(fmt) memset(buffer_send, 0, MAX_BUF_LEN);\
+ snprintf(buffer_send,MAX_BUF_LEN,"%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
+ ipacm_log_send (buffer_send); \
+ perror(fmt);
+#define IPACMERR(fmt, ...) memset(buffer_send, 0, MAX_BUF_LEN);\
+ snprintf(buffer_send,MAX_BUF_LEN,"ERROR: %s:%d %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);\
+ ipacm_log_send (buffer_send);\
+ printf("ERROR: %s:%d %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#define IPACMDBG_H(fmt, ...) memset(buffer_send, 0, MAX_BUF_LEN);\
+ snprintf(buffer_send,MAX_BUF_LEN,"%s:%d %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);\
+ ipacm_log_send (buffer_send);\
+ printf("%s:%d %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#else
+#define PERROR(fmt) perror(fmt)
+#define IPACMERR(fmt, ...) printf("ERR: %s:%d %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#define IPACMDBG_H(fmt, ...) printf("%s:%d %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#endif
+#define IPACMDBG(fmt, ...) printf("%s:%d %s() " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#define IPACMLOG(fmt, ...) printf(fmt, ##__VA_ARGS__);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPACM_LOG_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Neighbor.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Neighbor.h
new file mode 100644
index 0000000..745b145
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Neighbor.h
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2013-2017, 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.h
+
+ @brief
+ This file implements the functionality of handling IPACM Neighbor events.
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPACM_NEIGHBOR_H
+#define IPACM_NEIGHBOR_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Listener.h"
+#include "IPACM_Iface.h"
+
+#define IPA_MAX_NUM_NEIGHBOR_CLIENTS 100
+
+struct ipa_neighbor_client
+{
+ uint8_t mac_addr[6];
+ int iface_index;
+ uint32_t v4_addr;
+ int ipa_if_num;
+ /* add support for handling L2TP clients which associated with eth0 vlan interface */
+ char iface_name[IPA_IFACE_NAME_LEN];
+};
+
+class IPACM_Neighbor : public IPACM_Listener
+{
+
+public:
+
+ IPACM_Neighbor();
+
+ void event_callback(ipa_cm_event_id event,
+ void *data);
+
+private:
+
+ int num_neighbor_client;
+
+ int circular_index;
+
+ ipa_neighbor_client neighbor_client[IPA_MAX_NUM_NEIGHBOR_CLIENTS];
+
+};
+
+#endif /* IPACM_NEIGHBOR_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Netlink.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Netlink.h
new file mode 100644
index 0000000..b0bdeb8
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Netlink.h
@@ -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
+ IPA_Netlink.h
+
+ @brief
+ IPACM Netlink Messaging Implementation File
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPACM_NETLINK_H
+#define IPACM_NETLINK_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_addr.h>
+#include <linux/rtnetlink.h>
+#include <linux/netlink.h>
+#include <netinet/in.h>
+#include "IPACM_Defs.h"
+
+#define MAX_NUM_OF_FD 10
+#define IPA_NL_MSG_MAX_LEN (2048)
+
+/*---------------------------------------------------------------------------
+ Type representing enumeration of NetLink event indication messages
+---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+ Types representing parsed NetLink message
+---------------------------------------------------------------------------*/
+#define IPA_NLA_PARAM_NONE (0x0000)
+#define IPA_NLA_PARAM_PREFIXADDR (0x0001)
+#define IPA_NLA_PARAM_LOCALADDR (0x0002)
+#define IPA_NLA_PARAM_LABELNAME (0x0004)
+#define IPA_NLA_PARAM_BCASTADDR (0x0008)
+#define IPA_NLA_PARAM_ACASTADDR (0x0010)
+#define IPA_NLA_PARAM_MCASTADDR (0x0020)
+#define IPA_NLA_PARAM_CACHEINFO (0x0080)
+#define IPA_NLA_PARAM_PROTOINFO (0x0100)
+#define IPA_NLA_PARAM_FLAGS (0x0200)
+
+#define IPA_RTA_PARAM_NONE (0x0000)
+#define IPA_RTA_PARAM_DST (0x0001)
+#define IPA_RTA_PARAM_SRC (0x0002)
+#define IPA_RTA_PARAM_GATEWAY (0x0004)
+#define IPA_RTA_PARAM_IIF (0x0008)
+#define IPA_RTA_PARAM_OIF (0x0010)
+#define IPA_RTA_PARAM_CACHEINFO (0x0020)
+#define IPA_RTA_PARAM_PRIORITY (0x0080)
+#define IPA_RTA_PARAM_METRICS (0x0100)
+
+
+/*---------------------------------------------------------------------------
+ Type representing function callback registered with a socket listener
+ thread for reading from a socket on receipt of an incoming message
+---------------------------------------------------------------------------*/
+typedef int (*ipa_sock_thrd_fd_read_f)(int fd);
+
+typedef enum
+{
+ IPA_INIT = 0,
+ IPA_LINK_UP_WAIT,
+ IPA_LINK_UP,
+ IPA_LINK_DOWN_WAIT,
+ IPA_LINK_DOWN
+} ipa_nl_state_e;
+
+typedef struct
+{
+ int sk_fd;
+ ipa_sock_thrd_fd_read_f read_func;
+} ipa_nl_sk_fd_map_info_t;
+
+typedef struct
+{
+ ipa_nl_sk_fd_map_info_t sk_fds[MAX_NUM_OF_FD];
+ fd_set fdset;
+ int num_fd;
+ int max_fd;
+} ipa_nl_sk_fd_set_info_t;
+
+typedef struct
+{
+ int sk_fd; /* socket descriptor */
+ struct sockaddr_nl sk_addr_loc; /* local address of socket */
+} ipa_nl_sk_info_t;
+
+typedef struct ipa_nl_addr_s {
+ struct sockaddr_storage ip_addr;
+ unsigned int mask;
+} ipa_nl_addr_t;
+
+typedef struct ipa_nl_proto_info_s {
+ unsigned int param_mask;
+ unsigned int flags;
+ struct ifla_cacheinfo cache_info;
+} ipa_nl_proto_info_t;
+
+typedef struct
+{
+ struct ifinfomsg metainfo; /* from header */
+} ipa_nl_link_info_t;
+
+
+
+typedef struct ipa_nl_addr_info_s {
+ struct ifaddrmsg metainfo; /* from header */
+ struct /* attributes */
+ {
+ unsigned int param_mask;
+ unsigned char label_name[IF_NAME_LEN];
+ struct sockaddr_storage prefix_addr;
+ struct sockaddr_storage local_addr;
+ struct sockaddr_storage bcast_addr;
+ struct sockaddr_storage acast_addr;
+ struct sockaddr_storage mcast_addr;
+ } attr_info;
+} ipa_nl_addr_info_t;
+
+
+typedef struct ipa_nl_neigh_info_s {
+ struct ndmsg metainfo; /* from header */
+ struct /* attributes */
+ {
+ unsigned int param_mask;
+ struct sockaddr_storage local_addr;
+ struct sockaddr lladdr_hwaddr;
+ } attr_info;
+} ipa_nl_neigh_info_t;
+
+
+
+typedef struct ipa_nl_route_info_s {
+ struct rtmsg metainfo; /* from header */
+ struct /* attributes */
+ {
+ unsigned int param_mask;
+ struct sockaddr_storage dst_addr;
+ struct sockaddr_storage src_addr;
+ struct sockaddr_storage gateway_addr;
+ struct sockaddr_storage mark_addr;
+ struct rta_cacheinfo cache_info;
+ __u32 iif_index; /* Link index */
+ __u32 oif_index; /* Link index */
+ __u32 priority;
+ __u32 metrics;
+ ipa_nl_proto_info_t proto_info;
+ } attr_info;
+} ipa_nl_route_info_t;
+
+#define IPA_FLOW_TYPE_INVALID (-1)
+
+typedef struct
+{
+ unsigned int type;
+ bool link_event;
+ /* Optional parameters */
+ ipa_nl_link_info_t nl_link_info;
+ ipa_nl_addr_info_t nl_addr_info;
+ ipa_nl_neigh_info_t nl_neigh_info;
+ ipa_nl_route_info_t nl_route_info;
+} ipa_nl_msg_t;
+
+/* 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
+ );
+
+/* Virtual function registered to receive incoming messages over the NETLINK routing socket*/
+int ipa_nl_recv_msg(int fd);
+
+/* map mask value for ipv6 */
+int mask_v6(int index, uint32_t *mask);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPACM_NETLINK_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_OffloadManager.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_OffloadManager.h
new file mode 100644
index 0000000..bade0aa
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_OffloadManager.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+#ifndef _IPACM_OFFLOAD_MANAGER_H_
+#define _IPACM_OFFLOAD_MANAGER_H_
+
+#include <list>
+#include <stdint.h>
+#include <IOffloadManager.h>
+#include "IPACM_Defs.h"
+
+using RET = ::IOffloadManager::RET;
+using Prefix = ::IOffloadManager::Prefix;
+using IP_FAM = ::IOffloadManager::IP_FAM;
+using L4Protocol = ::IOffloadManager::ConntrackTimeoutUpdater::L4Protocol;
+using natTimeoutUpdate_t = ::IOffloadManager::ConntrackTimeoutUpdater::natTimeoutUpdate_t;
+//using ipAddrPortPair_t = ::IOffloadManager::ConntrackTimeoutUpdater::ipAddrPortPair_t;
+//using UDP = ::IOffloadManager::ConntrackTimeoutUpdater::UDP;
+//using TCP = ::IOffloadManager::ConntrackTimeoutUpdater::TCP;
+
+#define MAX_EVENT_CACHE 10
+
+typedef struct _framework_event_cache
+{
+ /* IPACM interface name */
+ ipa_cm_event_id event;
+ char dev_name[IF_NAME_LEN];
+ Prefix prefix_cache;
+ Prefix prefix_cache_v6; //for setupstream use
+ bool valid;
+}framework_event_cache;
+
+class IPACM_OffloadManager : public IOffloadManager
+{
+
+public:
+
+ IPACM_OffloadManager();
+ static IPACM_OffloadManager* GetInstance();
+
+ virtual RET registerEventListener(IpaEventListener* /* listener */);
+ virtual RET unregisterEventListener(IpaEventListener* /* listener */);
+ virtual RET registerCtTimeoutUpdater(ConntrackTimeoutUpdater* /* cb */);
+ virtual RET unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater* /* cb */);
+
+ virtual RET provideFd(int /* fd */, unsigned int /* group */);
+ virtual RET clearAllFds();
+ virtual bool isStaApSupported();
+
+ /* ---------------------------- ROUTE ------------------------------- */
+ virtual RET setLocalPrefixes(std::vector<Prefix> &/* prefixes */);
+ virtual RET addDownstream(const char * /* downstream */,
+ const Prefix & /* prefix */);
+ virtual RET removeDownstream(const char * /* downstream */,
+ const Prefix &/* prefix */);
+ virtual RET setUpstream(const char* /* iface */, const Prefix& /* v4Gw */, const Prefix& /* v6Gw */);
+ virtual RET stopAllOffload();
+
+ /* ------------------------- STATS/POLICY --------------------------- */
+ virtual RET setQuota(const char * /* upstream */, uint64_t /* limit */);
+ virtual RET getStats(const char * /* upstream */, bool /* reset */,
+ OffloadStatistics& /* ret */);
+
+ static IPACM_OffloadManager *pInstance; //sky
+
+ IpaEventListener *elrInstance;
+
+ ConntrackTimeoutUpdater *touInstance;
+
+ bool search_framwork_cache(char * interface_name);
+
+private:
+
+ std::list<std::string> valid_ifaces;
+
+ bool upstream_v4_up;
+
+ bool upstream_v6_up;
+
+ int default_gw_index;
+
+ int post_route_evt(enum ipa_ip_type iptype, int index, ipa_cm_event_id event, const Prefix &gw_addr);
+
+ int ipa_get_if_index(const char *if_name, int *if_index);
+
+ int resetTetherStats(const char *upstream_name);
+
+ static const char *DEVICE_NAME;
+
+ /* cache the add_downstream events if netdev is not ready */
+ framework_event_cache event_cache[MAX_EVENT_CACHE];
+
+ /* latest update cache entry */
+ int latest_cache_index;
+
+}; /* IPACM_OffloadManager */
+
+#endif /* _IPACM_OFFLOAD_MANAGER_H_ */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Routing.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Routing.h
new file mode 100644
index 0000000..b5ffabc
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Routing.h
@@ -0,0 +1,78 @@
+/*
+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
+ Skylar Chang
+
+*/
+
+
+#ifndef IPACM_ROUTING_H
+#define IPACM_ROUTING_H
+
+#include <stdint.h>
+#include <linux/msm_ipa.h>
+#include <IPACM_Defs.h>
+
+using namespace std;
+
+class IPACM_Routing
+{
+public:
+ IPACM_Routing();
+ ~IPACM_Routing();
+
+ bool AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable);
+ bool DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable);
+
+ bool Commit(enum ipa_ip_type ip);
+ bool Reset(enum ipa_ip_type ip);
+
+ bool GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable);
+
+ bool DeviceNodeIsOpened();
+ bool DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip);
+
+ bool ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *);
+
+private:
+ static const char *DEVICE_NAME;
+ int m_fd; /* File descriptor of the IPA device node /dev/ipa */
+
+ bool PutRoutingTable(uint32_t routingTableHandle);
+};
+
+#endif //IPACM_ROUTING_H
+
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Wan.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Wan.h
new file mode 100644
index 0000000..5d5e19b
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Wan.h
@@ -0,0 +1,574 @@
+/*
+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
+
+*/
+#ifndef IPACM_WAN_H
+#define IPACM_WAN_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include <IPACM_Iface.h>
+#include <IPACM_Defs.h>
+#include <IPACM_Xml.h>
+
+#define IPA_NUM_DEFAULT_WAN_FILTER_RULES 3 /*1 for v4, 2 for v6*/
+#define IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4 2
+
+#ifdef FEATURE_IPA_ANDROID
+#define IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6 6
+#define IPA_V2_NUM_TCP_WAN_FILTER_RULE_IPV6 3
+#define IPA_V2_NUM_MULTICAST_WAN_FILTER_RULE_IPV6 3
+#else
+#define IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6 3
+#endif
+
+#define NETWORK_STATS "%s %llu %llu %llu %llu"
+#define IPA_NETWORK_STATS_FILE_NAME "/data/misc/ipa/network_stats"
+
+typedef struct _wan_client_rt_hdl
+{
+ uint32_t wan_rt_rule_hdl_v4;
+ uint32_t wan_rt_rule_hdl_v6[IPV6_NUM_ADDR];
+ uint32_t wan_rt_rule_hdl_v6_wan[IPV6_NUM_ADDR];
+}wan_client_rt_hdl;
+
+typedef struct _ipa_wan_client
+{
+ ipacm_event_data_wlan_ex* p_hdr_info;
+ uint8_t mac[IPA_MAC_ADDR_SIZE];
+ uint32_t v4_addr;
+ uint32_t v6_addr[IPV6_NUM_ADDR][4];
+ uint32_t hdr_hdl_v4;
+ uint32_t hdr_hdl_v6;
+ bool route_rule_set_v4;
+ int route_rule_set_v6;
+ bool ipv4_set;
+ int ipv6_set;
+ bool ipv4_header_set;
+ bool ipv6_header_set;
+ bool power_save_set;
+ wan_client_rt_hdl wan_rt_hdl[0]; /* depends on number of tx properties */
+}ipa_wan_client;
+
+/* wan iface */
+class IPACM_Wan : public IPACM_Iface
+{
+
+public:
+
+ static bool wan_up;
+ static bool wan_up_v6;
+ static uint8_t xlat_mux_id;
+ /* IPACM interface name */
+ static char wan_up_dev_name[IF_NAME_LEN];
+ static uint32_t curr_wan_ip;
+ IPACM_Wan(int, ipacm_wan_iface_type, uint8_t *);
+ virtual ~IPACM_Wan();
+
+ static bool isWanUP(int ipa_if_num_tether)
+ {
+#ifdef FEATURE_IPA_ANDROID
+#ifdef FEATURE_IPACM_HAL
+ /*To avoid -Wall -Werror error */
+ IPACMDBG_H("ipa_if_num_tether: %d\n",ipa_if_num_tether);
+ return wan_up;
+#else
+ uint32_t i;
+ for (i=0; i < ipa_if_num_tether_v4_total;i++)
+ {
+ if (ipa_if_num_tether_v4[i] == ipa_if_num_tether)
+ {
+ IPACMDBG_H("support ipv4 tether_iface(%s)\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name);
+ return wan_up;
+ break;
+ }
+ }
+ return false;
+#endif
+#else
+ return wan_up;
+#endif
+ }
+
+ static bool isWanUP_V6(int ipa_if_num_tether)
+ {
+#ifdef FEATURE_IPA_ANDROID
+#ifdef FEATURE_IPACM_HAL
+ /*To avoid -Wall -Werror error */
+ IPACMDBG_H("ipa_if_num_tether: %d\n",ipa_if_num_tether);
+ return wan_up_v6;
+#else
+ uint32_t i;
+ for (i=0; i < ipa_if_num_tether_v6_total;i++)
+ {
+ if (ipa_if_num_tether_v6[i] == ipa_if_num_tether)
+ {
+ IPACMDBG_H("support ipv6 tether_iface(%s)\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name);
+ return wan_up_v6;
+ break;
+ }
+ }
+ return false;
+#endif
+#else
+ return wan_up_v6;
+#endif
+ }
+
+#ifdef FEATURE_IPA_ANDROID
+ static int delete_tether_iface(ipa_ip_type iptype, int ipa_if_num_tether)
+ {
+ uint32_t i, j;
+
+ if (iptype == IPA_IP_v4)
+ {
+ /* delete support tether ifaces to its array*/
+ for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
+ {
+ if(IPACM_Wan::ipa_if_num_tether_v4[i] == ipa_if_num_tether)
+ {
+ IPACMDBG_H("Found tether client at position %d name(%s)\n", i,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name);
+ break;
+ }
+ }
+ if(i == IPACM_Wan::ipa_if_num_tether_v4_total)
+ {
+ IPACMDBG_H("Not finding the tethered ipv4 client.\n");
+ return IPACM_FAILURE;
+ }
+ for(j = i+1; j < IPACM_Wan::ipa_if_num_tether_v4_total; j++)
+ {
+ IPACM_Wan::ipa_if_num_tether_v4[j-1] = IPACM_Wan::ipa_if_num_tether_v4[j];
+ }
+ IPACM_Wan::ipa_if_num_tether_v4_total--;
+ IPACMDBG_H("Now the total num of ipa_if_num_tether_v4_total is %d\n",
+ IPACM_Wan::ipa_if_num_tether_v4_total);
+ }
+ else
+ {
+ /* delete support tether ifaces to its array*/
+ for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
+ {
+ if(IPACM_Wan::ipa_if_num_tether_v6[i] == ipa_if_num_tether)
+ {
+ IPACMDBG_H("Found tether client at position %d name(%s)\n", i,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name);
+ break;
+ }
+ }
+ if(i == IPACM_Wan::ipa_if_num_tether_v6_total)
+ {
+ IPACMDBG_H("Not finding the tethered ipv6 client.\n");
+ return IPACM_FAILURE;
+ }
+ for(j = i+1; j < IPACM_Wan::ipa_if_num_tether_v6_total; j++)
+ {
+ IPACM_Wan::ipa_if_num_tether_v6[j-1] = IPACM_Wan::ipa_if_num_tether_v6[j];
+ }
+ IPACM_Wan::ipa_if_num_tether_v6_total--;
+ IPACMDBG_H("Now the total num of ipa_if_num_tether_v6_total is %d\n",
+ IPACM_Wan::ipa_if_num_tether_v6_total);
+ }
+ return IPACM_SUCCESS;
+ }
+#endif
+
+ static uint32_t getWANIP()
+ {
+ return curr_wan_ip;
+ }
+
+ static bool getXlat_Mux_Id()
+ {
+ return xlat_mux_id;
+ }
+
+ void event_callback(ipa_cm_event_id event,
+ void *data);
+
+ static struct ipa_flt_rule_add flt_rule_v4[IPA_MAX_FLT_RULE];
+ static struct ipa_flt_rule_add flt_rule_v6[IPA_MAX_FLT_RULE];
+
+ static int num_v4_flt_rule;
+ static int num_v6_flt_rule;
+
+ ipacm_wan_iface_type m_is_sta_mode;
+ static bool backhaul_is_sta_mode;
+ static bool is_ext_prop_set;
+ static uint32_t backhaul_ipv6_prefix[2];
+
+ static bool embms_is_on;
+ static bool backhaul_is_wan_bridge;
+
+ static bool isWan_Bridge_Mode()
+ {
+ return backhaul_is_wan_bridge;
+ }
+#ifdef FEATURE_IPA_ANDROID
+ /* IPACM interface id */
+ static uint32_t ipa_if_num_tether_v4_total;
+ static int ipa_if_num_tether_v4[IPA_MAX_IFACE_ENTRIES];
+ static uint32_t ipa_if_num_tether_v6_total;
+ static int ipa_if_num_tether_v6[IPA_MAX_IFACE_ENTRIES];
+#endif
+
+private:
+
+ bool is_ipv6_frag_firewall_flt_rule_installed;
+ uint32_t ipv6_frag_firewall_flt_rule_hdl;
+ uint32_t *wan_route_rule_v4_hdl;
+ uint32_t *wan_route_rule_v6_hdl;
+ uint32_t *wan_route_rule_v6_hdl_a5;
+ uint32_t hdr_hdl_sta_v4;
+ uint32_t hdr_hdl_sta_v6;
+ uint32_t firewall_hdl_v4[IPACM_MAX_FIREWALL_ENTRIES];
+ uint32_t firewall_hdl_v6[IPACM_MAX_FIREWALL_ENTRIES];
+ uint32_t dft_wan_fl_hdl[IPA_NUM_DEFAULT_WAN_FILTER_RULES];
+ uint32_t ipv6_dest_flt_rule_hdl[MAX_DEFAULT_v6_ROUTE_RULES];
+ int num_ipv6_dest_flt_rule;
+ uint32_t ODU_fl_hdl[IPA_NUM_DEFAULT_WAN_FILTER_RULES];
+ int num_firewall_v4,num_firewall_v6;
+ uint32_t wan_v4_addr;
+ uint32_t wan_v4_addr_gw;
+ uint32_t wan_v6_addr_gw[4];
+ bool wan_v4_addr_set;
+ bool wan_v4_addr_gw_set;
+ bool wan_v6_addr_gw_set;
+ bool active_v4;
+ bool active_v6;
+ bool header_set_v4;
+ bool header_set_v6;
+ bool header_partial_default_wan_v4;
+ bool header_partial_default_wan_v6;
+ uint8_t ext_router_mac_addr[IPA_MAC_ADDR_SIZE];
+ uint8_t netdev_mac[IPA_MAC_ADDR_SIZE];
+
+ static int num_ipv4_modem_pdn;
+
+ static int num_ipv6_modem_pdn;
+
+ int modem_ipv4_pdn_index;
+
+ int modem_ipv6_pdn_index;
+
+ bool is_default_gateway;
+
+ uint32_t ipv6_prefix[2];
+
+ /* IPACM firewall Configuration file*/
+ IPACM_firewall_conf_t firewall_config;
+
+ /* STA mode wan-client*/
+ int wan_client_len;
+ ipa_wan_client *wan_client;
+ int header_name_count;
+ uint32_t num_wan_client;
+ uint8_t invalid_mac[IPA_MAC_ADDR_SIZE];
+ bool is_xlat;
+
+ /* update network stats for CNE */
+ int ipa_network_stats_fd;
+ uint32_t hdr_hdl_dummy_v6;
+ uint32_t hdr_proc_hdl_dummy_v6;
+
+ inline ipa_wan_client* get_client_memptr(ipa_wan_client *param, int cnt)
+ {
+ char *ret = ((char *)param) + (wan_client_len * cnt);
+ return (ipa_wan_client *)ret;
+ }
+
+ inline int get_wan_client_index(uint8_t *mac_addr)
+ {
+ int cnt;
+ int num_wan_client_tmp = num_wan_client;
+
+ IPACMDBG_H("Passed 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]);
+
+ for(cnt = 0; cnt < num_wan_client_tmp; cnt++)
+ {
+ IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wan_client, cnt)->mac[0],
+ get_client_memptr(wan_client, cnt)->mac[1],
+ get_client_memptr(wan_client, cnt)->mac[2],
+ get_client_memptr(wan_client, cnt)->mac[3],
+ get_client_memptr(wan_client, cnt)->mac[4],
+ get_client_memptr(wan_client, cnt)->mac[5]);
+
+ if(memcmp(get_client_memptr(wan_client, cnt)->mac,
+ mac_addr,
+ sizeof(get_client_memptr(wan_client, cnt)->mac)) == 0)
+ {
+ IPACMDBG_H("Matched client index: %d\n", cnt);
+ return cnt;
+ }
+ }
+
+ return IPACM_INVALID_INDEX;
+ }
+
+ inline int get_wan_client_index_ipv4(uint32_t ipv4_addr)
+ {
+ int cnt;
+ int num_wan_client_tmp = num_wan_client;
+
+ IPACMDBG_H("Passed IPv4 %x\n", ipv4_addr);
+
+ for(cnt = 0; cnt < num_wan_client_tmp; cnt++)
+ {
+ if (get_client_memptr(wan_client, cnt)->ipv4_set)
+ {
+ IPACMDBG_H("stored IPv4 %x\n", get_client_memptr(wan_client, cnt)->v4_addr);
+
+ if(ipv4_addr == get_client_memptr(wan_client, cnt)->v4_addr)
+ {
+ IPACMDBG_H("Matched client index: %d\n", cnt);
+ IPACMDBG_H("The MAC is %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wan_client, cnt)->mac[0],
+ get_client_memptr(wan_client, cnt)->mac[1],
+ get_client_memptr(wan_client, cnt)->mac[2],
+ get_client_memptr(wan_client, cnt)->mac[3],
+ get_client_memptr(wan_client, cnt)->mac[4],
+ get_client_memptr(wan_client, cnt)->mac[5]);
+ IPACMDBG_H("header set ipv4(%d) ipv6(%d)\n",
+ get_client_memptr(wan_client, cnt)->ipv4_header_set,
+ get_client_memptr(wan_client, cnt)->ipv6_header_set);
+ return cnt;
+ }
+ }
+ }
+ return IPACM_INVALID_INDEX;
+ }
+
+ inline int get_wan_client_index_ipv6(uint32_t* ipv6_addr)
+ {
+ int cnt, v6_num;
+ int num_wan_client_tmp = num_wan_client;
+
+ IPACMDBG_H("Get ipv6 address 0x%08x.0x%08x.0x%08x.0x%08x\n", ipv6_addr[0], ipv6_addr[1], ipv6_addr[2], ipv6_addr[3]);
+
+ for(cnt = 0; cnt < num_wan_client_tmp; cnt++)
+ {
+ if (get_client_memptr(wan_client, cnt)->ipv6_set)
+ {
+ for(v6_num=0;v6_num < get_client_memptr(wan_client, cnt)->ipv6_set;v6_num++)
+ {
+
+ IPACMDBG_H("stored IPv6 0x%08x.0x%08x.0x%08x.0x%08x\n", get_client_memptr(wan_client, cnt)->v6_addr[v6_num][0],
+ get_client_memptr(wan_client, cnt)->v6_addr[v6_num][1],
+ get_client_memptr(wan_client, cnt)->v6_addr[v6_num][2],
+ get_client_memptr(wan_client, cnt)->v6_addr[v6_num][3]);
+
+ if(ipv6_addr[0] == get_client_memptr(wan_client, cnt)->v6_addr[v6_num][0] &&
+ ipv6_addr[1] == get_client_memptr(wan_client, cnt)->v6_addr[v6_num][1] &&
+ ipv6_addr[2]== get_client_memptr(wan_client, cnt)->v6_addr[v6_num][2] &&
+ ipv6_addr[3] == get_client_memptr(wan_client, cnt)->v6_addr[v6_num][3])
+ {
+ IPACMDBG_H("Matched client index: %d\n", cnt);
+ IPACMDBG_H("The MAC is %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wan_client, cnt)->mac[0],
+ get_client_memptr(wan_client, cnt)->mac[1],
+ get_client_memptr(wan_client, cnt)->mac[2],
+ get_client_memptr(wan_client, cnt)->mac[3],
+ get_client_memptr(wan_client, cnt)->mac[4],
+ get_client_memptr(wan_client, cnt)->mac[5]);
+ IPACMDBG_H("header set ipv4(%d) ipv6(%d)\n",
+ get_client_memptr(wan_client, cnt)->ipv4_header_set,
+ get_client_memptr(wan_client, cnt)->ipv6_header_set);
+ return cnt;
+ }
+ }
+ }
+ }
+ return IPACM_INVALID_INDEX;
+ }
+
+ inline int delete_wan_rtrules(int clt_indx, ipa_ip_type iptype)
+ {
+ uint32_t tx_index;
+ uint32_t rt_hdl;
+ int num_v6;
+
+ if(iptype == IPA_IP_v4)
+ {
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if((tx_prop->tx[tx_index].ip == IPA_IP_v4) && (get_client_memptr(wan_client, clt_indx)->route_rule_set_v4==true)) /* for ipv4 */
+ {
+ IPACMDBG_H("Delete client index %d ipv4 Qos rules for tx:%d \n",clt_indx,tx_index);
+ rt_hdl = get_client_memptr(wan_client, clt_indx)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4;
+
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v4) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ } /* end of for loop */
+
+ /* clean the 4 Qos ipv4 RT rules for client:clt_indx */
+ if(get_client_memptr(wan_client, clt_indx)->route_rule_set_v4==true) /* for ipv4 */
+ {
+ get_client_memptr(wan_client, clt_indx)->route_rule_set_v4 = false;
+ }
+ }
+
+ if(iptype == IPA_IP_v6)
+ {
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+
+ if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(wan_client, clt_indx)->route_rule_set_v6 != 0)) /* for ipv6 */
+ {
+ for(num_v6 =0;num_v6 < get_client_memptr(wan_client, clt_indx)->route_rule_set_v6;num_v6++)
+ {
+ IPACMDBG_H("Delete client index %d ipv6 Qos rules for %d-st ipv6 for tx:%d\n", clt_indx,num_v6,tx_index);
+ rt_hdl = get_client_memptr(wan_client, clt_indx)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[num_v6];
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ rt_hdl = get_client_memptr(wan_client, clt_indx)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[num_v6];
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+
+ }
+ } /* end of for loop */
+
+ /* clean the 4 Qos ipv6 RT rules for client:clt_indx */
+ if(get_client_memptr(wan_client, clt_indx)->route_rule_set_v6 != 0) /* for ipv6 */
+ {
+ get_client_memptr(wan_client, clt_indx)->route_rule_set_v6 = 0;
+ }
+ }
+
+ return IPACM_SUCCESS;
+ }
+
+ int handle_wan_hdr_init(uint8_t *mac_addr);
+ int handle_wan_client_ipaddr(ipacm_event_data_all *data);
+ int handle_wan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype);
+
+ /* handle new_address event */
+ int handle_addr_evt(ipacm_event_data_addr *data);
+
+ /* wan default route/filter rule configuration */
+ int handle_route_add_evt(ipa_ip_type iptype);
+
+ /* construct complete STA ethernet header */
+ int handle_sta_header_add_evt();
+
+ bool check_dft_firewall_rules_attr_mask(IPACM_firewall_conf_t *firewall_config);
+
+#ifdef FEATURE_IPA_ANDROID
+ /* wan posting supported tether_iface */
+ int post_wan_up_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether);
+
+ int post_wan_down_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether);
+#endif
+ int config_dft_firewall_rules(ipa_ip_type iptype);
+
+ /* configure the initial firewall filter rules */
+ int config_dft_embms_rules(ipa_ioc_add_flt_rule *pFilteringTable_v4, ipa_ioc_add_flt_rule *pFilteringTable_v6);
+
+ int handle_route_del_evt(ipa_ip_type iptype);
+
+ int del_dft_firewall_rules(ipa_ip_type iptype);
+
+ int handle_down_evt();
+
+ /*handle wan-iface down event */
+ int handle_down_evt_ex();
+
+ /* wan default route/filter rule delete */
+ int handle_route_del_evt_ex(ipa_ip_type iptype);
+
+ /* configure the initial firewall filter rules */
+ int config_dft_firewall_rules_ex(struct ipa_flt_rule_add* rules, int rule_offset,
+ ipa_ip_type iptype);
+
+ /* init filtering rule in wan dl filtering table */
+ int init_fl_rule_ex(ipa_ip_type iptype);
+
+ /* add ICMP and ALG rules in wan dl filtering table */
+ int add_icmp_alg_rules(struct ipa_flt_rule_add* rules, int rule_offset, ipa_ip_type iptype);
+
+ /* query extended property */
+ int query_ext_prop();
+
+ ipa_ioc_query_intf_ext_props *ext_prop;
+
+ int config_wan_firewall_rule(ipa_ip_type iptype);
+
+ int del_wan_firewall_rule(ipa_ip_type iptype);
+
+ int add_dft_filtering_rule(struct ipa_flt_rule_add* rules, int rule_offset, ipa_ip_type iptype);
+
+ int add_tcpv6_filtering_rule(struct ipa_flt_rule_add* rules, int rule_offset);
+
+ int install_wan_filtering_rule(bool is_sw_routing);
+
+ void change_to_network_order(ipa_ip_type iptype, ipa_rule_attrib* attrib);
+
+ bool is_global_ipv6_addr(uint32_t* ipv6_addr);
+
+ void handle_wlan_SCC_MCC_switch(bool, ipa_ip_type);
+
+ void handle_wan_client_SCC_MCC_switch(bool, ipa_ip_type);
+
+ int handle_network_stats_evt();
+
+ int m_fd_ipa;
+
+ int handle_network_stats_update(ipa_get_apn_data_stats_resp_msg_v01 *data);
+
+ /* construct dummy ethernet header */
+ int add_dummy_rx_hdr();
+};
+
+#endif /* IPACM_WAN_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Wlan.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Wlan.h
new file mode 100644
index 0000000..5fee0fa
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Wlan.h
@@ -0,0 +1,240 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Wlan.h
+
+ @brief
+ This file implements the WLAN iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#ifndef IPACM_WLAN_H
+#define IPACM_WLAN_H
+
+#include <stdio.h>
+#include <IPACM_CmdQueue.h>
+#include <linux/msm_ipa.h>
+#include "IPACM_Routing.h"
+#include "IPACM_Filtering.h"
+#include "IPACM_Lan.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Conntrack_NATApp.h"
+
+typedef struct _wlan_client_rt_hdl
+{
+ uint32_t wifi_rt_rule_hdl_v4;
+ uint32_t wifi_rt_rule_hdl_v6[IPV6_NUM_ADDR];
+ uint32_t wifi_rt_rule_hdl_v6_wan[IPV6_NUM_ADDR];
+}wlan_client_rt_hdl;
+
+typedef struct _ipa_wlan_client
+{
+ ipacm_event_data_wlan_ex* p_hdr_info;
+ uint8_t mac[IPA_MAC_ADDR_SIZE];
+ uint32_t v4_addr;
+ uint32_t v6_addr[IPV6_NUM_ADDR][4];
+ uint32_t hdr_hdl_v4;
+ uint32_t hdr_hdl_v6;
+ bool route_rule_set_v4;
+ int route_rule_set_v6;
+ bool ipv4_set;
+ int ipv6_set;
+ bool ipv4_header_set;
+ bool ipv6_header_set;
+ bool power_save_set;
+ wlan_client_rt_hdl wifi_rt_hdl[0]; /* depends on number of tx properties */
+}ipa_wlan_client;
+
+/* wlan iface */
+class IPACM_Wlan : public IPACM_Lan
+{
+
+public:
+
+ IPACM_Wlan(int iface_index);
+ virtual ~IPACM_Wlan(void);
+
+ static int total_num_wifi_clients;
+
+ void event_callback(ipa_cm_event_id event, void *data);
+
+ bool is_guest_ap();
+
+private:
+
+ bool m_is_guest_ap;
+
+ /* handle wlan access mode switch in ethernet bridging*/
+ void eth_bridge_handle_wlan_mode_switch();
+
+
+ int wlan_client_len;
+ ipa_wlan_client *wlan_client;
+
+ int header_name_count;
+ uint32_t num_wifi_client;
+
+ int wlan_ap_index;
+
+ static int num_wlan_ap_iface;
+
+ NatApp *Nat_App;
+
+ inline ipa_wlan_client* get_client_memptr(ipa_wlan_client *param, int cnt)
+ {
+ char *ret = ((char *)param) + (wlan_client_len * cnt);
+ return (ipa_wlan_client *)ret;
+ }
+
+ inline int get_wlan_client_index(uint8_t *mac_addr)
+ {
+ int cnt;
+ int num_wifi_client_tmp = num_wifi_client;
+
+ IPACMDBG_H("Passed 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]);
+
+ for(cnt = 0; cnt < num_wifi_client_tmp; cnt++)
+ {
+ IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wlan_client, cnt)->mac[0],
+ get_client_memptr(wlan_client, cnt)->mac[1],
+ get_client_memptr(wlan_client, cnt)->mac[2],
+ get_client_memptr(wlan_client, cnt)->mac[3],
+ get_client_memptr(wlan_client, cnt)->mac[4],
+ get_client_memptr(wlan_client, cnt)->mac[5]);
+
+ if(memcmp(get_client_memptr(wlan_client, cnt)->mac,
+ mac_addr,
+ sizeof(get_client_memptr(wlan_client, cnt)->mac)) == 0)
+ {
+ IPACMDBG_H("Matched client index: %d\n", cnt);
+ return cnt;
+ }
+ }
+
+ return IPACM_INVALID_INDEX;
+ }
+
+ inline int delete_default_qos_rtrules(int clt_indx, ipa_ip_type iptype)
+ {
+ uint32_t tx_index;
+ uint32_t rt_hdl;
+ int num_v6;
+
+ if(iptype == IPA_IP_v4)
+ {
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if((tx_prop->tx[tx_index].ip == IPA_IP_v4) && (get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4==true)) /* for ipv4 */
+ {
+ IPACMDBG_H("Delete client index %d ipv4 Qos rules for tx:%d \n",clt_indx,tx_index);
+ rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v4) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ } /* end of for loop */
+
+ /* clean the 4 Qos ipv4 RT rules for client:clt_indx */
+ if(get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4==true) /* for ipv4 */
+ {
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = false;
+ }
+ }
+
+ if(iptype == IPA_IP_v6)
+ {
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+
+ if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 != 0)) /* for ipv6 */
+ {
+ for(num_v6 =0;num_v6 < get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6;num_v6++)
+ {
+ IPACMDBG_H("Delete client index %d ipv6 Qos rules for %d-st ipv6 for tx:%d\n", clt_indx,num_v6,tx_index);
+ rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[num_v6];
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[num_v6];
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+
+ }
+ } /* end of for loop */
+
+ /* clean the 4 Qos ipv6 RT rules for client:clt_indx */
+ if(get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 != 0) /* for ipv6 */
+ {
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = 0;
+ }
+ }
+
+ return IPACM_SUCCESS;
+ }
+
+ /* for handle wifi client initial,copy all partial headers (tx property) */
+ int handle_wlan_client_init_ex(ipacm_event_data_wlan_ex *data);
+
+ /*handle wifi client */
+ int handle_wlan_client_ipaddr(ipacm_event_data_all *data);
+
+ /*handle wifi client routing rule*/
+ int handle_wlan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype);
+
+ /*handle wifi client power-save mode*/
+ int handle_wlan_client_pwrsave(uint8_t *mac_addr);
+
+ /*handle wifi client del mode*/
+ int handle_wlan_client_down_evt(uint8_t *mac_addr);
+
+ /*handle wlan iface down event*/
+ int handle_down_evt();
+
+ /*handle reset wifi-client rt-rules */
+ int handle_wlan_client_reset_rt(ipa_ip_type iptype);
+
+ void handle_SCC_MCC_switch(ipa_ip_type);
+
+};
+
+
+#endif /* IPACM_WLAN_H */
diff --git a/data-ipa-cfg-mgr/ipacm/inc/IPACM_Xml.h b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Xml.h
new file mode 100644
index 0000000..64c00ed
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/inc/IPACM_Xml.h
@@ -0,0 +1,303 @@
+/*
+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.h
+
+ @brief
+ This file implements the XML specific parsing functionality.
+
+ @Author
+ Skylar Chang/Shihuan Liu
+
+*/
+#ifndef IPACM_XML_H
+#define IPACM_XML_H
+
+#include <linux/msm_ipa.h>
+#include "IPACM_Defs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define IPACM_ASSERT(a) \
+if (!(a)) { \
+ fprintf(stderr, "%s, %d: assertion (a) failed!", \
+ __FILE__, \
+ __LINE__); \
+ abort(); \
+}
+
+/* Max allowed size of the XML file (2 MB) */
+#define IPACM_XML_MAX_FILESIZE (2 << 20)
+#define IPACM_MAX_FIREWALL_ENTRIES 50
+#define IPACM_IPV6_ADDR_LEN 16
+
+/* Defines for clipping space or space & quotes (single, double) */
+#define IPACM_XML_CLIP_SPACE " "
+#define IPACM_XML_CLIP_SPACE_QUOTES " '\""
+
+#define MAX_XML_STR_LEN 120
+
+/* IPA Config Entries */
+#define system_TAG "system"
+#define ODU_TAG "ODUCFG"
+#define ODUMODE_TAG "OduMode"
+#define ODUEMBMS_OFFLOAD_TAG "eMBMS_offload"
+#define ODU_ROUTER_TAG "router"
+#define ODU_BRIDGE_TAG "bridge"
+#define IPACMCFG_TAG "IPACM"
+#define IPACMIFACECFG_TAG "IPACMIface"
+#define IFACE_TAG "Iface"
+#define NAME_TAG "Name"
+#define CATEGORY_TAG "Category"
+#define MODE_TAG "Mode"
+#define IPACMPRIVATESUBNETCFG_TAG "IPACMPrivateSubnet"
+#define SUBNET_TAG "Subnet"
+#define SUBNETADDRESS_TAG "SubnetAddress"
+#define SUBNETMASK_TAG "SubnetMask"
+#define WANIF_TAG "WAN"
+#define LANIF_TAG "LAN"
+#define WLANIF_TAG "WLAN"
+#define WLAN_FULL_MODE_TAG "full"
+#define WLAN_INTERNET_MODE_TAG "internet"
+#define WLAN_MODE_TAG "WlanMode"
+#define VIRTUALIF_TAG "VIRTUAL"
+#define UNKNOWNIF_TAG "UNKNOWN"
+#define ODUIF_TAG "ODU"
+#define EMBMSIF_TAG "EMBMS"
+#define ETHIF_TAG "ETH"
+#define IFACE_ROUTER_MODE_TAG "ROUTER"
+#define IFACE_BRIDGE_MODE_TAG "BRIDGE"
+#define IPACMALG_TAG "IPACMALG"
+#define ALG_TAG "ALG"
+#define Protocol_TAG "Protocol"
+#define Port_TAG "Port"
+#define TCP_PROTOCOL_TAG "TCP"
+#define UDP_PROTOCOL_TAG "UDP"
+
+/* FIREWALL Config Entries */
+#define Firewall_TAG "Firewall"
+#define MobileAPFirewallCfg_TAG "MobileAPFirewallCfg"
+#define FirewallEnabled_TAG "FirewallEnabled"
+#define FirewallPktsAllowed_TAG "FirewallPktsAllowed"
+
+#define IPFamily_TAG "IPFamily"
+#define IPV4SourceAddress_TAG "IPV4SourceAddress"
+#define IPV4SourceIPAddress_TAG "IPV4SourceIPAddress"
+#define IPV4SourceSubnetMask_TAG "IPV4SourceSubnetMask"
+
+#define IPV4DestinationAddress_TAG "IPV4DestinationAddress"
+#define IPV4DestinationIPAddress_TAG "IPV4DestinationIPAddress"
+#define IPV4DestinationSubnetMask_TAG "IPV4DestinationSubnetMask"
+
+#define IPV4TypeOfService_TAG "IPV4TypeOfService"
+#define TOSValue_TAG "TOSValue"
+#define TOSMask_TAG "TOSMask"
+
+#define IPV4NextHeaderProtocol_TAG "IPV4NextHeaderProtocol"
+
+#define IPV6SourceAddress_TAG "IPV6SourceAddress"
+#define IPV6SourceIPAddress_TAG "IPV6SourceIPAddress"
+#define IPV6SourcePrefix_TAG "IPV6SourcePrefix"
+
+#define IPV6DestinationAddress_TAG "IPV6DestinationAddress"
+#define IPV6DestinationIPAddress_TAG "IPV6DestinationIPAddress"
+#define IPV6DestinationPrefix_TAG "IPV6DestinationPrefix"
+
+#define IPV6TrafficClass_TAG "IPV6TrafficClass"
+#define TrfClsValue_TAG "TrfClsValue"
+#define TrfClsMask_TAG "TrfClsMask"
+
+#define IPV6NextHeaderProtocol_TAG "IPV6NextHeaderProtocol"
+
+#define TCPSource_TAG "TCPSource"
+#define TCPSourcePort_TAG "TCPSourcePort"
+#define TCPSourceRange_TAG "TCPSourceRange"
+
+#define TCPDestination_TAG "TCPDestination"
+#define TCPDestinationPort_TAG "TCPDestinationPort"
+#define TCPDestinationRange_TAG "TCPDestinationRange"
+
+#define UDPSource_TAG "UDPSource"
+#define UDPSourcePort_TAG "UDPSourcePort"
+#define UDPSourceRange_TAG "UDPSourceRange"
+
+#define UDPDestination_TAG "UDPDestination"
+#define UDPDestinationPort_TAG "UDPDestinationPort"
+#define UDPDestinationRange_TAG "UDPDestinationRange"
+
+#define ICMPType_TAG "ICMPType"
+#define ICMPCode_TAG "ICMPCode"
+
+#define ESP_TAG "ESP"
+#define ESPSPI_TAG "ESPSPI"
+
+#define TCP_UDPSource_TAG "TCP_UDPSource"
+#define TCP_UDPSourcePort_TAG "TCP_UDPSourcePort"
+#define TCP_UDPSourceRange_TAG "TCP_UDPSourceRange"
+
+#define TCP_UDPDestination_TAG "TCP_UDPDestination"
+#define TCP_UDPDestinationPort_TAG "TCP_UDPDestinationPort"
+#define TCP_UDPDestinationRange_TAG "TCP_UDPDestinationRange"
+
+#define IPACMNat_TAG "IPACMNAT"
+#define NAT_MaxEntries_TAG "MaxNatEntries"
+
+#define IP_PassthroughFlag_TAG "IPPassthroughFlag"
+#define IP_PassthroughMode_TAG "IPPassthroughMode"
+
+/*---------------------------------------------------------------------------
+ IP protocol numbers - use in dss_socket() to identify protocols.
+ Also contains the extension header types for IPv6.
+---------------------------------------------------------------------------*/
+typedef enum
+{
+ IPACM_FIREWALL_IPV6_BASE_HDR = 4, /* IPv6 Base Header */
+ IPACM_FIREWALL_IPPROTO_HOP_BY_HOP_OPT_HDR = 0, /* Hop-by-hop Option Header */
+ IPACM_FIREWALL_IPPROTO_ICMP = 1, /* ICMP protocol */
+ IPACM_FIREWALL_IPPROTO_IGMP = 2, /* IGMP protocol */
+ IPACM_FIREWALL_IPPROTO_IP = IPACM_FIREWALL_IPV6_BASE_HDR, /* IPv4 */
+ IPACM_FIREWALL_IPPROTO_TCP = 6, /* TCP Protocol */
+ IPACM_FIREWALL_IPPROTO_UDP = 17, /* UDP Protocol */
+ IPACM_FIREWALL_IPPROTO_IPV6 = 41, /* IPv6 */
+ IPACM_FIREWALL_IPPROTO_ROUTING_HDR = 43, /* Routing Header */
+ IPACM_FIREWALL_IPPROTO_FRAG_HDR = 44, /* Fragmentation Header */
+ IPACM_FIREWALL_IPPROTO_GRE = 47, /* GRE Protocol */
+ IPACM_FIREWALL_IPPROTO_ESP = 50, /* ESP Protocol */
+ IPACM_FIREWALL_IPPROTO_AH = 51, /* Authentication Header */
+ IPACM_FIREWALL_IPPROTO_ICMP6 = 58, /* ICMPv6 */
+ IPACM_FIREWALL_NO_NEXT_HDR = 59, /* No Next Header for IPv6 */
+ IPACM_FIREWALL_IPPROTO_DEST_OPT_HDR = 60, /* Destination Options Header */
+ IPACM_FIREWALL_IPPROTO_MOBILITY_HDR = 135, /* Mobility Header */
+ IPACM_FIREWALL_IPPROTO_TCP_UDP = 253 /* Unspecified protocol used for IPACM */
+} ipacm_firewall_ip_protocol_enum_type;
+
+/* define as mobileap firewall rule format*/
+typedef enum
+{
+ IP_V4 = 4,
+ IP_V6 = 6
+} firewall_ip_version_enum;
+
+/*---------------------------------------------------------------------------
+ Extended FireWall Entry Configuration.
+---------------------------------------------------------------------------*/
+typedef struct
+{
+ struct ipa_rule_attrib attrib;
+ firewall_ip_version_enum ip_vsn;
+} IPACM_extd_firewall_entry_conf_t;
+
+
+/*---------------------------------------------------------------------------
+ Extended FireWall configuration.
+---------------------------------------------------------------------------*/
+typedef union
+{
+ IPACM_extd_firewall_entry_conf_t extd_firewall_entry;
+} IPACM_extd_firewall_conf_t;
+
+
+typedef struct
+{
+ char firewall_config_file[IPA_MAX_FILE_LEN];
+ uint8_t num_extd_firewall_entries;
+ IPACM_extd_firewall_entry_conf_t extd_firewall_entries[IPACM_MAX_FIREWALL_ENTRIES];
+ bool rule_action_accept;
+ bool firewall_enable;
+} IPACM_firewall_conf_t;
+
+
+
+typedef struct
+{
+ uint8_t num_iface_entries;
+ ipa_ifi_dev_name_t iface_entries[IPA_MAX_IFACE_ENTRIES];
+} ipacm_iface_conf_t;
+
+typedef struct
+{
+ uint8_t num_subnet_entries;
+ ipa_private_subnet private_subnet_entries[IPA_MAX_PRIVATE_SUBNET_ENTRIES];
+} ipacm_private_subnet_conf_t;
+
+typedef struct
+{
+ uint8_t protocol;
+ uint16_t port;
+} ipacm_alg;
+
+typedef struct
+{
+ uint8_t num_alg_entries;
+ ipacm_alg alg_entries[IPA_MAX_ALG_ENTRIES];
+} ipacm_alg_conf_t;
+
+
+typedef struct _IPACM_conf_t
+{
+ ipacm_iface_conf_t iface_config;
+ ipacm_private_subnet_conf_t private_subnet_config;
+ ipacm_alg_conf_t alg_config;
+ int nat_max_entries;
+ bool odu_enable;
+ bool router_mode_enable;
+ bool odu_embms_enable;
+ int num_wlan_guest_ap;
+ bool ip_passthrough_mode;
+} IPACM_conf_t;
+
+/* This function read IPACM XML configuration*/
+int ipacm_read_cfg_xml
+(
+ char *xml_file, /* Filename and path */
+ IPACM_conf_t *config /* Mobile AP config data */
+);
+
+/* This function reads QCMAP Firewall XML and store in IPACM Firewall stucture */
+int IPACM_read_firewall_xml
+(
+ char *xml_file, /* Filename and path */
+ IPACM_firewall_conf_t *config /* Mobile AP config data */
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //IPACM_XML
diff --git a/data-ipa-cfg-mgr/ipacm/src/Android.mk b/data-ipa-cfg-mgr/ipacm/src/Android.mk
new file mode 100644
index 0000000..1242cbf
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/Android.mk
@@ -0,0 +1,120 @@
+BOARD_PLATFORM_LIST := msm8909
+BOARD_PLATFORM_LIST += msm8916
+BOARD_PLATFORM_LIST += msm8917
+BOARD_IPAv3_LIST := msm8998
+ifneq ($(call is-board-platform-in-list,$(BOARD_PLATFORM_LIST)),true)
+ifneq (,$(filter $(QCOM_BOARD_PLATFORMS),$(TARGET_BOARD_PLATFORM)))
+ifneq (, $(filter aarch64 arm arm64, $(TARGET_ARCH)))
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../src
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../inc
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../ipanat/inc
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../hal/inc
+ifeq ($(call is-platform-sdk-version-at-least,20),true)
+LOCAL_C_INCLUDES += external/icu/icu4c/source/common
+else
+LOCAL_C_INCLUDES += external/icu4c/common
+endif
+#LOCAL_C_INCLUDES += external/dhcpcd
+LOCAL_C_INCLUDES += external/libxml2/include
+LOCAL_C_INCLUDES += external/libnetfilter_conntrack/include
+LOCAL_C_INCLUDES += external/libnfnetlink/include
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_CFLAGS := -v
+LOCAL_CFLAGS += -DFEATURE_IPA_ANDROID
+LOCAL_CFLAGS += -DFEATURE_IPACM_HAL -Wall -Werror -Wno-error=macro-redefined
+ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
+LOCAL_CFLAGS += -DDEBUG
+endif
+
+ifeq ($(call is-board-platform-in-list,$(BOARD_IPAv3_LIST)),true)
+LOCAL_CFLAGS += -DFEATURE_IPA_V3
+endif
+
+filetoadd = bionic/libc/kernel/arch-arm/asm/posix_types.h
+LOCAL_CFLAGS += $(shell if [ -a $(filetoadd) ] ; then echo -include $(filetoadd) ; fi ;)
+filetoadd = bionic/libc/kernel/arch-arm/asm/byteorder.h
+LOCAL_CFLAGS += $(shell if [ -a $(filetoadd) ] ; then echo -include $(filetoadd) ; fi ;)
+
+
+LOCAL_SRC_FILES := IPACM_Main.cpp \
+ IPACM_EvtDispatcher.cpp \
+ IPACM_Config.cpp \
+ IPACM_CmdQueue.cpp \
+ IPACM_Filtering.cpp \
+ IPACM_Routing.cpp \
+ IPACM_Header.cpp \
+ IPACM_Lan.cpp \
+ IPACM_Iface.cpp \
+ IPACM_Wlan.cpp \
+ IPACM_Wan.cpp \
+ IPACM_IfaceManager.cpp \
+ IPACM_Neighbor.cpp \
+ IPACM_Netlink.cpp \
+ IPACM_Xml.cpp \
+ IPACM_Conntrack_NATApp.cpp\
+ IPACM_ConntrackClient.cpp \
+ IPACM_ConntrackListener.cpp \
+ IPACM_Log.cpp \
+ IPACM_OffloadManager.cpp
+
+LOCAL_MODULE := ipacm
+LOCAL_CLANG := false
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := liboffloadhal
+LOCAL_SHARED_LIBRARIES += libipanat
+LOCAL_SHARED_LIBRARIES += libxml2
+LOCAL_SHARED_LIBRARIES += libnfnetlink
+LOCAL_SHARED_LIBRARIES += libnetfilter_conntrack
+LOCAL_SHARED_LIBRARIES += libhwbinder \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libcutils \
+ libdl \
+ libbase \
+ libutils \
+ libhardware_legacy \
+ libhardware \
+ android.hardware.tetheroffload.config@1.0 \
+ android.hardware.tetheroffload.control@1.0
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_EXECUTABLES)
+
+LOCAL_CLANG := true
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+define ADD_TEST
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := $1
+LOCAL_SRC_FILES := $1
+LOCAL_MODULE_CLASS := ipacm
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+include $(BUILD_PREBUILT)
+
+endef
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := IPACM_cfg.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_OWNER := ipacm
+include $(BUILD_PREBUILT)
+
+endif # $(TARGET_ARCH)
+endif
+endif
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_CmdQueue.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_CmdQueue.cpp
new file mode 100644
index 0000000..c612b7f
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_CmdQueue.cpp
@@ -0,0 +1,207 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_CmdQueue.cpp
+
+ @brief
+ This file implements the IPAM Comment Queue functionality
+
+ @Author
+ Sunil
+
+*/
+#include <string.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Log.h"
+#include "IPACM_Iface.h"
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
+
+MessageQueue* MessageQueue::inst_internal = NULL;
+MessageQueue* MessageQueue::inst_external = NULL;
+
+MessageQueue* MessageQueue::getInstanceInternal()
+{
+ if(inst_internal == NULL)
+ {
+ inst_internal = new MessageQueue();
+ if(inst_internal == NULL)
+ {
+ IPACMERR("unable to create internal Message Queue instance\n");
+ return NULL;
+ }
+ }
+
+ return inst_internal;
+}
+
+MessageQueue* MessageQueue::getInstanceExternal()
+{
+ if(inst_external == NULL)
+ {
+ inst_external = new MessageQueue();
+ if(inst_external == NULL)
+ {
+ IPACMERR("unable to create external Message Queue instance\n");
+ return NULL;
+ }
+ }
+
+ return inst_external;
+}
+
+void MessageQueue::enqueue(Message *item)
+{
+ if(!Head)
+ {
+ Tail = item;
+ Head = item;
+ }
+ else
+ {
+ if(Tail == NULL)
+ {
+ IPACMDBG("Tail is null\n");
+ Head->setnext(item);
+ }
+ else
+ {
+ Tail->setnext(item);
+ }
+ Tail = item;
+ }
+}
+
+
+Message* MessageQueue::dequeue(void)
+{
+ if(Head == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ Message *tmp = Head;
+ Head = Head->getnext();
+
+ return tmp;
+ }
+}
+
+
+void* MessageQueue::Process(void *param)
+{
+ MessageQueue *MsgQueueInternal = NULL;
+ MessageQueue *MsgQueueExternal = NULL;
+ Message *item = NULL;
+ param = NULL;
+
+ IPACMDBG("MessageQueue::Process()\n");
+
+ MsgQueueInternal = MessageQueue::getInstanceInternal();
+ if(MsgQueueInternal == NULL)
+ {
+ IPACMERR("unable to start internal cmd queue process\n");
+ return NULL;
+ }
+
+ MsgQueueExternal = MessageQueue::getInstanceExternal();
+ if(MsgQueueExternal == NULL)
+ {
+ IPACMERR("unable to start external cmd queue process\n");
+ return NULL;
+ }
+
+ while(1)
+ {
+ if(pthread_mutex_lock(&mutex) != 0)
+ {
+ IPACMERR("unable to lock the mutex\n");
+ return NULL;
+ }
+
+ item = MsgQueueInternal->dequeue();
+ if(item == NULL)
+ {
+ item = MsgQueueExternal->dequeue();
+ if(item)
+ {
+ IPACMDBG("Get event %s from external queue.\n",
+ IPACM_Iface::ipacmcfg->getEventName(item->evt.data.event));
+ }
+ }
+ else
+ {
+ IPACMDBG("Get event %s from internal queue.\n",
+ IPACM_Iface::ipacmcfg->getEventName(item->evt.data.event));
+ }
+
+ if(item == NULL)
+ {
+ IPACMDBG("Waiting for Message\n");
+
+ if(pthread_cond_wait(&cond_var, &mutex) != 0)
+ {
+ IPACMERR("unable to lock the mutex\n");
+
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return NULL;
+ }
+
+ return NULL;
+ }
+
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return NULL;
+ }
+
+ }
+ else
+ {
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return NULL;
+ }
+
+ IPACMDBG("Processing item %p event ID: %d\n",item,item->evt.data.event);
+ item->evt.callback_ptr(&item->evt.data);
+ delete item;
+ item = NULL;
+ }
+
+ } /* Go forever until a termination indication is received */
+
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Config.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Config.cpp
new file mode 100644
index 0000000..9e66367
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Config.cpp
@@ -0,0 +1,849 @@
+/*
+Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Config.cpp
+
+ @brief
+ This file implements the IPACM Configuration from XML file
+
+ @Author
+ Skylar Chang
+
+*/
+#include <IPACM_Config.h>
+#include <IPACM_Log.h>
+#include <IPACM_Iface.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+IPACM_Config *IPACM_Config::pInstance = NULL;
+const char *IPACM_Config::DEVICE_NAME = "/dev/ipa";
+const char *IPACM_Config::DEVICE_NAME_ODU = "/dev/odu_ipa_bridge";
+
+#define __stringify(x...) #x
+
+const char *ipacm_event_name[] = {
+ __stringify(IPA_CFG_CHANGE_EVENT), /* NULL */
+ __stringify(IPA_PRIVATE_SUBNET_CHANGE_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_FIREWALL_CHANGE_EVENT), /* NULL */
+ __stringify(IPA_LINK_UP_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_LINK_DOWN_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_USB_LINK_UP_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_BRIDGE_LINK_UP_EVENT), /* ipacm_event_data_all */
+ __stringify(IPA_WAN_EMBMS_LINK_UP_EVENT), /* ipacm_event_data_mac */
+ __stringify(IPA_ADDR_ADD_EVENT), /* ipacm_event_data_addr */
+ __stringify(IPA_ADDR_DEL_EVENT), /* no use */
+ __stringify(IPA_ROUTE_ADD_EVENT), /* ipacm_event_data_addr */
+ __stringify(IPA_ROUTE_DEL_EVENT), /* ipacm_event_data_addr */
+ __stringify(IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_WLAN_AP_LINK_UP_EVENT), /* ipacm_event_data_mac */
+ __stringify(IPA_WLAN_STA_LINK_UP_EVENT), /* ipacm_event_data_mac */
+ __stringify(IPA_WLAN_LINK_DOWN_EVENT), /* ipacm_event_data_mac */
+ __stringify(IPA_WLAN_CLIENT_ADD_EVENT), /* ipacm_event_data_mac */
+ __stringify(IPA_WLAN_CLIENT_ADD_EVENT_EX), /* ipacm_event_data_wlan_ex */
+ __stringify(IPA_WLAN_CLIENT_DEL_EVENT), /* ipacm_event_data_mac */
+ __stringify(IPA_WLAN_CLIENT_POWER_SAVE_EVENT), /* ipacm_event_data_mac */
+ __stringify(IPA_WLAN_CLIENT_RECOVER_EVENT), /* ipacm_event_data_mac */
+ __stringify(IPA_NEW_NEIGH_EVENT), /* ipacm_event_data_all */
+ __stringify(IPA_DEL_NEIGH_EVENT), /* ipacm_event_data_all */
+ __stringify(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT), /* ipacm_event_data_all */
+ __stringify(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT), /* ipacm_event_data_all */
+ __stringify(IPA_SW_ROUTING_ENABLE), /* NULL */
+ __stringify(IPA_SW_ROUTING_DISABLE), /* NULL */
+ __stringify(IPA_PROCESS_CT_MESSAGE), /* ipacm_ct_evt_data */
+ __stringify(IPA_PROCESS_CT_MESSAGE_V6), /* ipacm_ct_evt_data */
+ __stringify(IPA_LAN_TO_LAN_NEW_CONNECTION), /* ipacm_event_connection */
+ __stringify(IPA_LAN_TO_LAN_DEL_CONNECTION), /* ipacm_event_connection */
+ __stringify(IPA_WLAN_SWITCH_TO_SCC), /* No Data */
+ __stringify(IPA_WLAN_SWITCH_TO_MCC), /* No Data */
+ __stringify(IPA_CRADLE_WAN_MODE_SWITCH), /* ipacm_event_cradle_wan_mode */
+ __stringify(IPA_WAN_XLAT_CONNECT_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_TETHERING_STATS_UPDATE_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_NETWORK_STATS_UPDATE_EVENT), /* ipacm_event_data_fid */
+ __stringify(IPA_DOWNSTREAM_ADD), /* ipacm_event_ipahal_stream */
+ __stringify(IPA_DOWNSTREAM_DEL), /* ipacm_event_ipahal_stream */
+ __stringify(IPA_EXTERNAL_EVENT_MAX),
+ __stringify(IPA_HANDLE_WAN_UP), /* ipacm_event_iface_up */
+ __stringify(IPA_HANDLE_WAN_DOWN), /* ipacm_event_iface_up */
+ __stringify(IPA_HANDLE_WAN_UP_V6), /* NULL */
+ __stringify(IPA_HANDLE_WAN_DOWN_V6), /* NULL */
+ __stringify(IPA_HANDLE_WAN_UP_TETHER), /* ipacm_event_iface_up_tehter */
+ __stringify(IPA_HANDLE_WAN_DOWN_TETHER), /* ipacm_event_iface_up_tehter */
+ __stringify(IPA_HANDLE_WAN_UP_V6_TETHER), /* ipacm_event_iface_up_tehter */
+ __stringify(IPA_HANDLE_WAN_DOWN_V6_TETHER), /* ipacm_event_iface_up_tehter */
+ __stringify(IPA_HANDLE_WLAN_UP), /* ipacm_event_iface_up */
+ __stringify(IPA_HANDLE_LAN_UP), /* ipacm_event_iface_up */
+ __stringify(IPA_ETH_BRIDGE_IFACE_UP), /* ipacm_event_eth_bridge*/
+ __stringify(IPA_ETH_BRIDGE_IFACE_DOWN), /* ipacm_event_eth_bridge*/
+ __stringify(IPA_ETH_BRIDGE_CLIENT_ADD), /* ipacm_event_eth_bridge*/
+ __stringify(IPA_ETH_BRIDGE_CLIENT_DEL), /* ipacm_event_eth_bridge*/
+ __stringify(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH), /* ipacm_event_eth_bridge*/
+ __stringify(IPA_LAN_DELETE_SELF), /* ipacm_event_data_fid */
+#ifdef FEATURE_L2TP
+ __stringify(IPA_ADD_VLAN_IFACE), /* ipa_ioc_vlan_iface_info */
+ __stringify(IPA_DEL_VLAN_IFACE), /* ipa_ioc_vlan_iface_info */
+ __stringify(IPA_ADD_L2TP_VLAN_MAPPING), /* ipa_ioc_l2tp_vlan_mapping_info */
+ __stringify(IPA_DEL_L2TP_VLAN_MAPPING), /* ipa_ioc_l2tp_vlan_mapping_info */
+ __stringify(IPA_VLAN_CLIENT_INFO), /* ipacm_event_data_all */
+ __stringify(IPA_VLAN_IFACE_INFO), /* ipacm_event_data_all */
+#endif
+ __stringify(IPACM_EVENT_MAX),
+};
+
+IPACM_Config::IPACM_Config()
+{
+ iface_table = NULL;
+ alg_table = NULL;
+ pNatIfaces = NULL;
+ memset(&ipa_client_rm_map_tbl, 0, sizeof(ipa_client_rm_map_tbl));
+ memset(&ipa_rm_tbl, 0, sizeof(ipa_rm_tbl));
+ ipa_rm_a2_check=0;
+ ipacm_odu_enable = false;
+ ipacm_odu_router_mode = false;
+ ipa_num_wlan_guest_ap = 0;
+
+ ipa_num_ipa_interfaces = 0;
+ ipa_num_private_subnet = 0;
+ ipa_num_alg_ports = 0;
+ ipa_nat_max_entries = 0;
+ ipa_nat_iface_entries = 0;
+ ipa_sw_rt_enable = false;
+ ipa_bridge_enable = false;
+ isMCC_Mode = false;
+ ipa_max_valid_rm_entry = 0;
+
+ memset(&rt_tbl_default_v4, 0, sizeof(rt_tbl_default_v4));
+ memset(&rt_tbl_lan_v4, 0, sizeof(rt_tbl_lan_v4));
+ memset(&rt_tbl_wan_v4, 0, sizeof(rt_tbl_wan_v4));
+ memset(&rt_tbl_v6, 0, sizeof(rt_tbl_v6));
+ memset(&rt_tbl_wan_v6, 0, sizeof(rt_tbl_wan_v6));
+ memset(&rt_tbl_wan_dl, 0, sizeof(rt_tbl_wan_dl));
+ memset(&rt_tbl_odu_v4, 0, sizeof(rt_tbl_odu_v4));
+ memset(&rt_tbl_odu_v6, 0, sizeof(rt_tbl_odu_v6));
+
+ memset(&ext_prop_v4, 0, sizeof(ext_prop_v4));
+ memset(&ext_prop_v6, 0, sizeof(ext_prop_v6));
+
+ qmap_id = ~0;
+
+ memset(flt_rule_count_v4, 0, IPA_CLIENT_MAX*sizeof(int));
+ memset(flt_rule_count_v6, 0, IPA_CLIENT_MAX*sizeof(int));
+ memset(bridge_mac, 0, IPA_MAC_ADDR_SIZE*sizeof(uint8_t));
+
+ IPACMDBG_H(" create IPACM_Config constructor\n");
+ return;
+}
+
+int IPACM_Config::Init(void)
+{
+ /* Read IPACM Config file */
+ char IPACM_config_file[IPA_MAX_FILE_LEN];
+ IPACM_conf_t *cfg;
+ cfg = (IPACM_conf_t *)malloc(sizeof(IPACM_conf_t));
+ if(cfg == NULL)
+ {
+ IPACMERR("Unable to allocate cfg memory.\n");
+ return IPACM_FAILURE;
+ }
+ uint32_t subnet_addr;
+ uint32_t subnet_mask;
+ int i, ret = IPACM_SUCCESS;
+ struct in_addr in_addr_print;
+
+ m_fd = open(DEVICE_NAME, O_RDWR);
+ if (0 > m_fd)
+ {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ }
+#ifdef FEATURE_IPACM_HAL
+ strlcpy(IPACM_config_file, "/vendor/etc/IPACM_cfg.xml", sizeof(IPACM_config_file));
+#else
+ strlcpy(IPACM_config_file, "/etc/IPACM_cfg.xml", sizeof(IPACM_config_file));
+#endif
+ IPACMDBG_H("\n IPACM XML file is %s \n", IPACM_config_file);
+ if (IPACM_SUCCESS == ipacm_read_cfg_xml(IPACM_config_file, cfg))
+ {
+ IPACMDBG_H("\n IPACM XML read OK \n");
+ }
+ else
+ {
+ IPACMERR("\n IPACM XML read failed \n");
+ ret = IPACM_FAILURE;
+ goto fail;
+ }
+
+ /* Construct IPACM Iface table */
+ ipa_num_ipa_interfaces = cfg->iface_config.num_iface_entries;
+ if (iface_table != NULL)
+ {
+ free(iface_table);
+ iface_table = NULL;
+ IPACMDBG_H("RESET IPACM_Config::iface_table\n");
+ }
+ iface_table = (ipa_ifi_dev_name_t *)calloc(ipa_num_ipa_interfaces,
+ sizeof(ipa_ifi_dev_name_t));
+ if(iface_table == NULL)
+ {
+ IPACMERR("Unable to allocate iface_table memory.\n");
+ ret = IPACM_FAILURE;
+ goto fail;
+ }
+
+ for (i = 0; i < cfg->iface_config.num_iface_entries; i++)
+ {
+ strlcpy(iface_table[i].iface_name, cfg->iface_config.iface_entries[i].iface_name, sizeof(iface_table[i].iface_name));
+ iface_table[i].if_cat = cfg->iface_config.iface_entries[i].if_cat;
+ iface_table[i].if_mode = cfg->iface_config.iface_entries[i].if_mode;
+ iface_table[i].wlan_mode = cfg->iface_config.iface_entries[i].wlan_mode;
+ IPACMDBG_H("IPACM_Config::iface_table[%d] = %s, cat=%d, mode=%d wlan-mode=%d \n", i, iface_table[i].iface_name,
+ iface_table[i].if_cat, iface_table[i].if_mode, iface_table[i].wlan_mode);
+ /* copy bridge interface name to ipacmcfg */
+ if( iface_table[i].if_cat == VIRTUAL_IF)
+ {
+ strlcpy(ipa_virtual_iface_name, iface_table[i].iface_name, sizeof(ipa_virtual_iface_name));
+ IPACMDBG_H("ipa_virtual_iface_name(%s) \n", ipa_virtual_iface_name);
+ }
+ }
+
+ /* Construct IPACM Private_Subnet table */
+ memset(&private_subnet_table, 0, sizeof(private_subnet_table));
+ ipa_num_private_subnet = cfg->private_subnet_config.num_subnet_entries;
+
+ for (i = 0; i < cfg->private_subnet_config.num_subnet_entries; i++)
+ {
+ memcpy(&private_subnet_table[i].subnet_addr,
+ &cfg->private_subnet_config.private_subnet_entries[i].subnet_addr,
+ sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_addr));
+
+ memcpy(&private_subnet_table[i].subnet_mask,
+ &cfg->private_subnet_config.private_subnet_entries[i].subnet_mask,
+ sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_mask));
+
+ subnet_addr = htonl(private_subnet_table[i].subnet_addr);
+ memcpy(&in_addr_print,&subnet_addr,sizeof(in_addr_print));
+ IPACMDBG_H("%dst::private_subnet_table= %s \n ", i,
+ inet_ntoa(in_addr_print));
+
+ subnet_mask = htonl(private_subnet_table[i].subnet_mask);
+ memcpy(&in_addr_print,&subnet_mask,sizeof(in_addr_print));
+ IPACMDBG_H("%dst::private_subnet_table= %s \n ", i,
+ inet_ntoa(in_addr_print));
+ }
+
+ /* Construct IPACM ALG table */
+ ipa_num_alg_ports = cfg->alg_config.num_alg_entries;
+ if (alg_table != NULL)
+ {
+ free(alg_table);
+ alg_table = NULL;
+ IPACMDBG_H("RESET IPACM_Config::alg_table \n");
+ }
+ alg_table = (ipacm_alg *)calloc(ipa_num_alg_ports,
+ sizeof(ipacm_alg));
+ if(alg_table == NULL)
+ {
+ IPACMERR("Unable to allocate alg_table memory.\n");
+ ret = IPACM_FAILURE;
+ free(iface_table);
+ goto fail;;
+ }
+ for (i = 0; i < cfg->alg_config.num_alg_entries; i++)
+ {
+ alg_table[i].protocol = cfg->alg_config.alg_entries[i].protocol;
+ alg_table[i].port = cfg->alg_config.alg_entries[i].port;
+ IPACMDBG_H("IPACM_Config::ipacm_alg[%d] = %d, port=%d\n", i, alg_table[i].protocol, alg_table[i].port);
+ }
+
+ ipa_nat_max_entries = cfg->nat_max_entries;
+ IPACMDBG_H("Nat Maximum Entries %d\n", ipa_nat_max_entries);
+
+ /* Find ODU is either router mode or bridge mode*/
+ ipacm_odu_enable = cfg->odu_enable;
+ ipacm_odu_router_mode = cfg->router_mode_enable;
+ ipacm_odu_embms_enable = cfg->odu_embms_enable;
+ IPACMDBG_H("ipacm_odu_enable %d\n", ipacm_odu_enable);
+ IPACMDBG_H("ipacm_odu_mode %d\n", ipacm_odu_router_mode);
+ IPACMDBG_H("ipacm_odu_embms_enable %d\n", ipacm_odu_embms_enable);
+
+ ipacm_ip_passthrough_mode = cfg->ip_passthrough_mode;
+ IPACMDBG_H("ipacm_ip_passthrough_mode %d. \n", ipacm_ip_passthrough_mode);
+
+ ipa_num_wlan_guest_ap = cfg->num_wlan_guest_ap;
+ IPACMDBG_H("ipa_num_wlan_guest_ap %d\n",ipa_num_wlan_guest_ap);
+
+ /* Allocate more non-nat entries if the monitored iface dun have Tx/Rx properties */
+ if (pNatIfaces != NULL)
+ {
+ free(pNatIfaces);
+ pNatIfaces = NULL;
+ IPACMDBG_H("RESET IPACM_Config::pNatIfaces \n");
+ }
+ ipa_nat_iface_entries = 0;
+ pNatIfaces = (NatIfaces *)calloc(ipa_num_ipa_interfaces, sizeof(NatIfaces));
+ if (pNatIfaces == NULL)
+ {
+ IPACMERR("unable to allocate nat ifaces\n");
+ ret = IPACM_FAILURE;
+ free(iface_table);
+ free(alg_table);
+ goto fail;
+ }
+
+ /* Construct the routing table ictol name in iface static member*/
+ rt_tbl_default_v4.ip = IPA_IP_v4;
+ strlcpy(rt_tbl_default_v4.name, V4_DEFAULT_ROUTE_TABLE_NAME, sizeof(rt_tbl_default_v4.name));
+
+ rt_tbl_lan_v4.ip = IPA_IP_v4;
+ strlcpy(rt_tbl_lan_v4.name, V4_LAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_lan_v4.name));
+
+ rt_tbl_wan_v4.ip = IPA_IP_v4;
+ strlcpy(rt_tbl_wan_v4.name, V4_WAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_v4.name));
+
+ rt_tbl_v6.ip = IPA_IP_v6;
+ strlcpy(rt_tbl_v6.name, V6_COMMON_ROUTE_TABLE_NAME, sizeof(rt_tbl_v6.name));
+
+ rt_tbl_wan_v6.ip = IPA_IP_v6;
+ strlcpy(rt_tbl_wan_v6.name, V6_WAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_v6.name));
+
+ rt_tbl_odu_v4.ip = IPA_IP_v4;
+ strlcpy(rt_tbl_odu_v4.name, V4_ODU_ROUTE_TABLE_NAME, sizeof(rt_tbl_odu_v4.name));
+
+ rt_tbl_odu_v6.ip = IPA_IP_v6;
+ strlcpy(rt_tbl_odu_v6.name, V6_ODU_ROUTE_TABLE_NAME, sizeof(rt_tbl_odu_v6.name));
+
+ rt_tbl_wan_dl.ip = IPA_IP_MAX;
+ strlcpy(rt_tbl_wan_dl.name, WAN_DL_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_dl.name));
+
+ /* Construct IPACM ipa_client map to rm_resource table */
+ ipa_client_rm_map_tbl[IPA_CLIENT_WLAN1_PROD]= IPA_RM_RESOURCE_WLAN_PROD;
+ ipa_client_rm_map_tbl[IPA_CLIENT_USB_PROD]= IPA_RM_RESOURCE_USB_PROD;
+ ipa_client_rm_map_tbl[IPA_CLIENT_A5_WLAN_AMPDU_PROD]= IPA_RM_RESOURCE_HSIC_PROD;
+ ipa_client_rm_map_tbl[IPA_CLIENT_A2_EMBEDDED_PROD]= IPA_RM_RESOURCE_Q6_PROD;
+ ipa_client_rm_map_tbl[IPA_CLIENT_A2_TETHERED_PROD]= IPA_RM_RESOURCE_Q6_PROD;
+ ipa_client_rm_map_tbl[IPA_CLIENT_APPS_LAN_WAN_PROD]= IPA_RM_RESOURCE_Q6_PROD;
+ ipa_client_rm_map_tbl[IPA_CLIENT_WLAN1_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_WLAN2_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_WLAN3_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_WLAN4_CONS]= IPA_RM_RESOURCE_WLAN_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_USB_CONS]= IPA_RM_RESOURCE_USB_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_A2_EMBEDDED_CONS]= IPA_RM_RESOURCE_Q6_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_A2_TETHERED_CONS]= IPA_RM_RESOURCE_Q6_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_APPS_WAN_CONS]= IPA_RM_RESOURCE_Q6_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_ODU_PROD]= IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+ ipa_client_rm_map_tbl[IPA_CLIENT_ODU_EMB_CONS]= IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+ ipa_client_rm_map_tbl[IPA_CLIENT_ODU_TETH_CONS]= IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+
+ /* Create the entries which IPACM wants to add dependencies on */
+ ipa_rm_tbl[0].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
+ ipa_rm_tbl[0].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
+ ipa_rm_tbl[0].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
+ ipa_rm_tbl[0].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
+
+ ipa_rm_tbl[1].producer_rm1 = IPA_RM_RESOURCE_USB_PROD;
+ ipa_rm_tbl[1].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
+ ipa_rm_tbl[1].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
+ ipa_rm_tbl[1].consumer_rm2 = IPA_RM_RESOURCE_USB_CONS;
+
+ ipa_rm_tbl[2].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
+ ipa_rm_tbl[2].consumer_rm1 = IPA_RM_RESOURCE_USB_CONS;
+ ipa_rm_tbl[2].producer_rm2 = IPA_RM_RESOURCE_USB_PROD;
+ ipa_rm_tbl[2].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
+
+ ipa_rm_tbl[3].producer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+ ipa_rm_tbl[3].consumer_rm1 = IPA_RM_RESOURCE_Q6_CONS;
+ ipa_rm_tbl[3].producer_rm2 = IPA_RM_RESOURCE_Q6_PROD;
+ ipa_rm_tbl[3].consumer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+
+ ipa_rm_tbl[4].producer_rm1 = IPA_RM_RESOURCE_WLAN_PROD;
+ ipa_rm_tbl[4].consumer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+ ipa_rm_tbl[4].producer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+ ipa_rm_tbl[4].consumer_rm2 = IPA_RM_RESOURCE_WLAN_CONS;
+
+ ipa_rm_tbl[5].producer_rm1 = IPA_RM_RESOURCE_ODU_ADAPT_PROD;
+ ipa_rm_tbl[5].consumer_rm1 = IPA_RM_RESOURCE_USB_CONS;
+ ipa_rm_tbl[5].producer_rm2 = IPA_RM_RESOURCE_USB_PROD;
+ ipa_rm_tbl[5].consumer_rm2 = IPA_RM_RESOURCE_ODU_ADAPT_CONS;
+ ipa_max_valid_rm_entry = 6; /* max is IPA_MAX_RM_ENTRY (6)*/
+
+ IPACMDBG_H(" depend MAP-0 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_Q6_CONS);
+ IPACMDBG_H(" depend MAP-1 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_USB_PROD, IPA_RM_RESOURCE_Q6_CONS);
+ IPACMDBG_H(" depend MAP-2 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_USB_CONS);
+ IPACMDBG_H(" depend MAP-3 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_Q6_CONS);
+ IPACMDBG_H(" depend MAP-4 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_WLAN_PROD, IPA_RM_RESOURCE_ODU_ADAPT_CONS);
+ IPACMDBG_H(" depend MAP-5 rm index %d to rm index: %d \n", IPA_RM_RESOURCE_ODU_ADAPT_PROD, IPA_RM_RESOURCE_USB_CONS);
+
+fail:
+ if (cfg != NULL)
+ {
+ free(cfg);
+ cfg = NULL;
+ }
+
+ return ret;
+}
+
+IPACM_Config* IPACM_Config::GetInstance()
+{
+ int res = IPACM_SUCCESS;
+
+ if (pInstance == NULL)
+ {
+ pInstance = new IPACM_Config();
+
+ res = pInstance->Init();
+ if (res != IPACM_SUCCESS)
+ {
+ delete pInstance;
+ IPACMERR("unable to initialize config instance\n");
+ return NULL;
+ }
+ }
+
+ return pInstance;
+}
+
+int IPACM_Config::GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts)
+{
+ if (nPorts <= 0 || pAlgPorts == NULL)
+ {
+ IPACMERR("Invalid input\n");
+ return -1;
+ }
+
+ for (int cnt = 0; cnt < nPorts; cnt++)
+ {
+ pAlgPorts[cnt].protocol = alg_table[cnt].protocol;
+ pAlgPorts[cnt].port = alg_table[cnt].port;
+ }
+
+ return 0;
+}
+
+int IPACM_Config::GetNatIfaces(int nIfaces, NatIfaces *pIfaces)
+{
+ if (nIfaces <= 0 || pIfaces == NULL)
+ {
+ IPACMERR("Invalid input\n");
+ return -1;
+ }
+
+ for (int cnt=0; cnt<nIfaces; cnt++)
+ {
+ memcpy(pIfaces[cnt].iface_name,
+ pNatIfaces[cnt].iface_name,
+ sizeof(pIfaces[cnt].iface_name));
+ }
+
+ return 0;
+}
+
+
+int IPACM_Config::AddNatIfaces(char *dev_name)
+{
+ int i;
+ /* Check if this iface already in NAT-iface*/
+ for(i = 0; i < ipa_nat_iface_entries; i++)
+ {
+ if(strncmp(dev_name,
+ pNatIfaces[i].iface_name,
+ sizeof(pNatIfaces[i].iface_name)) == 0)
+ {
+ IPACMDBG("Interface (%s) is add to nat iface already\n", dev_name);
+ return 0;
+ }
+ }
+
+ IPACMDBG_H("Add iface %s to NAT-ifaces, origin it has %d nat ifaces\n",
+ dev_name, ipa_nat_iface_entries);
+ ipa_nat_iface_entries++;
+
+ if (ipa_nat_iface_entries < ipa_num_ipa_interfaces)
+ {
+ strlcpy(pNatIfaces[ipa_nat_iface_entries - 1].iface_name,
+ dev_name, IPA_IFACE_NAME_LEN);
+
+ IPACMDBG_H("Add Nat IfaceName: %s ,update nat-ifaces number: %d\n",
+ pNatIfaces[ipa_nat_iface_entries - 1].iface_name,
+ ipa_nat_iface_entries);
+ }
+
+ return 0;
+}
+
+int IPACM_Config::DelNatIfaces(char *dev_name)
+{
+ int i = 0;
+ IPACMDBG_H("Del iface %s from NAT-ifaces, origin it has %d nat ifaces\n",
+ dev_name, ipa_nat_iface_entries);
+
+ for (i = 0; i < ipa_nat_iface_entries; i++)
+ {
+ if (strcmp(dev_name, pNatIfaces[i].iface_name) == 0)
+ {
+ IPACMDBG_H("Found Nat IfaceName: %s with nat-ifaces number: %d\n",
+ pNatIfaces[i].iface_name, ipa_nat_iface_entries);
+
+ /* Reset the matched entry */
+ memset(pNatIfaces[i].iface_name, 0, IPA_IFACE_NAME_LEN);
+
+ for (; i < ipa_nat_iface_entries - 1; i++)
+ {
+ memcpy(pNatIfaces[i].iface_name,
+ pNatIfaces[i + 1].iface_name, IPA_IFACE_NAME_LEN);
+
+ /* Reset the copied entry */
+ memset(pNatIfaces[i + 1].iface_name, 0, IPA_IFACE_NAME_LEN);
+ }
+ ipa_nat_iface_entries--;
+ IPACMDBG_H("Update nat-ifaces number: %d\n", ipa_nat_iface_entries);
+ return 0;
+ }
+ }
+
+ IPACMDBG_H("Can't find Nat IfaceName: %s with total nat-ifaces number: %d\n",
+ dev_name, ipa_nat_iface_entries);
+ return 0;
+}
+
+int IPACM_Config::CheckNatIfaces(const char *dev_name)
+{
+ int i = 0;
+ IPACMDBG_H("Check iface %s from NAT-ifaces, currently it has %d nat ifaces\n",
+ dev_name, ipa_nat_iface_entries);
+
+ for (i = 0; i < ipa_nat_iface_entries; i++)
+ {
+ if (strcmp(dev_name, pNatIfaces[i].iface_name) == 0)
+ {
+ IPACMDBG_H("Find Nat IfaceName: %s ,previous nat-ifaces number: %d\n",
+ pNatIfaces[i].iface_name, ipa_nat_iface_entries);
+ return 0;
+ }
+ }
+ IPACMDBG_H("Can't find Nat IfaceName: %s with total nat-ifaces number: %d\n",
+ dev_name, ipa_nat_iface_entries);
+ return -1;
+}
+
+/* for IPACM resource manager dependency usage
+ add either Tx or Rx ipa_rm_resource_name and
+ also indicate that endpoint property if valid */
+void IPACM_Config::AddRmDepend(ipa_rm_resource_name rm1,bool rx_bypass_ipa)
+{
+ int retval = 0;
+ struct ipa_ioc_rm_dependency dep;
+
+ IPACMDBG_H(" Got rm add-depend index : %d \n", rm1);
+ /* ipa_rm_a2_check: IPA_RM_RESOURCE_Q6_CONS*/
+ if(rm1 == IPA_RM_RESOURCE_Q6_CONS)
+ {
+ ipa_rm_a2_check+=1;
+ IPACMDBG_H("got %d times default RT routing from A2 \n", ipa_rm_a2_check);
+ }
+
+ for(int i=0;i<ipa_max_valid_rm_entry;i++)
+ {
+ if(rm1 == ipa_rm_tbl[i].producer_rm1)
+ {
+ ipa_rm_tbl[i].producer1_up = true;
+ /* entry1's producer actually dun have registered Rx-property */
+ ipa_rm_tbl[i].rx_bypass_ipa = rx_bypass_ipa;
+ IPACMDBG_H("Matched RM_table entry: %d's producer_rm1 with non_rx_prop: %d \n", i,ipa_rm_tbl[i].rx_bypass_ipa);
+
+ if(ipa_rm_tbl[i].consumer1_up == true && ipa_rm_tbl[i].rm_set == false)
+ {
+ IPACMDBG_H("SETUP RM_table entry %d's bi-direction dependency \n", i);
+ /* add bi-directional dependency*/
+ if(ipa_rm_tbl[i].rx_bypass_ipa)
+ {
+ IPACMDBG_H("Skip ADD entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
+ }
+ else
+ {
+ memset(&dep, 0, sizeof(dep));
+ dep.resource_name = ipa_rm_tbl[i].producer_rm1;
+ dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
+ retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
+ IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+ if (retval)
+ {
+ IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+ }
+ }
+ memset(&dep, 0, sizeof(dep));
+ dep.resource_name = ipa_rm_tbl[i].producer_rm2;
+ dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
+ retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
+ IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+ if (retval)
+ {
+ IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+ }
+ ipa_rm_tbl[i].rm_set = true;
+ }
+ else
+ {
+ IPACMDBG_H("Not SETUP RM_table entry %d: prod_up:%d, cons_up:%d, rm_set: %d \n", i,ipa_rm_tbl[i].producer1_up, ipa_rm_tbl[i].consumer1_up, ipa_rm_tbl[i].rm_set);
+ }
+ }
+
+ if(rm1 == ipa_rm_tbl[i].consumer_rm1)
+ {
+ ipa_rm_tbl[i].consumer1_up = true;
+ IPACMDBG_H("Matched RM_table entry: %d's consumer_rm1 \n", i);
+
+ if(ipa_rm_tbl[i].producer1_up == true && ipa_rm_tbl[i].rm_set == false)
+ {
+ IPACMDBG_H("SETUP RM_table entry %d's bi-direction dependency \n", i);
+ /* add bi-directional dependency*/
+ if(ipa_rm_tbl[i].rx_bypass_ipa)
+ {
+ IPACMDBG_H("Skip ADD entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
+ }
+ else
+ {
+ memset(&dep, 0, sizeof(dep));
+ dep.resource_name = ipa_rm_tbl[i].producer_rm1;
+ dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
+ retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
+ IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+ if (retval)
+ {
+ IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+ }
+ }
+
+ memset(&dep, 0, sizeof(dep));
+ dep.resource_name = ipa_rm_tbl[i].producer_rm2;
+ dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
+ retval = ioctl(m_fd, IPA_IOC_RM_ADD_DEPENDENCY, &dep);
+ IPACMDBG_H("ADD entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+ if (retval)
+ {
+ IPACMERR("Failed adding dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+ }
+ ipa_rm_tbl[i].rm_set = true;
+ }
+ else
+ {
+ IPACMDBG_H("Not SETUP RM_table entry %d: prod_up:%d, cons_up:%d, rm_set: %d \n", i,ipa_rm_tbl[i].producer1_up, ipa_rm_tbl[i].consumer1_up, ipa_rm_tbl[i].rm_set);
+ }
+ }
+ }
+ return ;
+}
+
+/* for IPACM resource manager dependency usage
+ delete either Tx or Rx ipa_rm_resource_name */
+
+void IPACM_Config::DelRmDepend(ipa_rm_resource_name rm1)
+{
+ int retval = 0;
+ struct ipa_ioc_rm_dependency dep;
+
+ IPACMDBG_H(" Got rm del-depend index : %d \n", rm1);
+ /* ipa_rm_a2_check: IPA_RM_RESOURCE_Q6_CONS*/
+ if(rm1 == IPA_RM_RESOURCE_Q6_CONS)
+ {
+ ipa_rm_a2_check-=1;
+ IPACMDBG_H("Left %d times default RT routing from A2 \n", ipa_rm_a2_check);
+ }
+
+ for(int i=0;i<ipa_max_valid_rm_entry;i++)
+ {
+
+ if(rm1 == ipa_rm_tbl[i].producer_rm1)
+ {
+ if(ipa_rm_tbl[i].rm_set == true)
+ {
+ IPACMDBG_H("Matched RM_table entry: %d's producer_rm1 and dependency is up \n", i);
+ ipa_rm_tbl[i].rm_set = false;
+
+ /* delete bi-directional dependency*/
+ if(ipa_rm_tbl[i].rx_bypass_ipa)
+ {
+ IPACMDBG_H("Skip DEL entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
+ }
+ else
+ {
+ memset(&dep, 0, sizeof(dep));
+ dep.resource_name = ipa_rm_tbl[i].producer_rm1;
+ dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
+ retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
+ IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+ if (retval)
+ {
+ IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+ }
+ }
+ memset(&dep, 0, sizeof(dep));
+ dep.resource_name = ipa_rm_tbl[i].producer_rm2;
+ dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
+ retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
+ IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+ if (retval)
+ {
+ IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+ }
+ }
+ ipa_rm_tbl[i].producer1_up = false;
+ ipa_rm_tbl[i].rx_bypass_ipa = false;
+ }
+ if(rm1 == ipa_rm_tbl[i].consumer_rm1)
+ {
+ /* ipa_rm_a2_check: IPA_RM_RESOURCE_!6_CONS*/
+ if(ipa_rm_tbl[i].consumer_rm1 == IPA_RM_RESOURCE_Q6_CONS && ipa_rm_a2_check == 1)
+ {
+ IPACMDBG_H(" still have %d default RT routing from A2 \n", ipa_rm_a2_check);
+ continue;
+ }
+
+ if(ipa_rm_tbl[i].rm_set == true)
+ {
+ IPACMDBG_H("Matched RM_table entry: %d's consumer_rm1 and dependency is up \n", i);
+ ipa_rm_tbl[i].rm_set = false;
+ /* delete bi-directional dependency*/
+ if(ipa_rm_tbl[i].rx_bypass_ipa)
+ {
+ IPACMDBG_H("Skip DEL entry %d's dependency between WLAN-Pro: %d, Con: %d \n", i, ipa_rm_tbl[i].producer_rm1,ipa_rm_tbl[i].consumer_rm1);
+ }
+ else
+ {
+ memset(&dep, 0, sizeof(dep));
+ dep.resource_name = ipa_rm_tbl[i].producer_rm1;
+ dep.depends_on_name = ipa_rm_tbl[i].consumer_rm1;
+ retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
+ IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+ if (retval)
+ {
+ IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+ }
+ }
+
+ memset(&dep, 0, sizeof(dep));
+ dep.resource_name = ipa_rm_tbl[i].producer_rm2;
+ dep.depends_on_name = ipa_rm_tbl[i].consumer_rm2;
+ retval = ioctl(m_fd, IPA_IOC_RM_DEL_DEPENDENCY, &dep);
+ IPACMDBG_H("Delete entry %d's dependency between Pro: %d, Con: %d \n", i,dep.resource_name,dep.depends_on_name);
+ if (retval)
+ {
+ IPACMERR("Failed deleting dependecny for RM_table entry %d's bi-direction dependency (error:%d) \n", i,retval);
+ }
+ }
+ ipa_rm_tbl[i].consumer1_up = false;
+ }
+ }
+ return ;
+}
+
+int IPACM_Config::SetExtProp(ipa_ioc_query_intf_ext_props *prop)
+{
+ int i, num;
+
+ if(prop == NULL || prop->num_ext_props <= 0)
+ {
+ IPACMERR("There is no extended property!\n");
+ return IPACM_FAILURE;
+ }
+
+ num = prop->num_ext_props;
+ for(i=0; i<num; i++)
+ {
+ if(prop->ext[i].ip == IPA_IP_v4)
+ {
+ if(ext_prop_v4.num_ext_props >= MAX_NUM_EXT_PROPS)
+ {
+ IPACMERR("IPv4 extended property table is full!\n");
+ continue;
+ }
+ memcpy(&ext_prop_v4.prop[ext_prop_v4.num_ext_props], &prop->ext[i], sizeof(struct ipa_ioc_ext_intf_prop));
+ ext_prop_v4.num_ext_props++;
+ }
+ else if(prop->ext[i].ip == IPA_IP_v6)
+ {
+ if(ext_prop_v6.num_ext_props >= MAX_NUM_EXT_PROPS)
+ {
+ IPACMERR("IPv6 extended property table is full!\n");
+ continue;
+ }
+ memcpy(&ext_prop_v6.prop[ext_prop_v6.num_ext_props], &prop->ext[i], sizeof(struct ipa_ioc_ext_intf_prop));
+ ext_prop_v6.num_ext_props++;
+ }
+ else
+ {
+ IPACMERR("The IP type is not expected!\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ IPACMDBG_H("Set extended property succeeded.\n");
+
+ return IPACM_SUCCESS;
+}
+
+ipacm_ext_prop* IPACM_Config::GetExtProp(ipa_ip_type ip_type)
+{
+ if(ip_type == IPA_IP_v4)
+ return &ext_prop_v4;
+ else if(ip_type == IPA_IP_v6)
+ return &ext_prop_v6;
+ else
+ {
+ IPACMERR("Failed to get extended property: the IP version is neither IPv4 nor IPv6!\n");
+ return NULL;
+ }
+}
+
+int IPACM_Config::DelExtProp(ipa_ip_type ip_type)
+{
+ if(ip_type != IPA_IP_v6)
+ {
+ memset(&ext_prop_v4, 0, sizeof(ext_prop_v4));
+ }
+
+ if(ip_type != IPA_IP_v4)
+ {
+ memset(&ext_prop_v6, 0, sizeof(ext_prop_v6));
+ }
+
+ return IPACM_SUCCESS;
+}
+
+const char* IPACM_Config::getEventName(ipa_cm_event_id event_id)
+{
+ if(event_id >= sizeof(ipacm_event_name)/sizeof(ipacm_event_name[0]))
+ {
+ IPACMERR("Event name array is not consistent with event array!\n");
+ return NULL;
+ }
+
+ return ipacm_event_name[event_id];
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_ConntrackClient.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_ConntrackClient.cpp
new file mode 100644
index 0000000..3eab6fa
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_ConntrackClient.cpp
@@ -0,0 +1,741 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include "IPACM_Iface.h"
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_Log.h"
+
+#define LO_NAME "lo"
+
+extern IPACM_EvtDispatcher cm_dis;
+extern void ParseCTMessage(struct nf_conntrack *ct);
+
+IPACM_ConntrackClient *IPACM_ConntrackClient::pInstance = NULL;
+IPACM_ConntrackListener *CtList = NULL;
+
+/* ================================
+ Local Function Definitions
+ =================================
+*/
+IPACM_ConntrackClient::IPACM_ConntrackClient()
+{
+ IPACMDBG("\n");
+
+ tcp_hdl = NULL;
+ udp_hdl = NULL;
+ tcp_filter = NULL;
+ udp_filter = NULL;
+ fd_tcp = -1;
+ fd_udp = -1;
+ subscrips_tcp = NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY;
+ subscrips_udp = NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY;
+}
+
+IPACM_ConntrackClient* IPACM_ConntrackClient::GetInstance()
+{
+ if(pInstance == NULL)
+ {
+ pInstance = new IPACM_ConntrackClient();
+
+ pInstance->udp_filter = nfct_filter_create();
+ if(pInstance->udp_filter == NULL)
+ {
+ IPACMERR("unable to create UDP filter\n");
+ delete pInstance;
+ return NULL;
+ }
+ IPACMDBG("Created UDP filter\n");
+
+ pInstance->tcp_filter = nfct_filter_create();
+ if(pInstance->tcp_filter == NULL)
+ {
+ IPACMERR("unable to create TCP filter\n");
+ delete pInstance;
+ return NULL;
+ }
+ IPACMDBG("Created TCP filter\n");
+ }
+
+ return pInstance;
+}
+
+int IPACM_ConntrackClient::IPAConntrackEventCB
+(
+ enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ void *data
+ )
+{
+ ipacm_cmd_q_data evt_data;
+ ipacm_ct_evt_data *ct_data;
+ uint8_t ip_type = 0;
+ data = NULL;
+
+ IPACMDBG("Event callback called with msgtype: %d\n",type);
+
+ /* Retrieve ip type */
+ ip_type = nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO);
+
+#ifndef CT_OPT
+ if(AF_INET6 == ip_type)
+ {
+ IPACMDBG("Ignoring ipv6(%d) connections\n", ip_type);
+ goto IGNORE;
+ }
+
+#endif
+
+ ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
+ if(ct_data == NULL)
+ {
+ IPACMERR("unable to allocate memory \n");
+ goto IGNORE;
+ }
+
+ ct_data->ct = ct;
+ ct_data->type = type;
+
+ evt_data.event = IPA_PROCESS_CT_MESSAGE;
+ evt_data.evt_data = (void *)ct_data;
+
+#ifdef CT_OPT
+ if(AF_INET6 == ip_type)
+ {
+ evt_data.event = IPA_PROCESS_CT_MESSAGE_V6;
+ }
+#endif
+
+ if(0 != IPACM_EvtDispatcher::PostEvt(&evt_data))
+ {
+ IPACMERR("Error sending Conntrack message to processing thread!\n");
+ free(ct_data);
+ goto IGNORE;
+ }
+
+/* NFCT_CB_STOLEN means that the conntrack object is not released after the
+ callback That must be manually done later when the object is no longer needed. */
+ return NFCT_CB_STOLEN;
+
+IGNORE:
+ nfct_destroy(ct);
+ return NFCT_CB_STOLEN;
+
+}
+
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Bridge_Addrs
+(
+ struct nfct_filter *filter
+)
+{
+ int fd;
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if(fd < 0)
+ {
+ PERROR("unable to open socket");
+ return -1;
+ }
+
+ int ret;
+ uint32_t ipv4_addr;
+ struct ifreq ifr;
+
+ /* retrieve bridge interface ipv4 address */
+ memset(&ifr, 0, sizeof(struct ifreq));
+ ifr.ifr_addr.sa_family = AF_INET;
+ (void)strlcpy(ifr.ifr_name, IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, sizeof(ifr.ifr_name));
+ IPACMDBG("bridge interface name (%s)\n", ifr.ifr_name);
+
+ if(strlen(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name) >= sizeof(ifr.ifr_name))
+ {
+ IPACMERR("interface name overflows: len %zu\n",
+ strlen(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name));
+ close(fd);
+ return -1;
+ }
+
+ ret = ioctl(fd, SIOCGIFADDR, &ifr);
+ if (ret < 0)
+ {
+ IPACMERR("unable to retrieve (%s) interface address\n",ifr.ifr_name);
+ close(fd);
+ return -1;
+ }
+ IPACMDBG("Interface (%s) address %s\n", ifr.ifr_name, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
+ ipv4_addr = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
+ close(fd);
+
+ /* ignore whatever is destined to or originates from broadcast ip address */
+ struct nfct_filter_ipv4 filter_ipv4;
+
+ filter_ipv4.addr = ipv4_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+ return 0;
+}
+
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Iface
+(
+ struct nfct_filter *filter,
+ ipacm_event_iface_up *param
+)
+{
+ struct nfct_filter_ipv4 filter_ipv4;
+
+ filter_ipv4.addr = param->ipv4_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ /* ignore whatever is destined to local interfaces */
+ IPACMDBG("Ignore connections destinated to interface %s", param->ifname);
+ iptodot("with ipv4 address", param->ipv4_addr);
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ IPACMDBG("Ignore connections orignated from interface %s", param->ifname);
+ iptodot("with ipv4 address", filter_ipv4.addr);
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+ /* Retrieve broadcast address */
+ /* Intialize with 255.255.255.255 */
+ uint32_t bc_ip_addr = 0xFFFFFFFF;
+
+ /* calculate broadcast address from addr and addr_mask */
+ bc_ip_addr = (bc_ip_addr & (~param->addr_mask));
+ bc_ip_addr = (bc_ip_addr | (param->ipv4_addr & param->addr_mask));
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = bc_ip_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ iptodot("with broadcast address", filter_ipv4.addr);
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ return 0;
+}
+
+/* Function which sets up filters to ignore
+ connections to and from local interfaces */
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Addrs
+(
+ struct nfct_filter *filter
+)
+{
+ struct nfct_filter_ipv4 filter_ipv4;
+
+ /* ignore whatever is destined to or originates from broadcast ip address */
+ filter_ipv4.addr = 0xffffffff;
+ filter_ipv4.mask = 0xffffffff;
+
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+ return 0;
+} /* IPA_Conntrack_Filters_Ignore_Local_Addrs() */
+
+/* Initialize TCP Filter */
+int IPACM_ConntrackClient::IPA_Conntrack_TCP_Filter_Init(void)
+{
+ int ret = 0;
+ IPACM_ConntrackClient *pClient;
+
+ IPACMDBG("\n");
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to get conntrack client instance\n");
+ return -1;
+ }
+
+ ret = nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ if(ret == -1)
+ {
+ IPACMERR("Unable to set filter logic\n");
+ return -1;
+ }
+
+ /* set protocol filters as tcp and udp */
+ nfct_filter_add_attr_u32(pClient->tcp_filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
+
+
+ struct nfct_filter_proto tcp_proto_state;
+ tcp_proto_state.proto = IPPROTO_TCP;
+ tcp_proto_state.state = TCP_CONNTRACK_ESTABLISHED;
+
+ ret = nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO_STATE,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ if(ret == -1)
+ {
+ IPACMERR("unable to set filter logic\n");
+ return -1;
+ }
+ nfct_filter_add_attr(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO_STATE,
+ &tcp_proto_state);
+
+
+ tcp_proto_state.proto = IPPROTO_TCP;
+ tcp_proto_state.state = TCP_CONNTRACK_FIN_WAIT;
+ ret = nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO_STATE,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ if(ret == -1)
+ {
+ IPACMERR("unable to set filter logic\n");
+ return -1;
+ }
+
+ nfct_filter_add_attr(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO_STATE,
+ &tcp_proto_state);
+ return 0;
+}
+
+
+/* Initialize UDP Filter */
+int IPACM_ConntrackClient::IPA_Conntrack_UDP_Filter_Init(void)
+{
+ int ret = 0;
+ IPACM_ConntrackClient *pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to get conntrack client instance\n");
+ return -1;
+ }
+
+ ret = nfct_filter_set_logic(pClient->udp_filter,
+ NFCT_FILTER_L4PROTO,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ if(ret == -1)
+ {
+ IPACMERR("unable to set filter logic\n");
+ }
+ /* set protocol filters as tcp and udp */
+ nfct_filter_add_attr_u32(pClient->udp_filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
+
+ return 0;
+}
+
+void* IPACM_ConntrackClient::UDPConnTimeoutUpdate(void *ptr)
+{
+ NatApp *nat_inst = NULL;
+ ptr = NULL;
+#ifdef IPACM_DEBUG
+ IPACMDBG("\n");
+#endif
+
+ nat_inst = NatApp::GetInstance();
+ if(nat_inst == NULL)
+ {
+ IPACMERR("unable to create nat instance\n");
+ return NULL;
+ }
+
+ while(1)
+ {
+ nat_inst->UpdateUDPTimeStamp();
+ sleep(UDP_TIMEOUT_UPDATE);
+ } /* end of while(1) loop */
+
+#ifdef IPACM_DEBUG
+ IPACMDBG("Returning from %s() %d\n", __FUNCTION__, __LINE__);
+#endif
+
+ return NULL;
+}
+
+/* Thread to initialize TCP Conntrack Filters*/
+void* IPACM_ConntrackClient::TCPRegisterWithConnTrack(void *)
+{
+ int ret;
+ IPACM_ConntrackClient *pClient;
+ unsigned subscrips = 0;
+
+ IPACMDBG("\n");
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to get conntrack client instance\n");
+ return NULL;
+ }
+
+ subscrips = (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
+#ifdef CT_OPT
+ subscrips |= NF_NETLINK_CONNTRACK_NEW;
+#endif
+
+#ifdef FEATURE_IPACM_HAL
+ if (pClient->fd_tcp < 0) {
+ IPACMERR("unable to get conntrack TCP handle due to fd_tcp is invalid \n");
+ return NULL;
+ } else {
+ pClient->tcp_hdl = nfct_open2(CONNTRACK, subscrips, pClient->fd_tcp);
+ }
+#else
+ pClient->tcp_hdl = nfct_open(CONNTRACK, subscrips);
+#endif
+
+ if(pClient->tcp_hdl == NULL)
+ {
+ PERROR("nfct_open failed on getting tcp_hdl\n");
+ return NULL;
+ }
+
+ /* Initialize the filter */
+ ret = IPA_Conntrack_TCP_Filter_Init();
+ if(ret == -1)
+ {
+ IPACMERR("Unable to initliaze TCP Filter\n");
+ return NULL;
+ }
+
+ /* Attach the filter to net filter handler */
+ ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
+ if(ret == -1)
+ {
+ IPACMDBG("unable to attach TCP filter\n");
+ return NULL;
+ }
+
+ /* Register callback with netfilter handler */
+ IPACMDBG_H("tcp handle:%pK, fd:%d\n", pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl));
+#ifndef CT_OPT
+ nfct_callback_register(pClient->tcp_hdl,
+ (nf_conntrack_msg_type) (NFCT_T_UPDATE | NFCT_T_DESTROY | NFCT_T_NEW),
+ IPAConntrackEventCB, NULL);
+#else
+ nfct_callback_register(pClient->tcp_hdl, (nf_conntrack_msg_type) NFCT_T_ALL, IPAConntrackEventCB, NULL);
+#endif
+
+ /* Block to catch events from net filter connection track */
+ /* nfct_catch() receives conntrack events from kernel-space, by default it
+ blocks waiting for events. */
+ IPACMDBG("Waiting for events\n");
+
+ ret = nfct_catch(pClient->tcp_hdl);
+ if(ret == -1)
+ {
+ IPACMERR("(%d)(%s)\n", ret, strerror(errno));
+ return NULL;
+ }
+
+ IPACMDBG("Exit from tcp thread\n");
+
+ /* destroy the filter.. this will not detach the filter */
+ nfct_filter_destroy(pClient->tcp_filter);
+ pClient->tcp_filter = NULL;
+
+ /* de-register the callback */
+ nfct_callback_unregister(pClient->tcp_hdl);
+ /* close the handle */
+#ifdef FEATURE_IPACM_HAL
+ nfct_close2(pClient->tcp_hdl, true);
+#else
+ nfct_close(pClient->tcp_hdl);
+#endif
+ 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;
+ }
+
+#ifdef FEATURE_IPACM_HAL
+ if (pClient->fd_udp < 0) {
+ IPACMERR("unable to get conntrack UDP handle due to fd_udp is invalid \n");
+ return NULL;
+ } else {
+ pClient->udp_hdl = nfct_open2(CONNTRACK,
+ (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY), pClient->fd_udp);
+ }
+#else
+ pClient->udp_hdl = nfct_open(CONNTRACK,
+ (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY));
+#endif
+ if(pClient->udp_hdl == NULL)
+ {
+ PERROR("nfct_open failed on getting udp_hdl\n");
+ return NULL;
+ }
+
+ /* Initialize Filter */
+ ret = IPA_Conntrack_UDP_Filter_Init();
+ if(-1 == ret)
+ {
+ IPACMDBG("Unable to initalize udp filters\n");
+ return NULL;
+ }
+
+ /* Attach the filter to net filter handler */
+ ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
+ if(ret == -1)
+ {
+ IPACMDBG("unable to attach the filter\n");
+ return NULL;
+ }
+
+ /* Register callback with netfilter handler */
+ IPACMDBG_H("udp handle:%pK, fd:%d\n", pClient->udp_hdl, nfct_fd(pClient->udp_hdl));
+ nfct_callback_register(pClient->udp_hdl,
+ (nf_conntrack_msg_type)(NFCT_T_NEW | NFCT_T_DESTROY),
+ IPAConntrackEventCB,
+ NULL);
+
+ /* Block to catch events from net filter connection track */
+ctcatch:
+ ret = nfct_catch(pClient->udp_hdl);
+ if(ret == -1)
+ {
+ IPACMDBG("(%d)(%s)\n", ret, strerror(errno));
+ return NULL;
+ }
+ else
+ {
+ IPACMDBG("ctcatch ret:%d\n", ret);
+ goto ctcatch;
+ }
+
+ IPACMDBG("Exit from udp thread with ret: %d\n", ret);
+
+ /* destroy the filter.. this will not detach the filter */
+ nfct_filter_destroy(pClient->udp_filter);
+ pClient->udp_filter = NULL;
+
+ /* de-register the callback */
+ nfct_callback_unregister(pClient->udp_hdl);
+ /* close the handle */
+#ifdef FEATURE_IPACM_HAL
+ nfct_close2(pClient->udp_hdl, true);
+#else
+ nfct_close(pClient->udp_hdl);
+#endif
+ pClient->udp_hdl = NULL;
+
+ pthread_exit(NULL);
+ return NULL;
+}
+
+/* Thread to initialize TCP Conntrack Filters*/
+void IPACM_ConntrackClient::UNRegisterWithConnTrack(void)
+{
+ IPACM_ConntrackClient *pClient = NULL;
+
+ IPACMDBG("\n");
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to retrieve instance of conntrack client\n");
+ return;
+ }
+
+ /* destroy the TCP filter.. this will not detach the filter */
+ if (pClient->tcp_filter) {
+ nfct_filter_destroy(pClient->tcp_filter);
+ pClient->tcp_filter = NULL;
+ }
+
+ /* de-register the callback */
+ if (pClient->tcp_hdl) {
+ nfct_callback_unregister(pClient->tcp_hdl);
+ /* close the handle */
+ nfct_close(pClient->tcp_hdl);
+ pClient->tcp_hdl = NULL;
+ }
+
+ /* destroy the filter.. this will not detach the filter */
+ if (pClient->udp_filter) {
+ nfct_filter_destroy(pClient->udp_filter);
+ pClient->udp_filter = NULL;
+ }
+
+ /* de-register the callback */
+ if (pClient->udp_hdl) {
+ nfct_callback_unregister(pClient->udp_hdl);
+ /* close the handle */
+ nfct_close(pClient->udp_hdl);
+ pClient->udp_hdl = NULL;
+ }
+
+ pClient->fd_tcp = -1;
+ pClient->fd_udp = -1;
+
+ return;
+}
+
+void IPACM_ConntrackClient::UpdateUDPFilters(void *param, bool isWan)
+{
+ static bool isIgnore = false;
+ int ret = 0;
+ IPACM_ConntrackClient *pClient = NULL;
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to retrieve conntrack client instance\n");
+ return;
+ }
+
+ if(pClient->udp_filter == NULL)
+ {
+ return;
+ }
+
+ if(!isWan)
+ {
+ IPA_Conntrack_Filters_Ignore_Local_Iface(pClient->udp_filter,
+ (ipacm_event_iface_up *)param);
+
+ if(!isIgnore)
+ {
+ IPA_Conntrack_Filters_Ignore_Bridge_Addrs(pClient->udp_filter);
+ IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+ isIgnore = true;
+ }
+ }
+
+ /* Attach the filter to udp handle */
+ if(pClient->udp_hdl != NULL)
+ {
+ IPACMDBG("attaching the filter to udp handle\n");
+ ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
+ if(ret == -1)
+ {
+ PERROR("unable to attach the filter to udp handle\n");
+ IPACMERR("udp handle:%pK, fd:%d Error: %d\n",pClient->udp_hdl, nfct_fd(pClient->udp_hdl), ret);
+ return;
+ }
+ }
+
+ return;
+}
+
+void IPACM_ConntrackClient::UpdateTCPFilters(void *param, bool isWan)
+{
+ static bool isIgnore = false;
+ int ret = 0;
+ IPACM_ConntrackClient *pClient = NULL;
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to retrieve conntrack client instance\n");
+ return;
+ }
+
+ if(pClient->tcp_filter == NULL)
+ return;
+
+ if(!isWan)
+ {
+ IPA_Conntrack_Filters_Ignore_Local_Iface(pClient->tcp_filter,
+ (ipacm_event_iface_up *)param);
+
+ if(!isIgnore)
+ {
+ IPA_Conntrack_Filters_Ignore_Bridge_Addrs(pClient->udp_filter);
+ IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+ isIgnore = true;
+ }
+ }
+
+ /* Attach the filter to tcp handle */
+ if(pClient->tcp_hdl != NULL)
+ {
+ IPACMDBG("attaching the filter to tcp handle\n");
+ ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
+ if(ret == -1)
+ {
+ PERROR("unable to attach the filter to tcp handle\n");
+ IPACMERR("tcp handle:%pK, fd:%d Error: %d\n",pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl), ret);
+ return;
+ }
+ }
+
+ return;
+}
+
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_ConntrackListener.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_ConntrackListener.cpp
new file mode 100644
index 0000000..18f7e6b
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_ConntrackListener.cpp
@@ -0,0 +1,1203 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Wan.h"
+
+IPACM_ConntrackListener::IPACM_ConntrackListener()
+{
+ IPACMDBG("\n");
+
+ isNatThreadStart = false;
+ isCTReg = false;
+ WanUp = false;
+ nat_inst = NatApp::GetInstance();
+
+ NatIfaceCnt = 0;
+ StaClntCnt = 0;
+ pNatIfaces = NULL;
+ pConfig = IPACM_Config::GetInstance();;
+
+ memset(nat_iface_ipv4_addr, 0, sizeof(nat_iface_ipv4_addr));
+ memset(nonnat_iface_ipv4_addr, 0, sizeof(nonnat_iface_ipv4_addr));
+ memset(sta_clnt_ipv4_addr, 0, sizeof(sta_clnt_ipv4_addr));
+
+ 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_PROCESS_CT_MESSAGE_V6, this);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WLAN_UP, this);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_LAN_UP, this);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, this);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, this);
+
+#ifdef CT_OPT
+ p_lan2lan = IPACM_LanToLan::getLan2LanInstance();
+#endif
+}
+
+void IPACM_ConntrackListener::event_callback(ipa_cm_event_id evt,
+ void *data)
+{
+ ipacm_event_iface_up *wan_down = NULL;
+
+ if(data == NULL)
+ {
+ IPACMERR("Invalid Data\n");
+ return;
+ }
+
+ switch(evt)
+ {
+ case IPA_PROCESS_CT_MESSAGE:
+ IPACMDBG("Received IPA_PROCESS_CT_MESSAGE event\n");
+ ProcessCTMessage(data);
+ break;
+
+#ifdef CT_OPT
+ case IPA_PROCESS_CT_MESSAGE_V6:
+ IPACMDBG("Received IPA_PROCESS_CT_MESSAGE_V6 event\n");
+ ProcessCTV6Message(data);
+ break;
+#endif
+
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n");
+ CreateConnTrackThreads();
+ TriggerWANUp(data);
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN event\n");
+ wan_down = (ipacm_event_iface_up *)data;
+ if(isWanUp())
+ {
+ TriggerWANDown(wan_down->ipv4_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_H("Received event: %d with ifname: %s and address: 0x%x\n",
+ evt, ((ipacm_event_iface_up *)data)->ifname,
+ ((ipacm_event_iface_up *)data)->ipv4_addr);
+ if(isWanUp())
+ {
+ CreateConnTrackThreads();
+ IPACM_ConntrackClient::UpdateUDPFilters(data, false);
+ IPACM_ConntrackClient::UpdateTCPFilters(data, false);
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT event\n");
+ HandleNonNatIPAddr(data, true);
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT event\n");
+ HandleNonNatIPAddr(data, false);
+ break;
+
+ default:
+ IPACMDBG("Ignore cmd %d\n", evt);
+ break;
+ }
+}
+
+int IPACM_ConntrackListener::CheckNatIface(
+ ipacm_event_data_all *data, bool *NatIface)
+{
+ int fd = 0, len = 0, cnt, i;
+ struct ifreq ifr;
+ *NatIface = false;
+
+ if (data->ipv4_addr == 0 || data->iptype != IPA_IP_v4)
+ {
+ IPACMDBG("Ignoring\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("Received interface index %d with ip type: %d", data->if_index, data->iptype);
+ iptodot(" and ipv4 address", data->ipv4_addr);
+
+ if (pConfig == NULL)
+ {
+ pConfig = IPACM_Config::GetInstance();
+ if (pConfig == NULL)
+ {
+ IPACMERR("Unable to get Config instance\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ cnt = pConfig->GetNatIfacesCnt();
+ NatIfaceCnt = cnt;
+ IPACMDBG("Total Nat ifaces: %d\n", NatIfaceCnt);
+ if (pNatIfaces != NULL)
+ {
+ free(pNatIfaces);
+ pNatIfaces = NULL;
+ }
+
+ len = (sizeof(NatIfaces) * NatIfaceCnt);
+ pNatIfaces = (NatIfaces *)malloc(len);
+ if (pNatIfaces == NULL)
+ {
+ IPACMERR("Unable to allocate memory for non nat ifaces\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(pNatIfaces, 0, len);
+ if (pConfig->GetNatIfaces(NatIfaceCnt, pNatIfaces) != 0)
+ {
+ IPACMERR("Unable to retrieve non nat ifaces\n");
+ return IPACM_FAILURE;
+ }
+
+ /* 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 = data->if_index;
+ if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+ {
+ PERROR("call_ioctl_on_dev: ioctl failed:");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ close(fd);
+
+ for (i = 0; i < NatIfaceCnt; i++)
+ {
+ if (strncmp(ifr.ifr_name,
+ pNatIfaces[i].iface_name,
+ sizeof(pNatIfaces[i].iface_name)) == 0)
+ {
+ IPACMDBG_H("Nat iface (%s), entry (%d), dont cache",
+ pNatIfaces[i].iface_name, i);
+ iptodot("with ipv4 address: ", nat_iface_ipv4_addr[i]);
+ *NatIface = true;
+ return IPACM_SUCCESS;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+void IPACM_ConntrackListener::HandleNonNatIPAddr(
+ void *inParam, bool AddOp)
+{
+ ipacm_event_data_all *data = (ipacm_event_data_all *)inParam;
+ bool NatIface = false;
+ int cnt, ret;
+
+ if (isStaMode)
+ {
+ IPACMDBG("In STA mode, don't add dummy rules for non nat ifaces\n");
+ return;
+ }
+
+ /* Handle only non nat ifaces, NAT iface should be handle
+ separately to avoid race conditions between route/nat
+ rules add/delete operations */
+ if (AddOp)
+ {
+ ret = CheckNatIface(data, &NatIface);
+ if (!NatIface && ret == IPACM_SUCCESS)
+ {
+ /* Cache the non nat iface ip address */
+ for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+ {
+ if (nonnat_iface_ipv4_addr[cnt] == 0)
+ {
+ nonnat_iface_ipv4_addr[cnt] = data->ipv4_addr;
+ IPACMDBG("Add ip addr to non nat list (%d) ", cnt);
+ iptodot("with ipv4 address", nonnat_iface_ipv4_addr[cnt]);
+
+ /* Add dummy nat rule for non nat ifaces */
+ nat_inst->FlushTempEntries(data->ipv4_addr, true, true);
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* for delete operation */
+ for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+ {
+ if (nonnat_iface_ipv4_addr[cnt] == data->ipv4_addr)
+ {
+ IPACMDBG("Reseting ct filters, entry (%d) ", cnt);
+ iptodot("with ipv4 address", nonnat_iface_ipv4_addr[cnt]);
+ nonnat_iface_ipv4_addr[cnt] = 0;
+ nat_inst->FlushTempEntries(data->ipv4_addr, false);
+ nat_inst->DelEntriesOnClntDiscon(data->ipv4_addr);
+ return;
+ }
+ }
+
+ }
+
+ return;
+}
+
+void IPACM_ConntrackListener::HandleNeighIpAddrAddEvt(
+ ipacm_event_data_all *data)
+{
+ bool NatIface = false;
+ int j, ret;
+
+ ret = CheckNatIface(data, &NatIface);
+ if (NatIface && ret == IPACM_SUCCESS)
+ {
+ for (j = 0; j < MAX_IFACE_ADDRESS; j++)
+ {
+ /* check if duplicate NAT ip */
+ if (nat_iface_ipv4_addr[j] == data->ipv4_addr)
+ break;
+
+ /* Cache the new nat iface address */
+ if (nat_iface_ipv4_addr[j] == 0)
+ {
+ nat_iface_ipv4_addr[j] = data->ipv4_addr;
+ iptodot("Nating connections of addr: ", nat_iface_ipv4_addr[j]);
+ break;
+ }
+ }
+
+ /* Add the cached temp entries to NAT table */
+ if (j != MAX_IFACE_ADDRESS)
+ {
+ nat_inst->ResetPwrSaveIf(data->ipv4_addr);
+ nat_inst->FlushTempEntries(data->ipv4_addr, true);
+ }
+ }
+ return;
+}
+
+void IPACM_ConntrackListener::HandleNeighIpAddrDelEvt(
+ uint32_t ipv4_addr)
+{
+ int cnt;
+
+ if(ipv4_addr == 0)
+ {
+ IPACMDBG("Ignoring\n");
+ return;
+ }
+
+ iptodot("HandleNeighIpAddrDelEvt(): Received ip addr", ipv4_addr);
+ for(cnt = 0; cnt<MAX_IFACE_ADDRESS; cnt++)
+ {
+ if (nat_iface_ipv4_addr[cnt] == ipv4_addr)
+ {
+ IPACMDBG("Reseting ct nat iface, entry (%d) ", cnt);
+ iptodot("with ipv4 address", nat_iface_ipv4_addr[cnt]);
+ nat_iface_ipv4_addr[cnt] = 0;
+ nat_inst->FlushTempEntries(ipv4_addr, false);
+ nat_inst->DelEntriesOnClntDiscon(ipv4_addr);
+ }
+ }
+
+ return;
+}
+
+void IPACM_ConntrackListener::TriggerWANUp(void *in_param)
+{
+ ipacm_event_iface_up *wanup_data = (ipacm_event_iface_up *)in_param;
+
+ IPACMDBG_H("Recevied below information during wanup,\n");
+ IPACMDBG_H("if_name:%s, ipv4_address:0x%x\n",
+ wanup_data->ifname, wanup_data->ipv4_addr);
+
+ if(wanup_data->ipv4_addr == 0)
+ {
+ IPACMERR("Invalid ipv4 address,ignoring IPA_HANDLE_WAN_UP event\n");
+ return;
+ }
+
+ if(isWanUp())
+ {
+ if (wan_ipaddr != wanup_data->ipv4_addr)
+ TriggerWANDown(wan_ipaddr);
+ else
+ return;
+ }
+
+ WanUp = true;
+ isStaMode = wanup_data->is_sta;
+ IPACMDBG("isStaMode: %d\n", isStaMode);
+
+ wan_ipaddr = wanup_data->ipv4_addr;
+ memcpy(wan_ifname, wanup_data->ifname, sizeof(wan_ifname));
+
+ if(nat_inst != NULL)
+ {
+ nat_inst->AddTable(wanup_data->ipv4_addr);
+ }
+
+ IPACMDBG("creating nat threads\n");
+ CreateNatThreads();
+}
+
+int IPACM_ConntrackListener::CreateConnTrackThreads(void)
+{
+ int ret;
+ pthread_t tcp_thread = 0, udp_thread = 0;
+
+ if(isCTReg == false)
+ {
+ ret = pthread_create(&tcp_thread, NULL, IPACM_ConntrackClient::TCPRegisterWithConnTrack, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create TCP conntrack event listner thread\n");
+ PERROR("unable to create TCP conntrack\n");
+ goto error;
+ }
+
+ IPACMDBG("created TCP conntrack event listner thread\n");
+ if(pthread_setname_np(tcp_thread, "tcp ct listener") != 0)
+ {
+ IPACMERR("unable to set thread name\n");
+ }
+
+ ret = pthread_create(&udp_thread, NULL, IPACM_ConntrackClient::UDPRegisterWithConnTrack, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create UDP conntrack event listner thread\n");
+ PERROR("unable to create UDP conntrack\n");
+ goto error;
+ }
+
+ IPACMDBG("created UDP conntrack event listner thread\n");
+ if(pthread_setname_np(udp_thread, "udp ct listener") != 0)
+ {
+ IPACMERR("unable to set thread name\n");
+ }
+
+ isCTReg = true;
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+int IPACM_ConntrackListener::CreateNatThreads(void)
+{
+ int ret;
+ pthread_t udpcto_thread = 0;
+
+ if(isNatThreadStart == false)
+ {
+ ret = pthread_create(&udpcto_thread, NULL, IPACM_ConntrackClient::UDPConnTimeoutUpdate, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create udp conn timeout thread\n");
+ PERROR("unable to create udp conn timeout\n");
+ goto error;
+ }
+
+ IPACMDBG("created upd conn timeout thread\n");
+ if(pthread_setname_np(udpcto_thread, "udp conn timeout") != 0)
+ {
+ IPACMERR("unable to set thread name\n");
+ }
+
+ isNatThreadStart = true;
+ }
+ return 0;
+
+error:
+ return -1;
+}
+
+void IPACM_ConntrackListener::TriggerWANDown(uint32_t wan_addr)
+{
+ int ret = 0;
+ IPACMDBG_H("Deleting ipv4 nat table with");
+ IPACMDBG_H(" public ip address(0x%x): %d.%d.%d.%d\n", wan_addr,
+ ((wan_addr>>24) & 0xFF), ((wan_addr>>16) & 0xFF),
+ ((wan_addr>>8) & 0xFF), (wan_addr & 0xFF));
+
+ if(nat_inst != NULL)
+ {
+ ret = nat_inst->DeleteTable(wan_addr);
+ if (ret)
+ return;
+
+ WanUp = false;
+ wan_ipaddr = 0;
+ }
+}
+
+
+void ParseCTMessage(struct nf_conntrack *ct)
+{
+ uint32_t status, timeout;
+ IPACMDBG("Printing conntrack parameters\n");
+
+ iptodot("ATTR_IPV4_SRC = ATTR_ORIG_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC));
+ 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));
+
+ iptodot("ATTR_REPL_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC));
+ 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));
+
+ iptodot("ATTR_SNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_SNAT_IPV4));
+ 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);
+
+ timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT);
+ IPACMDBG("ATTR_TIMEOUT: 0x%x\n", timeout);
+
+ if(IPS_SRC_NAT & status)
+ {
+ IPACMDBG("IPS_SRC_NAT set\n");
+ }
+
+ if(IPS_DST_NAT & status)
+ {
+ IPACMDBG("IPS_DST_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 ParseCTV6Message(struct nf_conntrack *ct)
+{
+ uint32_t status, timeout;
+ struct nfct_attr_grp_ipv6 orig_params;
+ uint8_t l4proto, tcp_flags, tcp_state;
+
+ IPACMDBG("Printing conntrack parameters\n");
+
+ nfct_get_attr_grp(ct, ATTR_GRP_ORIG_IPV6, (void *)&orig_params);
+ IPACMDBG("Orig src_v6_addr: 0x%08x%08x%08x%08x\n", orig_params.src[0], orig_params.src[1],
+ orig_params.src[2], orig_params.src[3]);
+ IPACMDBG("Orig dst_v6_addr: 0x%08x%08x%08x%08x\n", orig_params.dst[0], orig_params.dst[1],
+ orig_params.dst[2], orig_params.dst[3]);
+
+ 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));
+
+ 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));
+
+ timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT);
+ IPACMDBG("ATTR_TIMEOUT: 0x%x\n", timeout);
+
+ status = nfct_get_attr_u32(ct, ATTR_STATUS);
+ IPACMDBG("ATTR_STATUS: 0x%x\n", status);
+
+ l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
+ IPACMDBG("ATTR_ORIG_L4PROTO: 0x%x\n", l4proto);
+ if(l4proto == IPPROTO_TCP)
+ {
+ tcp_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+ IPACMDBG("ATTR_TCP_STATE: 0x%x\n", tcp_state);
+
+ tcp_flags = nfct_get_attr_u8(ct, ATTR_TCP_FLAGS_ORIG);
+ IPACMDBG("ATTR_TCP_FLAGS_ORIG: 0x%x\n", tcp_flags);
+ }
+
+ IPACMDBG("\n");
+ return;
+}
+
+#ifdef CT_OPT
+void IPACM_ConntrackListener::ProcessCTV6Message(void *param)
+{
+ ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
+ u_int8_t l4proto = 0;
+ uint32_t status = 0;
+ struct nf_conntrack *ct = evt_data->ct;
+
+#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");
+ ParseCTV6Message(ct);
+#endif
+
+ if(p_lan2lan == NULL)
+ {
+ IPACMERR("Lan2Lan Instance is null\n");
+ goto IGNORE;
+ }
+
+ status = nfct_get_attr_u32(ct, ATTR_STATUS);
+ if((IPS_DST_NAT & status) || (IPS_SRC_NAT & status))
+ {
+ IPACMDBG("Either Destination or Source nat flag Set\n");
+ goto IGNORE;
+ }
+
+ l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
+ if(IPPROTO_UDP != l4proto && IPPROTO_TCP != l4proto)
+ {
+ IPACMDBG("Received unexpected protocl %d conntrack message\n", l4proto);
+ goto IGNORE;
+ }
+
+ IPACMDBG("Neither Destination nor Source nat flag Set\n");
+ struct nfct_attr_grp_ipv6 orig_params;
+ nfct_get_attr_grp(ct, ATTR_GRP_ORIG_IPV6, (void *)&orig_params);
+
+ ipacm_event_connection lan2lan_conn;
+ lan2lan_conn.iptype = IPA_IP_v6;
+ memcpy(lan2lan_conn.src_ipv6_addr, orig_params.src,
+ sizeof(lan2lan_conn.src_ipv6_addr));
+ IPACMDBG("Before convert, src_v6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.src_ipv6_addr[0], lan2lan_conn.src_ipv6_addr[1],
+ lan2lan_conn.src_ipv6_addr[2], lan2lan_conn.src_ipv6_addr[3]);
+ for(int cnt=0; cnt<4; cnt++)
+ {
+ lan2lan_conn.src_ipv6_addr[cnt] = ntohl(lan2lan_conn.src_ipv6_addr[cnt]);
+ }
+ IPACMDBG("After convert src_v6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.src_ipv6_addr[0], lan2lan_conn.src_ipv6_addr[1],
+ lan2lan_conn.src_ipv6_addr[2], lan2lan_conn.src_ipv6_addr[3]);
+
+ memcpy(lan2lan_conn.dst_ipv6_addr, orig_params.dst,
+ sizeof(lan2lan_conn.dst_ipv6_addr));
+ IPACMDBG("Before convert, dst_ipv6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.dst_ipv6_addr[0], lan2lan_conn.dst_ipv6_addr[1],
+ lan2lan_conn.dst_ipv6_addr[2], lan2lan_conn.dst_ipv6_addr[3]);
+ for(int cnt=0; cnt<4; cnt++)
+ {
+ lan2lan_conn.dst_ipv6_addr[cnt] = ntohl(lan2lan_conn.dst_ipv6_addr[cnt]);
+ }
+ IPACMDBG("After convert, dst_ipv6_addr: 0x%08x%08x%08x%08x\n", lan2lan_conn.dst_ipv6_addr[0], lan2lan_conn.dst_ipv6_addr[1],
+ lan2lan_conn.dst_ipv6_addr[2], lan2lan_conn.dst_ipv6_addr[3]);
+
+ if(((IPPROTO_UDP == l4proto) && (NFCT_T_NEW == evt_data->type)) ||
+ ((IPPROTO_TCP == l4proto) &&
+ (nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED))
+ )
+ {
+ p_lan2lan->handle_new_connection(&lan2lan_conn);
+ }
+ else if((IPPROTO_UDP == l4proto && NFCT_T_DESTROY == evt_data->type) ||
+ (IPPROTO_TCP == l4proto &&
+ nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT))
+ {
+ p_lan2lan->handle_del_connection(&lan2lan_conn);
+ }
+
+IGNORE:
+ /* Cleanup item that was allocated during the original CT callback */
+ nfct_destroy(ct);
+ return;
+}
+#endif
+
+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];
+ unsigned int out_flags;
+
+ /* Process message and generate ioctl call to kernel thread */
+ out_flags = (NFCT_OF_SHOW_LAYER3 | NFCT_OF_TIME | NFCT_OF_ID);
+ nfct_snprintf(buf, sizeof(buf), evt_data->ct,
+ evt_data->type, NFCT_O_PLAIN, out_flags);
+ IPACMDBG_H("%s\n", buf);
+
+ 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;
+}
+
+bool IPACM_ConntrackListener::AddIface(
+ nat_table_entry *rule, bool *isTempEntry)
+{
+ int cnt;
+
+ *isTempEntry = false;
+
+ /* Special handling for Passthrough IP. */
+ if (IPACM_Iface::ipacmcfg->ipacm_ip_passthrough_mode)
+ {
+ if (rule->private_ip == IPACM_Wan::getWANIP())
+ {
+ IPACMDBG("In Passthrough mode and entry matched with Wan IP (0x%x)\n",
+ rule->private_ip);
+ return true;
+ }
+ }
+
+ /* check whether nat iface or not */
+ for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+ {
+ if (nat_iface_ipv4_addr[cnt] != 0)
+ {
+ if (rule->private_ip == nat_iface_ipv4_addr[cnt] ||
+ rule->target_ip == nat_iface_ipv4_addr[cnt])
+ {
+ IPACMDBG("matched nat_iface_ipv4_addr entry(%d)\n", cnt);
+ iptodot("AddIface(): Nat entry match with ip addr",
+ nat_iface_ipv4_addr[cnt]);
+ return true;
+ }
+ }
+ }
+
+ if (!isStaMode)
+ {
+ /* check whether non nat iface or not, on Non Nat iface
+ add dummy rule by copying public ip to private ip */
+ for (cnt = 0; cnt < MAX_IFACE_ADDRESS; cnt++)
+ {
+ if (nonnat_iface_ipv4_addr[cnt] != 0)
+ {
+ if (rule->private_ip == nonnat_iface_ipv4_addr[cnt] ||
+ rule->target_ip == nonnat_iface_ipv4_addr[cnt])
+ {
+ IPACMDBG("matched non_nat_iface_ipv4_addr entry(%d)\n", cnt);
+ iptodot("AddIface(): Non Nat entry match with ip addr",
+ nonnat_iface_ipv4_addr[cnt]);
+
+ rule->private_ip = rule->public_ip;
+ rule->private_port = rule->public_port;
+ return true;
+ }
+ }
+ }
+ IPACMDBG_H("Not mtaching with non-nat ifaces\n");
+ }
+ else
+ IPACMDBG("In STA mode, don't compare against non nat ifaces\n");
+
+ if(pConfig == NULL)
+ {
+ pConfig = IPACM_Config::GetInstance();
+ if(pConfig == NULL)
+ {
+ IPACMERR("Unable to get Config instance\n");
+ return false;
+ }
+ }
+
+ if (pConfig->isPrivateSubnet(rule->private_ip) ||
+ pConfig->isPrivateSubnet(rule->target_ip))
+ {
+ IPACMDBG("Matching with Private subnet\n");
+ *isTempEntry = true;
+ return true;
+ }
+
+ return false;
+}
+
+void IPACM_ConntrackListener::AddORDeleteNatEntry(const nat_entry_bundle *input)
+{
+ u_int8_t tcp_state;
+
+ if (nat_inst == NULL)
+ {
+ IPACMERR("Nat instance is NULL, unable to add or delete\n");
+ return;
+ }
+
+ IPACMDBG_H("Below Nat Entry will either be added or deleted\n");
+ iptodot("AddORDeleteNatEntry(): target ip or dst ip",
+ input->rule->target_ip);
+ IPACMDBG("target port or dst port: 0x%x Decimal:%d\n",
+ input->rule->target_port, input->rule->target_port);
+ iptodot("AddORDeleteNatEntry(): private ip or src ip",
+ input->rule->private_ip);
+ IPACMDBG("private port or src port: 0x%x, Decimal:%d\n",
+ input->rule->private_port, input->rule->private_port);
+ IPACMDBG("public port or reply dst port: 0x%x, Decimal:%d\n",
+ input->rule->public_port, input->rule->public_port);
+ IPACMDBG("Protocol: %d, destination nat flag: %d\n",
+ input->rule->protocol, input->rule->dst_nat);
+
+ if (IPPROTO_TCP == input->rule->protocol)
+ {
+ tcp_state = nfct_get_attr_u8(input->ct, ATTR_TCP_STATE);
+ if (TCP_CONNTRACK_ESTABLISHED == tcp_state)
+ {
+ IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED(%d)\n", tcp_state);
+ if (!CtList->isWanUp())
+ {
+ IPACMDBG("Wan is not up, cache connections\n");
+ nat_inst->CacheEntry(input->rule);
+ }
+ else if (input->isTempEntry)
+ {
+ nat_inst->AddTempEntry(input->rule);
+ }
+ else
+ {
+ nat_inst->AddEntry(input->rule);
+ }
+ }
+ else if (TCP_CONNTRACK_FIN_WAIT == tcp_state ||
+ input->type == NFCT_T_DESTROY)
+ {
+ IPACMDBG("TCP state TCP_CONNTRACK_FIN_WAIT(%d) "
+ "or type NFCT_T_DESTROY(%d)\n", tcp_state, input->type);
+
+ nat_inst->DeleteEntry(input->rule);
+ nat_inst->DeleteTempEntry(input->rule);
+ }
+ else
+ {
+ IPACMDBG("Ignore tcp state: %d and type: %d\n",
+ tcp_state, input->type);
+ }
+
+ }
+ else if (IPPROTO_UDP == input->rule->protocol)
+ {
+ if (NFCT_T_NEW == input->type)
+ {
+ IPACMDBG("New UDP connection at time %ld\n", time(NULL));
+ if (!CtList->isWanUp())
+ {
+ IPACMDBG("Wan is not up, cache connections\n");
+ nat_inst->CacheEntry(input->rule);
+ }
+ else if (input->isTempEntry)
+ {
+ nat_inst->AddTempEntry(input->rule);
+ }
+ else
+ {
+ nat_inst->AddEntry(input->rule);
+ }
+ }
+ else if (NFCT_T_DESTROY == input->type)
+ {
+ IPACMDBG("UDP connection close at time %ld\n", time(NULL));
+ nat_inst->DeleteEntry(input->rule);
+ nat_inst->DeleteTempEntry(input->rule);
+ }
+ }
+
+ return;
+}
+
+void IPACM_ConntrackListener::PopulateTCPorUDPEntry(
+ struct nf_conntrack *ct,
+ uint32_t status,
+ nat_table_entry *rule)
+{
+ if (IPS_DST_NAT == status)
+ {
+ IPACMDBG("Destination NAT\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);
+ iptodot("PopulateTCPorUDPEntry(): target ip", 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);
+ iptodot("PopulateTCPorUDPEntry(): private ip", 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 if (IPS_SRC_NAT == status)
+ {
+ IPACMDBG("Source NAT\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);
+ iptodot("PopulateTCPorUDPEntry(): target ip", 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);
+ iptodot("PopulateTCPorUDPEntry(): private ip", 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");
+ }
+ }
+
+ return;
+}
+
+#ifdef CT_OPT
+void IPACM_ConntrackListener::HandleLan2Lan(struct nf_conntrack *ct,
+ enum nf_conntrack_msg_type type,
+ nat_table_entry *rule)
+{
+ ipacm_event_connection lan2lan_conn = { 0 };
+
+ if (p_lan2lan == NULL)
+ {
+ IPACMERR("Lan2Lan Instance is null\n");
+ return;
+ }
+
+ lan2lan_conn.iptype = IPA_IP_v4;
+ lan2lan_conn.src_ipv4_addr = orig_src_ip;
+ lan2lan_conn.dst_ipv4_addr = orig_dst_ip;
+
+ if (((IPPROTO_UDP == rule->protocol) && (NFCT_T_NEW == type)) ||
+ ((IPPROTO_TCP == rule->protocol) && (nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_ESTABLISHED)))
+ {
+ p_lan2lan->handle_new_connection(&lan2lan_conn);
+ }
+ else if ((IPPROTO_UDP == rule->protocol && NFCT_T_DESTROY == type) ||
+ (IPPROTO_TCP == rule->protocol &&
+ nfct_get_attr_u8(ct, ATTR_TCP_STATE) == TCP_CONNTRACK_FIN_WAIT))
+ {
+ p_lan2lan->handle_del_connection(&lan2lan_conn);
+ }
+}
+#endif
+
+void IPACM_ConntrackListener::CheckSTAClient(
+ const nat_table_entry *rule, bool *isTempEntry)
+{
+ int nCnt;
+
+ /* Check whether target is in STA client list or not
+ if not ignore the connection */
+ if(!isStaMode || (StaClntCnt == 0))
+ {
+ return;
+ }
+
+ if((sta_clnt_ipv4_addr[0] & STA_CLNT_SUBNET_MASK) !=
+ (rule->target_ip & STA_CLNT_SUBNET_MASK))
+ {
+ IPACMDBG("STA client subnet mask not matching\n");
+ return;
+ }
+
+ IPACMDBG("StaClntCnt %d\n", StaClntCnt);
+ for(nCnt = 0; nCnt < StaClntCnt; nCnt++)
+ {
+ IPACMDBG("Comparing trgt_ip 0x%x with sta clnt ip: 0x%x\n",
+ rule->target_ip, sta_clnt_ipv4_addr[nCnt]);
+ if(rule->target_ip == sta_clnt_ipv4_addr[nCnt])
+ {
+ IPACMDBG("Match index %d\n", nCnt);
+ return;
+ }
+ }
+
+ IPACMDBG_H("Not matching with STA Clnt Ip Addrs 0x%x\n",
+ rule->target_ip);
+ *isTempEntry = true;
+}
+
+/* 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;
+ uint32_t status = 0;
+ uint32_t orig_src_ip, orig_dst_ip;
+ bool isAdd = false;
+
+ nat_entry_bundle nat_entry;
+ nat_entry.isTempEntry = false;
+ nat_entry.ct = ct;
+ nat_entry.type = type;
+
+ memset(&rule, 0, sizeof(rule));
+ IPACMDBG("Received type:%d with proto:%d\n", type, l4proto);
+ status = nfct_get_attr_u32(ct, ATTR_STATUS);
+
+ /* Retrieve Protocol */
+ rule.protocol = nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO);
+
+ if(IPS_DST_NAT & status)
+ {
+ status = IPS_DST_NAT;
+ }
+ else if(IPS_SRC_NAT & status)
+ {
+ status = IPS_SRC_NAT;
+ }
+ else
+ {
+ IPACMDBG("Neither Destination nor Source nat flag Set\n");
+ orig_src_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+ orig_src_ip = ntohl(orig_src_ip);
+ if(orig_src_ip == 0)
+ {
+ IPACMERR("unable to retrieve orig src ip address\n");
+ return;
+ }
+
+ orig_dst_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST);
+ orig_dst_ip = ntohl(orig_dst_ip);
+ if(orig_dst_ip == 0)
+ {
+ IPACMERR("unable to retrieve orig dst ip address\n");
+ return;
+ }
+
+ if(orig_src_ip == wan_ipaddr)
+ {
+ IPACMDBG("orig src ip:0x%x equal to wan ip\n",orig_src_ip);
+ status = IPS_SRC_NAT;
+ }
+ else if(orig_dst_ip == wan_ipaddr)
+ {
+ IPACMDBG("orig Dst IP:0x%x equal to wan ip\n",orig_dst_ip);
+ status = IPS_DST_NAT;
+ }
+ else
+ {
+ IPACMDBG_H("Neither orig src ip:0x%x Nor orig Dst IP:0x%x equal to wan ip:0x%x\n",
+ orig_src_ip, orig_dst_ip, wan_ipaddr);
+
+#ifdef CT_OPT
+ HandleLan2Lan(ct, type, &rule);
+#endif
+ return;
+ }
+ }
+
+ if(IPS_DST_NAT == status || IPS_SRC_NAT == status)
+ {
+ PopulateTCPorUDPEntry(ct, status, &rule);
+ rule.public_ip = wan_ipaddr;
+ }
+ else
+ {
+ IPACMDBG("Neither source Nor destination nat\n");
+ goto IGNORE;
+ }
+
+ if (rule.private_ip != wan_ipaddr)
+ {
+ isAdd = AddIface(&rule, &nat_entry.isTempEntry);
+ if (!isAdd)
+ {
+ goto IGNORE;
+ }
+ }
+ else
+ {
+ if (isStaMode)
+ {
+ IPACMDBG("In STA mode, ignore connections destinated to STA interface\n");
+ goto IGNORE;
+ }
+
+ IPACMDBG("For embedded connections add dummy nat rule\n");
+ IPACMDBG("Change private port %d to %d\n",
+ rule.private_port, rule.public_port);
+ rule.private_port = rule.public_port;
+ }
+
+ CheckSTAClient(&rule, &nat_entry.isTempEntry);
+ nat_entry.rule = &rule;
+ AddORDeleteNatEntry(&nat_entry);
+ return;
+
+IGNORE:
+ IPACMDBG_H("ignoring below Nat Entry\n");
+ iptodot("ProcessTCPorUDPMsg(): 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);
+ iptodot("ProcessTCPorUDPMsg(): 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);
+ return;
+}
+
+void IPACM_ConntrackListener::HandleSTAClientAddEvt(uint32_t clnt_ip_addr)
+{
+ int cnt;
+ IPACMDBG_H("Received STA client 0x%x\n", clnt_ip_addr);
+
+ if(StaClntCnt >= MAX_STA_CLNT_IFACES)
+ {
+ IPACMDBG("Max STA client reached, ignore 0x%x\n", clnt_ip_addr);
+ return;
+ }
+
+ for(cnt=0; cnt<MAX_STA_CLNT_IFACES; cnt++)
+ {
+ if(sta_clnt_ipv4_addr[cnt] != 0 &&
+ sta_clnt_ipv4_addr[cnt] == clnt_ip_addr)
+ {
+ IPACMDBG("Ignoring duplicate one 0x%x\n", clnt_ip_addr);
+ break;
+ }
+
+ if(sta_clnt_ipv4_addr[cnt] == 0)
+ {
+ IPACMDBG("Adding STA client 0x%x at Index: %d\n",
+ clnt_ip_addr, cnt);
+ sta_clnt_ipv4_addr[cnt] = clnt_ip_addr;
+ StaClntCnt++;
+ IPACMDBG("STA client cnt %d\n", StaClntCnt);
+ break;
+ }
+
+ }
+
+ nat_inst->FlushTempEntries(clnt_ip_addr, true);
+ return;
+}
+
+void IPACM_ConntrackListener::HandleSTAClientDelEvt(uint32_t clnt_ip_addr)
+{
+ int cnt;
+ IPACMDBG_H("Received STA client 0x%x\n", clnt_ip_addr);
+
+ for(cnt=0; cnt<MAX_STA_CLNT_IFACES; cnt++)
+ {
+ if(sta_clnt_ipv4_addr[cnt] != 0 &&
+ sta_clnt_ipv4_addr[cnt] == clnt_ip_addr)
+ {
+ IPACMDBG("Deleting STA client 0x%x at index: %d\n",
+ clnt_ip_addr, cnt);
+ sta_clnt_ipv4_addr[cnt] = 0;
+ nat_inst->DelEntriesOnSTAClntDiscon(clnt_ip_addr);
+ StaClntCnt--;
+ IPACMDBG("STA client cnt %d\n", StaClntCnt);
+ break;
+ }
+ }
+
+ nat_inst->FlushTempEntries(clnt_ip_addr, false);
+ return;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Conntrack_NATApp.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Conntrack_NATApp.cpp
new file mode 100644
index 0000000..c13c48e
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -0,0 +1,1022 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_ConntrackClient.h"
+#ifdef FEATURE_IPACM_HAL
+#include "IPACM_OffloadManager.h"
+#endif
+
+#define INVALID_IP_ADDR 0x0
+
+/* NatApp class Implementation */
+NatApp *NatApp::pInstance = NULL;
+NatApp::NatApp()
+{
+ max_entries = 0;
+ cache = NULL;
+
+ nat_table_hdl = 0;
+ pub_ip_addr = 0;
+
+ curCnt = 0;
+
+ pALGPorts = NULL;
+ nALGPort = 0;
+
+ ct = NULL;
+ ct_hdl = NULL;
+
+ memset(temp, 0, sizeof(temp));
+}
+
+int NatApp::Init(void)
+{
+ IPACM_Config *pConfig;
+ int size = 0;
+
+ pConfig = IPACM_Config::GetInstance();
+ if(pConfig == NULL)
+ {
+ IPACMERR("Unable to get Config instance\n");
+ return -1;
+ }
+
+ max_entries = pConfig->GetNatMaxEntries();
+
+ size = (sizeof(nat_table_entry) * max_entries);
+ cache = (nat_table_entry *)malloc(size);
+ if(cache == NULL)
+ {
+ IPACMERR("Unable to allocate memory for cache\n");
+ goto fail;
+ }
+ IPACMDBG("Allocated %d bytes for config manager nat cache\n", size);
+ memset(cache, 0, size);
+
+ nALGPort = pConfig->GetAlgPortCnt();
+ if(nALGPort > 0)
+ {
+ pALGPorts = (ipacm_alg *)malloc(sizeof(ipacm_alg) * nALGPort);
+ if(pALGPorts == NULL)
+ {
+ IPACMERR("Unable to allocate memory for alg prots\n");
+ goto fail;
+ }
+ memset(pALGPorts, 0, sizeof(ipacm_alg) * nALGPort);
+
+ if(pConfig->GetAlgPorts(nALGPort, pALGPorts) != 0)
+ {
+ IPACMERR("Unable to retrieve ALG prots\n");
+ goto fail;
+ }
+
+ IPACMDBG("Printing %d alg ports information\n", nALGPort);
+ for(int cnt=0; cnt<nALGPort; cnt++)
+ {
+ IPACMDBG("%d: Proto[%d], port[%d]\n", cnt, pALGPorts[cnt].protocol, pALGPorts[cnt].port);
+ }
+ }
+
+ return 0;
+
+fail:
+ free(cache);
+ free(pALGPorts);
+ return -1;
+}
+
+NatApp* NatApp::GetInstance()
+{
+ if(pInstance == NULL)
+ {
+ pInstance = new NatApp();
+
+ if(pInstance->Init())
+ {
+ delete pInstance;
+ return NULL;
+ }
+ }
+
+ return pInstance;
+}
+
+/* NAT APP related object function definitions */
+
+int NatApp::AddTable(uint32_t pub_ip)
+{
+ int ret;
+ int cnt = 0;
+ ipa_nat_ipv4_rule nat_rule;
+ IPACMDBG_H("%s() %d\n", __FUNCTION__, __LINE__);
+
+ /* Not reset the cache wait it timeout by destroy event */
+#if 0
+ if (pub_ip != pub_ip_addr_pre)
+ {
+ IPACMDBG("Reset the cache because NAT-ipv4 different\n");
+ memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+ curCnt = 0;
+ }
+#endif
+ ret = ipa_nat_add_ipv4_tbl(pub_ip, max_entries, &nat_table_hdl);
+ if(ret)
+ {
+ IPACMERR("unable to create nat table Error:%d\n", ret);
+ return ret;
+ }
+
+ /* Add back the cached NAT-entry */
+ if (pub_ip == pub_ip_addr_pre)
+ {
+ IPACMDBG("Restore the cache to ipa NAT-table\n");
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip !=0)
+ {
+ memset(&nat_rule, 0 , sizeof(nat_rule));
+ nat_rule.private_ip = cache[cnt].private_ip;
+ nat_rule.target_ip = cache[cnt].target_ip;
+ nat_rule.target_port = cache[cnt].target_port;
+ nat_rule.private_port = cache[cnt].private_port;
+ nat_rule.public_port = cache[cnt].public_port;
+ nat_rule.protocol = cache[cnt].protocol;
+
+ if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to add the rule delete from cache\n");
+ memset(&cache[cnt], 0, sizeof(cache[cnt]));
+ curCnt--;
+ continue;
+ }
+ cache[cnt].enabled = true;
+
+ IPACMDBG("On wan-iface reset added below rule successfully\n");
+ iptodot("Private IP", nat_rule.private_ip);
+ iptodot("Target IP", nat_rule.target_ip);
+ IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
+ IPACMDBG("Public Port:%d\n", nat_rule.public_port);
+ IPACMDBG("protocol: %d\n", nat_rule.protocol);
+ }
+ }
+ }
+
+ pub_ip_addr = pub_ip;
+ return 0;
+}
+
+void NatApp::Reset()
+{
+ int cnt = 0;
+
+ nat_table_hdl = 0;
+ pub_ip_addr = 0;
+ /* NAT tbl deleted, reset enabled bit */
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ cache[cnt].enabled = false;
+ }
+}
+
+int NatApp::DeleteTable(uint32_t pub_ip)
+{
+ int ret;
+ IPACMDBG_H("%s() %d\n", __FUNCTION__, __LINE__);
+
+ CHK_TBL_HDL();
+
+ if(pub_ip_addr != pub_ip)
+ {
+ IPACMDBG("Public ip address is not matching\n");
+ IPACMERR("unable to delete the nat table\n");
+ return -1;
+ }
+
+ ret = ipa_nat_del_ipv4_tbl(nat_table_hdl);
+ if(ret)
+ {
+ IPACMERR("unable to delete nat table Error: %d\n", ret);;
+ return ret;
+ }
+
+ pub_ip_addr_pre = pub_ip_addr;
+ Reset();
+ return 0;
+}
+
+/* Check for duplicate entries */
+bool NatApp::ChkForDup(const nat_table_entry *rule)
+{
+ int cnt = 0;
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ for(; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == rule->private_ip &&
+ cache[cnt].target_ip == rule->target_ip &&
+ cache[cnt].private_port == rule->private_port &&
+ cache[cnt].target_port == rule->target_port &&
+ cache[cnt].protocol == rule->protocol)
+ {
+ log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
+ rule->target_port,"Duplicate Rule\n");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Delete the entry from Nat table on connection close */
+int NatApp::DeleteEntry(const nat_table_entry *rule)
+{
+ int cnt = 0;
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
+ rule->target_port,"for deletion\n");
+
+
+ for(; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == rule->private_ip &&
+ cache[cnt].target_ip == rule->target_ip &&
+ cache[cnt].private_port == rule->private_port &&
+ cache[cnt].target_port == rule->target_port &&
+ cache[cnt].protocol == rule->protocol)
+ {
+
+ if(cache[cnt].enabled == true)
+ {
+ if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("%s() %d deletion failed\n", __FUNCTION__, __LINE__);
+ }
+
+ IPACMDBG_H("Deleted Nat entry(%d) Successfully\n", cnt);
+ }
+ else
+ {
+ IPACMDBG_H("Deleted Nat entry(%d) only from cache\n", cnt);
+ }
+
+ memset(&cache[cnt], 0, sizeof(cache[cnt]));
+ curCnt--;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* Add new entry to the nat table on new connection */
+int NatApp::AddEntry(const nat_table_entry *rule)
+{
+ int cnt = 0;
+ ipa_nat_ipv4_rule nat_rule;
+
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ CHK_TBL_HDL();
+ log_nat(rule->protocol,rule->private_ip,rule->target_ip,rule->private_port,\
+ rule->target_port,"for addition\n");
+ if(isAlgPort(rule->protocol, rule->private_port) ||
+ isAlgPort(rule->protocol, rule->target_port))
+ {
+ IPACMERR("connection using ALG Port, ignore\n");
+ return -1;
+ }
+
+ if(rule->private_ip == 0 ||
+ rule->target_ip == 0 ||
+ rule->private_port == 0 ||
+ rule->target_port == 0 ||
+ rule->protocol == 0)
+ {
+ IPACMERR("Invalid Connection, ignoring it\n");
+ return 0;
+ }
+
+ if(!ChkForDup(rule))
+ {
+ for(; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == 0 &&
+ cache[cnt].target_ip == 0 &&
+ cache[cnt].private_port == 0 &&
+ cache[cnt].target_port == 0 &&
+ cache[cnt].protocol == 0)
+ {
+ break;
+ }
+ }
+
+ if(max_entries == cnt)
+ {
+ IPACMERR("Error: Unable to add, reached maximum rules\n");
+ return -1;
+ }
+ else
+ {
+ memset(&nat_rule, 0, sizeof(nat_rule));
+ nat_rule.private_ip = rule->private_ip;
+ nat_rule.target_ip = rule->target_ip;
+ nat_rule.target_port = rule->target_port;
+ nat_rule.private_port = rule->private_port;
+ nat_rule.public_port = rule->public_port;
+ nat_rule.protocol = rule->protocol;
+
+ if(isPwrSaveIf(rule->private_ip) ||
+ isPwrSaveIf(rule->target_ip))
+ {
+ IPACMDBG("Device is Power Save mode: Dont insert into nat table but cache\n");
+ cache[cnt].enabled = false;
+ cache[cnt].rule_hdl = 0;
+ }
+ else
+ {
+
+ if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to add the rule\n");
+ return -1;
+ }
+
+ cache[cnt].enabled = true;
+ }
+
+ cache[cnt].private_ip = rule->private_ip;
+ cache[cnt].target_ip = rule->target_ip;
+ cache[cnt].target_port = rule->target_port;
+ cache[cnt].private_port = rule->private_port;
+ cache[cnt].protocol = rule->protocol;
+ cache[cnt].timestamp = 0;
+ cache[cnt].public_port = rule->public_port;
+ cache[cnt].dst_nat = rule->dst_nat;
+ curCnt++;
+ }
+
+ }
+ else
+ {
+ IPACMERR("Duplicate rule. Ignore it\n");
+ return -1;
+ }
+
+ if(cache[cnt].enabled == true)
+ {
+ IPACMDBG_H("Added rule(%d) successfully\n", cnt);
+ }
+ else
+ {
+ IPACMDBG_H("Cached rule(%d) successfully\n", cnt);
+ }
+
+ return 0;
+}
+
+void NatApp::UpdateCTUdpTs(nat_table_entry *rule, uint32_t new_ts)
+{
+#ifdef FEATURE_IPACM_HAL
+ IOffloadManager::ConntrackTimeoutUpdater::natTimeoutUpdate_t entry;
+ IPACM_OffloadManager* OffloadMng;
+#endif
+ iptodot("Private IP:", rule->private_ip);
+ iptodot("Target IP:", rule->target_ip);
+ IPACMDBG("Private Port: %d, Target Port: %d\n", rule->private_port, rule->target_port);
+
+#ifndef FEATURE_IPACM_HAL
+ int ret;
+ if(!ct_hdl)
+ {
+ ct_hdl = nfct_open(CONNTRACK, 0);
+ if(!ct_hdl)
+ {
+ PERROR("nfct_open");
+ return;
+ }
+ }
+
+ if(!ct)
+ {
+ ct = nfct_new();
+ if(!ct)
+ {
+ PERROR("nfct_new");
+ return;
+ }
+ }
+
+ nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
+ if(rule->protocol == IPPROTO_UDP)
+ {
+ nfct_set_attr_u8(ct, ATTR_L4PROTO, rule->protocol);
+ nfct_set_attr_u32(ct, ATTR_TIMEOUT, udp_timeout);
+ }
+ else
+ {
+ nfct_set_attr_u8(ct, ATTR_L4PROTO, rule->protocol);
+ nfct_set_attr_u32(ct, ATTR_TIMEOUT, tcp_timeout);
+ }
+
+ if(rule->dst_nat == false)
+ {
+ nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->private_ip));
+ nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->private_port));
+
+ nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(rule->target_ip));
+ nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->target_port));
+
+ IPACMDBG("dst nat is not set\n");
+ }
+ else
+ {
+ nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->target_ip));
+ nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->target_port));
+
+ nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(pub_ip_addr));
+ nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->public_port));
+
+ IPACMDBG("dst nat is set\n");
+ }
+
+ iptodot("Source IP:", nfct_get_attr_u32(ct, ATTR_IPV4_SRC));
+ iptodot("Destination IP:", nfct_get_attr_u32(ct, ATTR_IPV4_DST));
+ IPACMDBG("Source Port: %d, Destination Port: %d\n",
+ nfct_get_attr_u16(ct, ATTR_PORT_SRC), nfct_get_attr_u16(ct, ATTR_PORT_DST));
+
+ IPACMDBG("updating %d connection with time: %d\n",
+ rule->protocol, nfct_get_attr_u32(ct, ATTR_TIMEOUT));
+
+ ret = nfct_query(ct_hdl, NFCT_Q_UPDATE, ct);
+ if(ret == -1)
+ {
+ IPACMERR("unable to update time stamp");
+ DeleteEntry(rule);
+ }
+ else
+ {
+ rule->timestamp = new_ts;
+ IPACMDBG("Updated time stamp successfully\n");
+ }
+#else
+ if(rule->protocol == IPPROTO_UDP)
+ {
+ entry.proto = IOffloadManager::ConntrackTimeoutUpdater::UDP;;
+ }
+ else
+ {
+ entry.proto = IOffloadManager::ConntrackTimeoutUpdater::TCP;
+ }
+
+ if(rule->dst_nat == false)
+ {
+ entry.src.ipAddr = htonl(rule->private_ip);
+ entry.src.port = rule->private_port;
+ entry.dst.ipAddr = htonl(rule->target_ip);
+ entry.dst.port = rule->target_port;
+ IPACMDBG("dst nat is not set\n");
+ }
+ else
+ {
+ entry.src.ipAddr = htonl(rule->target_ip);
+ entry.src.port = rule->target_port;
+ entry.dst.ipAddr = htonl(pub_ip_addr);
+ entry.dst.port = rule->public_port;
+ IPACMDBG("dst nat is set\n");
+ }
+
+ iptodot("Source IP:", entry.src.ipAddr);
+ iptodot("Destination IP:", entry.dst.ipAddr);
+ IPACMDBG("Source Port: %d, Destination Port: %d\n",
+ entry.src.port, entry.dst.port);
+
+ OffloadMng = IPACM_OffloadManager::GetInstance();
+ if (OffloadMng->touInstance == NULL) {
+ IPACMERR("OffloadMng->touInstance is NULL, can't forward to framework!\n");
+ } else {
+ OffloadMng->touInstance->updateTimeout(entry);
+ IPACMDBG("Updated time stamp successfully\n");
+ rule->timestamp = new_ts;
+ }
+#endif
+ return;
+}
+
+void NatApp::UpdateUDPTimeStamp()
+{
+ int cnt;
+ uint32_t ts;
+ bool read_to = false;
+
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ ts = 0;
+ if(cache[cnt].enabled == true &&
+ (cache[cnt].private_ip != cache[cnt].public_ip))
+ {
+ IPACMDBG("\n");
+ if(ipa_nat_query_timestamp(nat_table_hdl, cache[cnt].rule_hdl, &ts) < 0)
+ {
+ IPACMERR("unable to retrieve timeout for rule hanle: %d\n", cache[cnt].rule_hdl);
+ continue;
+ }
+
+ if(cache[cnt].timestamp == ts)
+ {
+ IPACMDBG("No Change in Time Stamp: cahce:%d, ipahw:%d\n",
+ cache[cnt].timestamp, ts);
+ continue;
+ }
+
+ if (read_to == false) {
+ read_to = true;
+ Read_TcpUdp_Timeout();
+ }
+
+ UpdateCTUdpTs(&cache[cnt], ts);
+ } /* end of outer if */
+
+ } /* end of for loop */
+
+}
+
+bool NatApp::isAlgPort(uint8_t proto, uint16_t port)
+{
+ int cnt;
+ for(cnt = 0; cnt < nALGPort; cnt++)
+ {
+ if(proto == pALGPorts[cnt].protocol &&
+ port == pALGPorts[cnt].port)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool NatApp::isPwrSaveIf(uint32_t ip_addr)
+{
+ int cnt;
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(0 != PwrSaveIfs[cnt] &&
+ ip_addr == PwrSaveIfs[cnt])
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int NatApp::UpdatePwrSaveIf(uint32_t client_lan_ip)
+{
+ int cnt;
+ IPACMDBG_H("Received IP address: 0x%x\n", client_lan_ip);
+
+ if(client_lan_ip == INVALID_IP_ADDR)
+ {
+ IPACMERR("Invalid ip address received\n");
+ return -1;
+ }
+
+ /* check for duplicate events */
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(PwrSaveIfs[cnt] == client_lan_ip)
+ {
+ IPACMDBG("The client 0x%x is already in power save\n", client_lan_ip);
+ return 0;
+ }
+ }
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(PwrSaveIfs[cnt] == 0)
+ {
+ PwrSaveIfs[cnt] = client_lan_ip;
+ break;
+ }
+ }
+
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == client_lan_ip &&
+ cache[cnt].enabled == true)
+ {
+ if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to delete the rule\n");
+ continue;
+ }
+
+ cache[cnt].enabled = false;
+ cache[cnt].rule_hdl = 0;
+ }
+ }
+
+ return 0;
+}
+
+int NatApp::ResetPwrSaveIf(uint32_t client_lan_ip)
+{
+ int cnt;
+ ipa_nat_ipv4_rule nat_rule;
+
+ IPACMDBG_H("Received ip address: 0x%x\n", client_lan_ip);
+
+ if(client_lan_ip == INVALID_IP_ADDR)
+ {
+ IPACMERR("Invalid ip address received\n");
+ return -1;
+ }
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(PwrSaveIfs[cnt] == client_lan_ip)
+ {
+ PwrSaveIfs[cnt] = 0;
+ break;
+ }
+ }
+
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ IPACMDBG("cache (%d): enable %d, ip 0x%x\n", cnt, cache[cnt].enabled, cache[cnt].private_ip);
+
+ if(cache[cnt].private_ip == client_lan_ip &&
+ cache[cnt].enabled == false)
+ {
+ memset(&nat_rule, 0 , sizeof(nat_rule));
+ nat_rule.private_ip = cache[cnt].private_ip;
+ nat_rule.target_ip = cache[cnt].target_ip;
+ nat_rule.target_port = cache[cnt].target_port;
+ nat_rule.private_port = cache[cnt].private_port;
+ nat_rule.public_port = cache[cnt].public_port;
+ nat_rule.protocol = cache[cnt].protocol;
+
+ if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to add the rule delete from cache\n");
+ memset(&cache[cnt], 0, sizeof(cache[cnt]));
+ curCnt--;
+ continue;
+ }
+ cache[cnt].enabled = true;
+
+ IPACMDBG("On power reset added below rule successfully\n");
+ iptodot("Private IP", nat_rule.private_ip);
+ iptodot("Target IP", nat_rule.target_ip);
+ IPACMDBG("Private Port:%d \t Target Port: %d\t", nat_rule.private_port, nat_rule.target_port);
+ IPACMDBG("Public Port:%d\n", nat_rule.public_port);
+ IPACMDBG("protocol: %d\n", nat_rule.protocol);
+
+ }
+ }
+
+ return -1;
+}
+
+uint32_t NatApp::GetTableHdl(uint32_t in_ip_addr)
+{
+ if(in_ip_addr == pub_ip_addr)
+ {
+ return nat_table_hdl;
+ }
+
+ return -1;
+}
+
+void NatApp::AddTempEntry(const nat_table_entry *new_entry)
+{
+ int cnt;
+
+ IPACMDBG("Received below Temp Nat entry\n");
+ iptodot("Private IP", new_entry->private_ip);
+ iptodot("Target IP", new_entry->target_ip);
+ IPACMDBG("Private Port: %d\t Target Port: %d\t", new_entry->private_port, new_entry->target_port);
+ IPACMDBG("protocolcol: %d\n", new_entry->protocol);
+
+ if(isAlgPort(new_entry->protocol, new_entry->private_port) ||
+ isAlgPort(new_entry->protocol, new_entry->target_port))
+ {
+ IPACMDBG("connection using ALG Port. Dont insert into nat cache\n");
+ return;
+ }
+
+ if(ChkForDup(new_entry))
+ {
+ return;
+ }
+
+ for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
+ {
+ if(temp[cnt].private_ip == new_entry->private_ip &&
+ temp[cnt].target_ip == new_entry->target_ip &&
+ temp[cnt].private_port == new_entry->private_port &&
+ temp[cnt].target_port == new_entry->target_port &&
+ temp[cnt].protocol == new_entry->protocol)
+ {
+ IPACMDBG("Received duplicate Temp entry\n");
+ return;
+ }
+ }
+
+ for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
+ {
+ if(temp[cnt].private_ip == 0 &&
+ temp[cnt].target_ip == 0)
+ {
+ memcpy(&temp[cnt], new_entry, sizeof(nat_table_entry));
+ IPACMDBG("Added Temp Entry\n");
+ return;
+ }
+ }
+
+ IPACMDBG("Unable to add temp entry, cache full\n");
+ return;
+}
+
+void NatApp::DeleteTempEntry(const nat_table_entry *entry)
+{
+ int cnt;
+
+ IPACMDBG("Received below nat entry\n");
+ iptodot("Private IP", entry->private_ip);
+ iptodot("Target IP", entry->target_ip);
+ IPACMDBG("Private Port: %d\t Target Port: %d\n", entry->private_port, entry->target_port);
+ IPACMDBG("protocol: %d\n", entry->protocol);
+
+ for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
+ {
+ if(temp[cnt].private_ip == entry->private_ip &&
+ temp[cnt].target_ip == entry->target_ip &&
+ temp[cnt].private_port == entry->private_port &&
+ temp[cnt].target_port == entry->target_port &&
+ temp[cnt].protocol == entry->protocol)
+ {
+ memset(&temp[cnt], 0, sizeof(nat_table_entry));
+ IPACMDBG("Delete Temp Entry\n");
+ return;
+ }
+ }
+
+ IPACMDBG("No Such Temp Entry exists\n");
+ return;
+}
+
+void NatApp::FlushTempEntries(uint32_t ip_addr, bool isAdd,
+ bool isDummy)
+{
+ int cnt;
+ int ret;
+
+ IPACMDBG_H("Received below with isAdd:%d ", isAdd);
+ iptodot("IP Address: ", ip_addr);
+
+ for(cnt=0; cnt<MAX_TEMP_ENTRIES; cnt++)
+ {
+ if(temp[cnt].private_ip == ip_addr ||
+ temp[cnt].target_ip == ip_addr)
+ {
+ if(isAdd)
+ {
+ if(temp[cnt].public_ip == pub_ip_addr)
+ {
+ if (isDummy) {
+ /* To avoild DL expections for non IPA path */
+ temp[cnt].private_ip = temp[cnt].public_ip;
+ temp[cnt].private_port = temp[cnt].public_port;
+ IPACMDBG("Flushing dummy temp rule");
+ iptodot("Private IP", temp[cnt].private_ip);
+ }
+
+ ret = AddEntry(&temp[cnt]);
+ if(ret)
+ {
+ IPACMERR("unable to add temp entry: %d\n", ret);
+ continue;
+ }
+ }
+ }
+ memset(&temp[cnt], 0, sizeof(nat_table_entry));
+ }
+ }
+
+ return;
+}
+
+int NatApp::DelEntriesOnClntDiscon(uint32_t ip_addr)
+{
+ int cnt, tmp = 0;
+ IPACMDBG_H("Received IP address: 0x%x\n", ip_addr);
+
+ if(ip_addr == INVALID_IP_ADDR)
+ {
+ IPACMERR("Invalid ip address received\n");
+ return -1;
+ }
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(PwrSaveIfs[cnt] == ip_addr)
+ {
+ PwrSaveIfs[cnt] = 0;
+ IPACMDBG("Remove %d power save entry\n", cnt);
+ break;
+ }
+ }
+
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == ip_addr)
+ {
+ if(cache[cnt].enabled == true)
+ {
+ if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to delete the rule\n");
+ continue;
+ }
+ else
+ {
+ IPACMDBG("won't delete the rule\n");
+ cache[cnt].enabled = false;
+ tmp++;
+ }
+ }
+ IPACMDBG("won't delete the rule for entry %d, enabled %d\n",cnt, cache[cnt].enabled);
+ }
+ }
+
+ IPACMDBG("Deleted (but cached) %d entries\n", tmp);
+ return 0;
+}
+
+int NatApp::DelEntriesOnSTAClntDiscon(uint32_t ip_addr)
+{
+ int cnt, tmp = curCnt;
+ IPACMDBG_H("Received IP address: 0x%x\n", ip_addr);
+
+ if(ip_addr == INVALID_IP_ADDR)
+ {
+ IPACMERR("Invalid ip address received\n");
+ return -1;
+ }
+
+
+ for(cnt = 0; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].target_ip == ip_addr)
+ {
+ if(cache[cnt].enabled == true)
+ {
+ if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to delete the rule\n");
+ continue;
+ }
+ }
+
+ memset(&cache[cnt], 0, sizeof(cache[cnt]));
+ curCnt--;
+ }
+ }
+
+ IPACMDBG("Deleted %d entries\n", (tmp - curCnt));
+ return 0;
+}
+
+void NatApp::CacheEntry(const nat_table_entry *rule)
+{
+ int cnt;
+
+ if(rule->private_ip == 0 ||
+ rule->target_ip == 0 ||
+ rule->private_port == 0 ||
+ rule->target_port == 0 ||
+ rule->protocol == 0)
+ {
+ IPACMERR("Invalid Connection, ignoring it\n");
+ return;
+ }
+
+ if(!ChkForDup(rule))
+ {
+ for(cnt=0; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == 0 &&
+ cache[cnt].target_ip == 0 &&
+ cache[cnt].private_port == 0 &&
+ cache[cnt].target_port == 0 &&
+ cache[cnt].protocol == 0)
+ {
+ break;
+ }
+ }
+
+ if(max_entries == cnt)
+ {
+ IPACMERR("Error: Unable to add, reached maximum rules\n");
+ return;
+ }
+ else
+ {
+ cache[cnt].enabled = false;
+ cache[cnt].rule_hdl = 0;
+ cache[cnt].private_ip = rule->private_ip;
+ cache[cnt].target_ip = rule->target_ip;
+ cache[cnt].target_port = rule->target_port;
+ cache[cnt].private_port = rule->private_port;
+ cache[cnt].protocol = rule->protocol;
+ cache[cnt].timestamp = 0;
+ cache[cnt].public_port = rule->public_port;
+ cache[cnt].public_ip = rule->public_ip;
+ cache[cnt].dst_nat = rule->dst_nat;
+ curCnt++;
+ }
+
+ }
+ else
+ {
+ IPACMERR("Duplicate rule. Ignore it\n");
+ return;
+ }
+
+ IPACMDBG("Cached rule(%d) successfully\n", cnt);
+ return;
+}
+
+void NatApp::Read_TcpUdp_Timeout(void) {
+#ifdef FEATURE_IPACM_HAL
+ tcp_timeout = 432000;
+ udp_timeout = 180;
+ IPACMDBG_H("udp timeout value: %d\n", udp_timeout);
+ IPACMDBG_H("tcp timeout value: %d\n", tcp_timeout);
+#else
+ FILE *udp_fd = NULL, *tcp_fd = NULL;
+ /* Read UDP timeout value */
+ udp_fd = fopen(IPACM_UDP_FULL_FILE_NAME, "r");
+ if (udp_fd == NULL) {
+ IPACMERR("unable to open %s\n", IPACM_UDP_FULL_FILE_NAME);
+ goto fail;
+ }
+
+ if (fscanf(udp_fd, "%d", &udp_timeout) != 1) {
+ IPACMERR("Error reading udp timeout\n");
+ }
+ IPACMDBG_H("udp timeout value: %d\n", udp_timeout);
+
+
+ /* Read TCP timeout value */
+ tcp_fd = fopen(IPACM_TCP_FULL_FILE_NAME, "r");
+ if (tcp_fd == NULL) {
+ IPACMERR("unable to open %s\n", IPACM_TCP_FULL_FILE_NAME);
+ goto fail;
+ }
+
+
+ if (fscanf(tcp_fd, "%d", &tcp_timeout) != 1) {
+ IPACMERR("Error reading tcp timeout\n");
+ }
+ IPACMDBG_H("tcp timeout value: %d\n", tcp_timeout);
+
+fail:
+ if (udp_fd) {
+ fclose(udp_fd);
+ }
+ if (tcp_fd) {
+ fclose(tcp_fd);
+ }
+#endif
+ return;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_EvtDispatcher.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_EvtDispatcher.cpp
new file mode 100644
index 0000000..edb5901
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_EvtDispatcher.cpp
@@ -0,0 +1,214 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_EvtDispatcher.cpp
+
+ @brief
+ This file implements the IPAM event dispatcher functionality
+
+ @Author
+
+*/
+#include <string.h>
+#include <pthread.h>
+#include <IPACM_EvtDispatcher.h>
+#include <IPACM_Neighbor.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Defs.h"
+
+
+extern pthread_mutex_t mutex;
+extern pthread_cond_t cond_var;
+
+cmd_evts *IPACM_EvtDispatcher::head = NULL;
+extern uint32_t ipacm_event_stats[IPACM_EVENT_MAX];
+
+int IPACM_EvtDispatcher::PostEvt
+(
+ ipacm_cmd_q_data *data
+)
+{
+ Message *item = NULL;
+ MessageQueue *MsgQueue = NULL;
+
+ if(data->event < IPA_EXTERNAL_EVENT_MAX)
+ {
+ IPACMDBG("Insert event into external queue.\n");
+ MsgQueue = MessageQueue::getInstanceExternal();
+ }
+ else
+ {
+ IPACMDBG("Insert event into internal queue.\n");
+ MsgQueue = MessageQueue::getInstanceInternal();
+ }
+ if(MsgQueue == NULL)
+ {
+ IPACMERR("unable to retrieve MsgQueue instance\n");
+ return IPACM_FAILURE;
+ }
+
+ item = new Message();
+ if(item == NULL)
+ {
+ IPACMERR("unable to create new message item\n");
+ return IPACM_FAILURE;
+ }
+
+ item->evt.callback_ptr = IPACM_EvtDispatcher::ProcessEvt;
+ memcpy(&item->evt.data, data, sizeof(ipacm_cmd_q_data));
+
+ if(pthread_mutex_lock(&mutex) != 0)
+ {
+ IPACMERR("unable to lock the mutex\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("Enqueing item\n");
+ MsgQueue->enqueue(item);
+ IPACMDBG("Enqueued item %p\n", item);
+
+ if(pthread_cond_signal(&cond_var) != 0)
+ {
+ IPACMDBG("unable to lock the mutex\n");
+ /* Release the mutex before you return failure */
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return IPACM_FAILURE;
+ }
+ return IPACM_FAILURE;
+ }
+
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+void IPACM_EvtDispatcher::ProcessEvt(ipacm_cmd_q_data *data)
+{
+
+ cmd_evts *tmp = head, tmp1;
+
+ if(head == NULL)
+ {
+ IPACMDBG("Queue is empty\n");
+ }
+
+ while(tmp != NULL)
+ {
+ memcpy(&tmp1, tmp, sizeof(tmp1));
+ if(data->event == tmp1.event)
+ {
+ ipacm_event_stats[data->event]++;
+ tmp1.obj->event_callback(data->event, data->evt_data);
+ IPACMDBG(" Find matched registered events\n");
+ }
+ tmp = tmp1.next;
+ }
+
+ IPACMDBG(" Finished process events\n");
+
+ if(data->evt_data != NULL)
+ {
+ IPACMDBG("free the event:%d data: %p\n", data->event, data->evt_data);
+ free(data->evt_data);
+ }
+ return;
+}
+
+int IPACM_EvtDispatcher::registr(ipa_cm_event_id event, IPACM_Listener *obj)
+{
+ cmd_evts *tmp = head,*nw;
+
+ nw = (cmd_evts *)malloc(sizeof(cmd_evts));
+ if(nw != NULL)
+ {
+ nw->event = event;
+ nw->obj = obj;
+ nw->next = NULL;
+ }
+ else
+ {
+ return IPACM_FAILURE;
+ }
+
+ if(head == NULL)
+ {
+ head = nw;
+ }
+ else
+ {
+ while(tmp->next)
+ {
+ tmp = tmp->next;
+ }
+ tmp->next = nw;
+ }
+ return IPACM_SUCCESS;
+}
+
+
+int IPACM_EvtDispatcher::deregistr(IPACM_Listener *param)
+{
+ cmd_evts *tmp = head,*tmp1,*prev = head;
+
+ while(tmp != NULL)
+ {
+ if(tmp->obj == param)
+ {
+ tmp1 = tmp;
+ if(tmp == head)
+ {
+ head = head->next;
+ }
+ else if(tmp->next == NULL)
+ {
+ prev->next = NULL;
+ }
+ else
+ {
+ prev->next = tmp->next;
+ }
+
+ tmp = tmp->next;
+ free(tmp1);
+ }
+ else
+ {
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ }
+ return IPACM_SUCCESS;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Filtering.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Filtering.cpp
new file mode 100644
index 0000000..210814f
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Filtering.cpp
@@ -0,0 +1,535 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Filtering.cpp
+
+ @brief
+ This file implements the IPACM filtering functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Filtering.h"
+#include <IPACM_Log.h>
+#include "IPACM_Defs.h"
+
+
+const char *IPACM_Filtering::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Filtering::IPACM_Filtering()
+{
+ fd = open(DEVICE_NAME, O_RDWR);
+ if (fd < 0)
+ {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ }
+}
+
+IPACM_Filtering::~IPACM_Filtering()
+{
+ close(fd);
+}
+
+bool IPACM_Filtering::DeviceNodeIsOpened()
+{
+ return fd;
+}
+
+bool IPACM_Filtering::AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable)
+{
+ int retval = 0;
+
+ IPACMDBG("Printing filter add attributes\n");
+ IPACMDBG("ip type: %d\n", ruleTable->ip);
+ IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
+ IPACMDBG("End point: %d and global value: %d\n", ruleTable->ep, ruleTable->global);
+ IPACMDBG("commit value: %d\n", ruleTable->commit);
+ for (int cnt=0; cnt<ruleTable->num_rules; cnt++)
+ {
+ IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", cnt,
+ ruleTable->rules[cnt].rule.attrib.attrib_mask);
+ }
+
+ retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE, ruleTable);
+ if (retval != 0)
+ {
+ IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
+ PERROR("unable to add filter rule:");
+
+ for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
+ {
+ if (ruleTable->rules[cnt].status != 0)
+ {
+ IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+ cnt, ruleTable->rules[cnt].status);
+ }
+ }
+ return false;
+ }
+
+ for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
+ {
+ if(ruleTable->rules[cnt].status != 0)
+ {
+ IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+ cnt, ruleTable->rules[cnt].status);
+ }
+ }
+
+ IPACMDBG("Added Filtering rule %p\n", ruleTable);
+ return true;
+}
+
+bool IPACM_Filtering::AddFilteringRuleAfter(struct ipa_ioc_add_flt_rule_after const *ruleTable)
+{
+ IPACMDBG("Printing filter add attributes\n");
+ IPACMDBG("ip type: %d\n", ruleTable->ip);
+ IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
+ IPACMDBG("End point: %d\n", ruleTable->ep);
+ IPACMDBG("commit value: %d\n", ruleTable->commit);
+
+#ifdef FEATURE_IPA_V3
+ int retval = 0;
+
+ retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE_AFTER, ruleTable);
+
+ for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
+ {
+ if(ruleTable->rules[cnt].status != 0)
+ {
+ IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+ cnt, ruleTable->rules[cnt].status);
+ }
+ }
+
+ if (retval != 0)
+ {
+ IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
+ return false;
+ }
+ IPACMDBG("Added Filtering rule %p\n", ruleTable);
+#endif
+ return true;
+}
+
+bool IPACM_Filtering::DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable)
+{
+ int retval = 0;
+
+ retval = ioctl(fd, IPA_IOC_DEL_FLT_RULE, ruleTable);
+ if (retval != 0)
+ {
+ IPACMERR("Failed deleting Filtering rule %p\n", ruleTable);
+ return false;
+ }
+
+ IPACMDBG("Deleted Filtering rule %p\n", ruleTable);
+ return true;
+}
+
+bool IPACM_Filtering::Commit(enum ipa_ip_type ip)
+{
+ int retval = 0;
+
+ retval = ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+ if (retval != 0)
+ {
+ IPACMERR("failed committing Filtering rules.\n");
+ return false;
+ }
+
+ IPACMDBG("Committed Filtering rules to IPA HW.\n");
+ return true;
+}
+
+bool IPACM_Filtering::Reset(enum ipa_ip_type ip)
+{
+ int retval = 0;
+
+ retval = ioctl(fd, IPA_IOC_RESET_FLT, ip);
+ retval |= ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+ if (retval)
+ {
+ IPACMERR("failed resetting Filtering block.\n");
+ return false;
+ }
+
+ IPACMDBG("Reset command issued to IPA Filtering block.\n");
+ return true;
+}
+
+bool IPACM_Filtering::DeleteFilteringHdls
+(
+ uint32_t *flt_rule_hdls,
+ ipa_ip_type ip,
+ uint8_t num_rules
+)
+{
+ struct ipa_ioc_del_flt_rule *flt_rule;
+ bool res = true;
+ int len = 0, cnt = 0;
+ const uint8_t UNIT_RULES = 1;
+
+ len = (sizeof(struct ipa_ioc_del_flt_rule)) + (UNIT_RULES * sizeof(struct ipa_flt_rule_del));
+ flt_rule = (struct ipa_ioc_del_flt_rule *)malloc(len);
+ if (flt_rule == NULL)
+ {
+ IPACMERR("unable to allocate memory for del filter rule\n");
+ return false;
+ }
+
+ for (cnt = 0; cnt < num_rules; cnt++)
+ {
+ memset(flt_rule, 0, len);
+ flt_rule->commit = 1;
+ flt_rule->num_hdls = UNIT_RULES;
+ flt_rule->ip = ip;
+
+ if (flt_rule_hdls[cnt] == 0)
+ {
+ IPACMERR("invalid filter handle passed, ignoring it: %d\n", cnt)
+ }
+ else
+ {
+
+ flt_rule->hdl[0].status = -1;
+ flt_rule->hdl[0].hdl = flt_rule_hdls[cnt];
+ IPACMDBG("Deleting filter hdl:(0x%x) with ip type: %d\n", flt_rule_hdls[cnt], ip);
+
+ if (DeleteFilteringRule(flt_rule) == false)
+ {
+ PERROR("Filter rule deletion failed!\n");
+ res = false;
+ goto fail;
+ }
+ else
+ {
+
+ if (flt_rule->hdl[0].status != 0)
+ {
+ IPACMERR("Filter rule hdl 0x%x deletion failed with error:%d\n",
+ flt_rule->hdl[0].hdl, flt_rule->hdl[0].status);
+ res = false;
+ goto fail;
+ }
+ }
+ }
+ }
+
+fail:
+ free(flt_rule);
+
+ return res;
+}
+
+bool IPACM_Filtering::AddWanDLFilteringRule(struct ipa_ioc_add_flt_rule const *rule_table_v4, struct ipa_ioc_add_flt_rule const * rule_table_v6, uint8_t mux_id)
+{
+ int ret = 0, cnt, num_rules = 0, pos = 0;
+ ipa_install_fltr_rule_req_msg_v01 qmi_rule_msg;
+#ifdef FEATURE_IPA_V3
+ ipa_install_fltr_rule_req_ex_msg_v01 qmi_rule_ex_msg;
+#endif
+
+ memset(&qmi_rule_msg, 0, sizeof(qmi_rule_msg));
+ int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
+ if(fd_wwan_ioctl < 0)
+ {
+ IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
+ return false;
+ }
+
+ if(rule_table_v4 != NULL)
+ {
+ num_rules += rule_table_v4->num_rules;
+ IPACMDBG_H("Get %d WAN DL IPv4 filtering rules.\n", rule_table_v4->num_rules);
+ }
+ if(rule_table_v6 != NULL)
+ {
+ num_rules += rule_table_v6->num_rules;
+ IPACMDBG_H("Get %d WAN DL IPv6 filtering rules.\n", rule_table_v6->num_rules);
+ }
+
+ /* if it is not IPA v3, use old QMI format */
+#ifndef FEATURE_IPA_V3
+ if(num_rules > QMI_IPA_MAX_FILTERS_V01)
+ {
+ IPACMERR("The number of filtering rules exceed limit.\n");
+ close(fd_wwan_ioctl);
+ return false;
+ }
+ else
+ {
+ if (num_rules > 0)
+ {
+ qmi_rule_msg.filter_spec_list_valid = true;
+ }
+ else
+ {
+ qmi_rule_msg.filter_spec_list_valid = false;
+ }
+
+ qmi_rule_msg.filter_spec_list_len = num_rules;
+ qmi_rule_msg.source_pipe_index_valid = 0;
+
+ IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
+
+ if(rule_table_v4 != NULL)
+ {
+ for(cnt = rule_table_v4->num_rules - 1; cnt >= 0; cnt--)
+ {
+ if (pos < QMI_IPA_MAX_FILTERS_V01)
+ {
+ qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
+ qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
+ qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
+ qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
+ qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
+ qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
+ qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
+ memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
+ &rule_table_v4->rules[cnt].rule.eq_attrib,
+ sizeof(struct ipa_filter_rule_type_v01));
+ pos++;
+ }
+ else
+ {
+ IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
+ }
+ }
+ }
+
+ if(rule_table_v6 != NULL)
+ {
+ for(cnt = rule_table_v6->num_rules - 1; cnt >= 0; cnt--)
+ {
+ if (pos < QMI_IPA_MAX_FILTERS_V01)
+ {
+ qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
+ qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
+ qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
+ qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
+ qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
+ qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
+ qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
+ memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
+ &rule_table_v6->rules[cnt].rule.eq_attrib,
+ sizeof(struct ipa_filter_rule_type_v01));
+ pos++;
+ }
+ else
+ {
+ IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
+ }
+ }
+ }
+
+ ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE, &qmi_rule_msg);
+ if (ret != 0)
+ {
+ IPACMERR("Failed adding Filtering rule %p with ret %d\n ", &qmi_rule_msg, ret);
+ close(fd_wwan_ioctl);
+ return false;
+ }
+ }
+ /* if it is IPA v3, use new QMI format */
+#else
+ if(num_rules > QMI_IPA_MAX_FILTERS_EX_V01)
+ {
+ IPACMERR("The number of filtering rules exceed limit.\n");
+ close(fd_wwan_ioctl);
+ return false;
+ }
+ else
+ {
+ memset(&qmi_rule_ex_msg, 0, sizeof(qmi_rule_ex_msg));
+
+ if (num_rules > 0)
+ {
+ qmi_rule_ex_msg.filter_spec_ex_list_valid = true;
+ }
+ else
+ {
+ qmi_rule_ex_msg.filter_spec_ex_list_valid = false;
+ }
+ qmi_rule_ex_msg.filter_spec_ex_list_len = num_rules;
+ qmi_rule_ex_msg.source_pipe_index_valid = 0;
+
+ IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
+
+ if(rule_table_v4 != NULL)
+ {
+ for(cnt = rule_table_v4->num_rules - 1; cnt >= 0; cnt--)
+ {
+ if (pos < QMI_IPA_MAX_FILTERS_EX_V01)
+ {
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].mux_id = mux_id;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].rule_id = rule_table_v4->rules[cnt].rule.rule_id;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v4->rules[cnt].rule.hashable;
+ memcpy(&qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_rule,
+ &rule_table_v4->rules[cnt].rule.eq_attrib,
+ sizeof(struct ipa_filter_rule_type_v01));
+
+ pos++;
+ }
+ else
+ {
+ IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_EX_V01, pos);
+ }
+ }
+ }
+
+ if(rule_table_v6 != NULL)
+ {
+ for(cnt = rule_table_v6->num_rules - 1; cnt >= 0; cnt--)
+ {
+ if (pos < QMI_IPA_MAX_FILTERS_EX_V01)
+ {
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].mux_id = mux_id;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].rule_id = rule_table_v6->rules[cnt].rule.rule_id;
+ qmi_rule_ex_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v6->rules[cnt].rule.hashable;
+ memcpy(&qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_rule,
+ &rule_table_v6->rules[cnt].rule.eq_attrib,
+ sizeof(struct ipa_filter_rule_type_v01));
+
+ pos++;
+ }
+ else
+ {
+ IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_EX_V01, pos);
+ }
+ }
+ }
+
+ ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE_EX, &qmi_rule_ex_msg);
+ if (ret != 0)
+ {
+ IPACMERR("Failed adding Filtering rule %p with ret %d\n ", &qmi_rule_ex_msg, ret);
+ close(fd_wwan_ioctl);
+ return false;
+ }
+ }
+#endif
+
+ close(fd_wwan_ioctl);
+ return true;
+}
+
+bool IPACM_Filtering::SendFilteringRuleIndex(struct ipa_fltr_installed_notif_req_msg_v01* table)
+{
+ int ret = 0;
+ int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
+ if(fd_wwan_ioctl < 0)
+ {
+ IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
+ return false;
+ }
+
+ ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE_INDEX, table);
+ if (ret != 0)
+ {
+ IPACMERR("Failed adding filtering rule index %p with ret %d\n", table, ret);
+ close(fd_wwan_ioctl);
+ return false;
+ }
+
+ IPACMDBG("Added Filtering rule index %p\n", table);
+ close(fd_wwan_ioctl);
+ return true;
+}
+
+ipa_filter_action_enum_v01 IPACM_Filtering::GetQmiFilterAction(ipa_flt_action action)
+{
+ switch(action)
+ {
+ case IPA_PASS_TO_ROUTING:
+ return QMI_IPA_FILTER_ACTION_ROUTING_V01;
+
+ case IPA_PASS_TO_SRC_NAT:
+ return QMI_IPA_FILTER_ACTION_SRC_NAT_V01;
+
+ case IPA_PASS_TO_DST_NAT:
+ return QMI_IPA_FILTER_ACTION_DST_NAT_V01;
+
+ case IPA_PASS_TO_EXCEPTION:
+ return QMI_IPA_FILTER_ACTION_EXCEPTION_V01;
+
+ default:
+ return IPA_FILTER_ACTION_ENUM_MAX_ENUM_VAL_V01;
+ }
+}
+
+bool IPACM_Filtering::ModifyFilteringRule(struct ipa_ioc_mdfy_flt_rule* ruleTable)
+{
+ int i, ret = 0;
+
+ IPACMDBG("Printing filtering add attributes\n");
+ IPACMDBG("IP type: %d Number of rules: %d commit value: %d\n", ruleTable->ip, ruleTable->num_rules, ruleTable->commit);
+
+ for (i=0; i<ruleTable->num_rules; i++)
+ {
+ IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", i, ruleTable->rules[i].rule.attrib.attrib_mask);
+ }
+
+ ret = ioctl(fd, IPA_IOC_MDFY_FLT_RULE, ruleTable);
+ if (ret != 0)
+ {
+ IPACMERR("Failed modifying filtering rule %p\n", ruleTable);
+
+ for (i = 0; i < ruleTable->num_rules; i++)
+ {
+ if (ruleTable->rules[i].status != 0)
+ {
+ IPACMERR("Modifying filter rule %d failed\n", i);
+ }
+ }
+ return false;
+ }
+
+ IPACMDBG("Modified filtering rule %p\n", ruleTable);
+ return true;
+}
+
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Header.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Header.cpp
new file mode 100644
index 0000000..c77c69c
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Header.cpp
@@ -0,0 +1,236 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Header.h"
+#include "IPACM_Log.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//All interaction through the driver are made through this inode.
+static const char *DEVICE_NAME = "/dev/ipa";
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+IPACM_Header::IPACM_Header()
+{
+ m_fd = open(DEVICE_NAME, O_RDWR);
+ if (-1 == m_fd)
+ {
+ IPACMERR("Failed to open %s in IPACM_Header test application constructor.\n", DEVICE_NAME);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+IPACM_Header::~IPACM_Header()
+{
+ if (-1 != m_fd)
+ {
+ close(m_fd);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::DeviceNodeIsOpened()
+{
+ return (-1 != m_fd);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::AddHeader(struct ipa_ioc_add_hdr *pHeaderTableToAdd)
+{
+ int nRetVal = 0;
+ //call the Driver ioctl in order to add header
+ nRetVal = ioctl(m_fd, IPA_IOC_ADD_HDR, pHeaderTableToAdd);
+ IPACMDBG("return value: %d\n", nRetVal);
+ return (-1 != nRetVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTableToDelete)
+{
+ int nRetVal = 0;
+ //call the Driver ioctl in order to remove header
+ nRetVal = ioctl(m_fd, IPA_IOC_DEL_HDR, pHeaderTableToDelete);
+ IPACMDBG("return value: %d\n", nRetVal);
+ return (-1 != nRetVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::Commit()
+{
+ int nRetVal = 0;
+ nRetVal = ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+ IPACMDBG("return value: %d\n", nRetVal);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::Reset()
+{
+ int nRetVal = 0;
+
+ nRetVal = ioctl(m_fd, IPA_IOC_RESET_HDR);
+ nRetVal |= ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+ IPACMDBG("return value: %d\n", nRetVal);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_GET_HDR, pHeaderStruct);
+ if (retval)
+ {
+ IPACMERR("IPA_IOC_GET_HDR ioctl failed, routingTable =0x%p, retval=0x%x.\n", pHeaderStruct, retval);
+ return false;
+ }
+
+ IPACMDBG("IPA_IOC_GET_HDR ioctl issued to IPA header insertion block.\n");
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_COPY_HDR, pCopyHeaderStruct);
+ if (retval)
+ {
+ IPACMERR("IPA_IOC_COPY_HDR ioctl failed, retval=0x%x.\n", retval);
+ return false;
+ }
+
+ IPACMDBG("IPA_IOC_COPY_HDR ioctl issued to IPA header insertion block.\n");
+ return true;
+}
+
+bool IPACM_Header::DeleteHeaderHdl(uint32_t hdr_hdl)
+{
+ const uint8_t NUM_HDLS = 1;
+ struct ipa_ioc_del_hdr *pHeaderDescriptor = NULL;
+ struct ipa_hdr_del *hd_rule_entry;
+ int len = 0;
+ bool res = true;
+
+ if (hdr_hdl == 0)
+ {
+ IPACMERR("Invalid header handle passed. Ignoring it\n");
+ return false;
+ }
+
+ len = (sizeof(struct ipa_ioc_del_hdr)) + (NUM_HDLS * sizeof(struct ipa_hdr_del));
+ pHeaderDescriptor = (struct ipa_ioc_del_hdr *)malloc(len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("Unable to allocate memory for del header\n");
+ return false;
+ }
+
+ memset(pHeaderDescriptor, 0, len);
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdls = NUM_HDLS;
+ hd_rule_entry = &pHeaderDescriptor->hdl[0];
+
+ hd_rule_entry->hdl = hdr_hdl;
+ hd_rule_entry->status = -1;
+
+ IPACMDBG("Deleting Header hdl:(%x)\n", hd_rule_entry->hdl);
+ if ((false == DeleteHeader(pHeaderDescriptor)) ||
+ (hd_rule_entry->status))
+ {
+ IPACMERR("Header hdl:(%x) deletion failed! status: %d\n", hd_rule_entry->hdl,hd_rule_entry->status);
+ res = false;
+ goto fail;
+ }
+
+ IPACMDBG_H("Deleted Header hdl:(%x) successfully\n", hd_rule_entry->hdl);
+
+fail:
+ free(pHeaderDescriptor);
+
+ return res;
+
+}
+
+bool IPACM_Header::AddHeaderProcCtx(struct ipa_ioc_add_hdr_proc_ctx* pHeader)
+{
+ int ret = 0;
+ //call the Driver ioctl to add header processing context
+ ret = ioctl(m_fd, IPA_IOC_ADD_HDR_PROC_CTX, pHeader);
+ return (ret == 0);
+}
+
+bool IPACM_Header::DeleteHeaderProcCtx(uint32_t hdl)
+{
+ int len, ret;
+ struct ipa_ioc_del_hdr_proc_ctx* pHeaderTable = NULL;
+
+ len = sizeof(struct ipa_ioc_del_hdr_proc_ctx) + sizeof(struct ipa_hdr_proc_ctx_del);
+ pHeaderTable = (struct ipa_ioc_del_hdr_proc_ctx*)malloc(len);
+ if(pHeaderTable == NULL)
+ {
+ IPACMERR("Failed to allocate buffer.\n");
+ return false;
+ }
+ memset(pHeaderTable, 0, len);
+
+ pHeaderTable->commit = 1;
+ pHeaderTable->num_hdls = 1;
+ pHeaderTable->hdl[0].hdl = hdl;
+
+ ret = ioctl(m_fd, IPA_IOC_DEL_HDR_PROC_CTX, pHeaderTable);
+ if(ret != 0)
+ {
+ IPACMERR("Failed to delete hdr proc ctx: return value %d, status %d\n",
+ ret, pHeaderTable->hdl[0].status);
+ }
+ free(pHeaderTable);
+ return (ret == 0);
+}
+
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Iface.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Iface.cpp
new file mode 100644
index 0000000..36e2141
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Iface.cpp
@@ -0,0 +1,1029 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+* Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.Z
+*/
+/*!
+ @file
+ IPACM_Iface.cpp
+
+ @brief
+ This file implements the basis Iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <IPACM_Netlink.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Wlan.h>
+#include <string.h>
+
+extern "C"
+{
+#include <ifaddrs.h>
+}
+
+
+const char *IPACM_Iface::DEVICE_NAME = "/dev/ipa";
+IPACM_Routing IPACM_Iface::m_routing;
+IPACM_Filtering IPACM_Iface::m_filtering;
+IPACM_Header IPACM_Iface::m_header;
+
+IPACM_Config *IPACM_Iface::ipacmcfg = IPACM_Config::GetInstance();
+
+IPACM_Iface::IPACM_Iface(int iface_index)
+{
+ ip_type = IPACM_IP_NULL; /* initially set invalid */
+ num_dft_rt_v6 = 0;
+ softwarerouting_act = false;
+ ipa_if_num = iface_index;
+ ipa_if_cate = IPACM_Iface::ipacmcfg->iface_table[iface_index].if_cat;
+
+ iface_query = NULL;
+ tx_prop = NULL;
+ rx_prop = NULL;
+
+ memcpy(dev_name,
+ IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name,
+ sizeof(IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name));
+
+ memset(dft_v4fl_rule_hdl, 0, sizeof(dft_v4fl_rule_hdl));
+ memset(dft_v6fl_rule_hdl, 0, sizeof(dft_v6fl_rule_hdl));
+
+ memset(dft_rt_rule_hdl, 0, sizeof(dft_rt_rule_hdl));
+ memset(software_routing_fl_rule_hdl, 0, sizeof(software_routing_fl_rule_hdl));
+ memset(ipv6_addr, 0, sizeof(ipv6_addr));
+
+ query_iface_property();
+ IPACMDBG_H(" create iface-index(%d) constructor\n", ipa_if_num);
+ return;
+}
+
+/* software routing enable */
+int IPACM_Iface::handle_software_routing_enable(void)
+{
+
+ int res = IPACM_SUCCESS;
+ struct ipa_flt_rule_add flt_rule_entry;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("\n");
+ if (softwarerouting_act == true)
+ {
+ IPACMDBG("already setup software_routing rule for (%s)iface ip-family %d\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
+ return IPACM_SUCCESS;
+ }
+
+ if(rx_prop == NULL)
+ {
+ IPACMDBG("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+ if (!m_pFilteringTable)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+ /* Configuring Software-Routing Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = false;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* check iface is v4 or v6 or both*/
+// if (ip_type == IPA_IP_MAX)
+// {
+ /* handle v4 */
+ m_pFilteringTable->ip = IPA_IP_v4;
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+
+ /* handle v6*/
+ m_pFilteringTable->ip = IPA_IP_v6;
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ softwarerouting_act = true;
+#if 0
+ }
+ else
+ {
+ if (ip_type == IPA_IP_v4)
+ {
+ m_pFilteringTable->ip = IPA_IP_v4;
+ }
+ else
+ {
+ m_pFilteringTable->ip = IPA_IP_v6;
+ }
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, ip_type, 1);
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ if (ip_type == IPA_IP_v4)
+ {
+ software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+ else
+ {
+ software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+ softwarerouting_act = true;
+ }
+#endif
+
+fail:
+ free(m_pFilteringTable);
+
+ return res;
+}
+
+/* software routing disable */
+int IPACM_Iface::handle_software_routing_disable(void)
+{
+ int res = IPACM_SUCCESS;
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ if (softwarerouting_act == false)
+ {
+ IPACMDBG("already delete software_routing rule for (%s)iface ip-family %d\n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
+ return IPACM_SUCCESS;
+ }
+
+// if (ip_type == IPA_IP_MAX)
+// {
+ /* ipv4 case */
+ if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[0],
+ IPA_IP_v4, 1) == false)
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+
+ /* ipv6 case */
+ if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[1],
+ IPA_IP_v6, 1) == false)
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ softwarerouting_act = false;
+#if 0
+ }
+ else
+ {
+ if (ip_type == IPA_IP_v4)
+ {
+ ip = IPA_IP_v4;
+ }
+ else
+ {
+ ip = IPA_IP_v6;
+ }
+
+
+ if (ip_type == IPA_IP_v4)
+ {
+ flt_hdl = software_routing_fl_rule_hdl[0];
+ }
+ else
+ {
+ flt_hdl = software_routing_fl_rule_hdl[1];
+ }
+
+ if (m_filtering.DeleteFilteringHdls(&flt_hdl, ip, 1) == false)
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, ip, 1);
+ softwarerouting_act = false;
+ }
+#endif
+
+fail:
+ return res;
+}
+
+/* Query ipa_interface_index by given linux interface_index */
+int IPACM_Iface::iface_ipa_index_query
+(
+ int interface_index
+)
+{
+ int fd;
+ int link = INVALID_IFACE;
+ int i = 0;
+ struct ifreq ifr;
+
+
+ if(IPACM_Iface::ipacmcfg->iface_table == NULL)
+ {
+ IPACMERR("Iface table in IPACM_Config is not available.\n");
+ return link;
+ }
+
+ /* Search known linux interface-index and map to IPA interface-index*/
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
+ {
+ if (interface_index == IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index)
+ {
+ link = i;
+ IPACMDBG("Interface (%s) found: linux(%d) ipa(%d) \n",
+ IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
+ IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index,
+ link);
+ return link;
+ break;
+ }
+ }
+
+ /* Search/Configure linux interface-index and map it to IPA interface-index */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ PERROR("get interface name socket create failed");
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ ifr.ifr_ifindex = interface_index;
+ IPACMDBG_H("Interface index %d\n", interface_index);
+
+ if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+ {
+ PERROR("call_ioctl_on_dev: ioctl failed:");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ close(fd);
+
+ IPACMDBG_H("Received interface name %s\n", ifr.ifr_name);
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
+ {
+ if (strncmp(ifr.ifr_name,
+ IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
+ sizeof(IPACM_Iface::ipacmcfg->iface_table[i].iface_name)) == 0)
+ {
+ IPACMDBG_H("Interface (%s) linux(%d) mapped to ipa(%d) \n", ifr.ifr_name,
+ IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index, i);
+
+ link = i;
+ IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index = interface_index;
+ break;
+ }
+ }
+
+ return link;
+}
+
+/* Query ipa_interface ipv4_addr by given linux interface_index */
+void IPACM_Iface::iface_addr_query
+(
+ int interface_index
+)
+{
+ int fd;
+ struct ifreq ifr;
+ struct ifaddrs *myaddrs, *ifa;
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_addr *data_addr;
+ struct in_addr iface_ipv4;
+
+ /* use linux interface-index to find interface name */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ PERROR("get interface name socket create failed");
+ return ;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ ifr.ifr_ifindex = interface_index;
+ IPACMDBG_H("Interface index %d\n", interface_index);
+
+ if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+ {
+ PERROR("call_ioctl_on_dev: ioctl failed:");
+ close(fd);
+ return ;
+ }
+ IPACMDBG_H("Interface index %d name: %s\n", interface_index,ifr.ifr_name);
+ close(fd);
+
+ /* query ipv4/v6 address */
+ if(getifaddrs(&myaddrs) != 0)
+ {
+ IPACMERR("getifaddrs");
+ return ;
+ }
+
+ for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
+ {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if (!(ifa->ifa_flags & IFF_UP))
+ continue;
+
+ if(strcmp(ifr.ifr_name,ifa->ifa_name) == 0) // find current iface
+ {
+ IPACMDBG_H("Internal post new_addr event for iface %s\n", ifa->ifa_name);
+ switch (ifa->ifa_addr->sa_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *s4 = (struct sockaddr_in *)ifa->ifa_addr;
+ IPACMDBG_H("ipv4 address %s\n",inet_ntoa(s4->sin_addr));
+ iface_ipv4 = s4->sin_addr;
+ /* post new_addr event to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ freeifaddrs(myaddrs);
+ return ;
+ }
+ memset(data_addr, 0, sizeof(ipacm_event_data_addr));
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->if_index = interface_index;
+ data_addr->ipv4_addr = iface_ipv4.s_addr;
+ data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+ strlcpy(data_addr->iface_name, ifr.ifr_name, sizeof(data_addr->iface_name));
+ IPACMDBG_H("Posting IPA_ADDR_ADD_EVENT with if index:%d, if name:%s, ipv4 addr:0x%x\n",
+ data_addr->if_index,
+ data_addr->iface_name,
+ data_addr->ipv4_addr);
+
+ evt_data.event = IPA_ADDR_ADD_EVENT;
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ break;
+ }
+
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ /* post new_addr event to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ freeifaddrs(myaddrs);
+ return ;
+ }
+ memset(data_addr, 0, sizeof(ipacm_event_data_addr));
+ data_addr->iptype = IPA_IP_v6;
+ data_addr->if_index = interface_index;
+ memcpy(data_addr->ipv6_addr,
+ &s6->sin6_addr,
+ sizeof(data_addr->ipv6_addr));
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+ strlcpy(data_addr->iface_name, ifr.ifr_name, sizeof(data_addr->iface_name));
+ IPACMDBG_H("Posting IPA_ADDR_ADD_EVENT with if index:%d, if name:%s, ipv6 addr:0x%x:%x:%x:%x\n",
+ data_addr->if_index,
+ data_addr->iface_name,
+ data_addr->ipv6_addr[0], data_addr->ipv6_addr[1], data_addr->ipv6_addr[2], data_addr->ipv6_addr[3]);
+
+ evt_data.event = IPA_ADDR_ADD_EVENT;
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ break;
+ }
+
+ default:
+ continue;
+ }
+ }
+ }
+ freeifaddrs(myaddrs);
+ return ;
+}
+
+/*Query the IPA endpoint property */
+int IPACM_Iface::query_iface_property(void)
+{
+ int res = IPACM_SUCCESS, fd = 0;
+ uint32_t cnt=0;
+
+ fd = open(DEVICE_NAME, O_RDWR);
+ IPACMDBG("iface query-property \n");
+ if (0 == fd)
+ {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+
+ iface_query = (struct ipa_ioc_query_intf *)
+ calloc(1, sizeof(struct ipa_ioc_query_intf));
+ if(iface_query == NULL)
+ {
+ IPACMERR("Unable to allocate iface_query memory.\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("iface name %s\n", dev_name);
+ memcpy(iface_query->name, dev_name, sizeof(dev_name));
+
+ if (ioctl(fd, IPA_IOC_QUERY_INTF, iface_query) < 0)
+ {
+ PERROR("ioctl IPA_IOC_QUERY_INTF failed\n");
+ /* iface_query memory will free when iface-down*/
+ res = IPACM_FAILURE;
+ }
+
+ if(iface_query->num_tx_props > 0)
+ {
+ tx_prop = (struct ipa_ioc_query_intf_tx_props *)
+ calloc(1, sizeof(struct ipa_ioc_query_intf_tx_props) +
+ iface_query->num_tx_props * sizeof(struct ipa_ioc_tx_intf_prop));
+ if(tx_prop == NULL)
+ {
+ IPACMERR("Unable to allocate tx_prop memory.\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ memcpy(tx_prop->name, dev_name, sizeof(tx_prop->name));
+ tx_prop->num_tx_props = iface_query->num_tx_props;
+
+ if (ioctl(fd, IPA_IOC_QUERY_INTF_TX_PROPS, tx_prop) < 0)
+ {
+ PERROR("ioctl IPA_IOC_QUERY_INTF_TX_PROPS failed\n");
+ /* tx_prop memory will free when iface-down*/
+ res = IPACM_FAILURE;
+ }
+
+ if (res != IPACM_FAILURE)
+ {
+ for (cnt = 0; cnt < tx_prop->num_tx_props; cnt++)
+ {
+ IPACMDBG_H("Tx(%d):attrib-mask:0x%x, ip-type: %d, dst_pipe: %d, alt_dst_pipe: %d, header: %s\n",
+ cnt, tx_prop->tx[cnt].attrib.attrib_mask,
+ tx_prop->tx[cnt].ip, tx_prop->tx[cnt].dst_pipe,
+ tx_prop->tx[cnt].alt_dst_pipe,
+ tx_prop->tx[cnt].hdr_name);
+
+ if (tx_prop->tx[cnt].dst_pipe == 0)
+ {
+ IPACMERR("Tx(%d): wrong tx property: dst_pipe: 0.\n", cnt);
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ if (tx_prop->tx[cnt].alt_dst_pipe == 0 &&
+ ((memcmp(dev_name, "wlan0", sizeof("wlan0")) == 0) ||
+ (memcmp(dev_name, "wlan1", sizeof("wlan1")) == 0)))
+ {
+ IPACMERR("Tx(%d): wrong tx property: alt_dst_pipe: 0. \n", cnt);
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ }
+ }
+
+ }
+
+ if (iface_query->num_rx_props > 0)
+ {
+ rx_prop = (struct ipa_ioc_query_intf_rx_props *)
+ calloc(1, sizeof(struct ipa_ioc_query_intf_rx_props) +
+ iface_query->num_rx_props * sizeof(struct ipa_ioc_rx_intf_prop));
+ if(rx_prop == NULL)
+ {
+ IPACMERR("Unable to allocate rx_prop memory.\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ memcpy(rx_prop->name, dev_name,
+ sizeof(rx_prop->name));
+ rx_prop->num_rx_props = iface_query->num_rx_props;
+
+ if (ioctl(fd, IPA_IOC_QUERY_INTF_RX_PROPS, rx_prop) < 0)
+ {
+ PERROR("ioctl IPA_IOC_QUERY_INTF_RX_PROPS failed\n");
+ /* rx_prop memory will free when iface-down*/
+ res = IPACM_FAILURE;
+ }
+
+ if (res != IPACM_FAILURE)
+ {
+ for (cnt = 0; cnt < rx_prop->num_rx_props; cnt++)
+ {
+ IPACMDBG_H("Rx(%d):attrib-mask:0x%x, ip-type: %d, src_pipe: %d\n",
+ cnt, rx_prop->rx[cnt].attrib.attrib_mask, rx_prop->rx[cnt].ip, rx_prop->rx[cnt].src_pipe);
+ }
+ }
+ }
+
+ /* Add Natting iface to IPACM_Config if there is Rx/Tx property */
+ if (rx_prop != NULL || tx_prop != NULL)
+ {
+ IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
+ IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
+ }
+
+ close(fd);
+ return res;
+}
+
+/*Configure the initial filter rules */
+int IPACM_Iface::init_fl_rule(ipa_ip_type iptype)
+{
+
+ int res = IPACM_SUCCESS, len = 0;
+ struct ipa_flt_rule_add flt_rule_entry;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ /* Adding this hack because WLAN may not registered for Rx-endpoint, other ifaces will always have*/
+ const char *dev_wlan0="wlan0";
+ const char *dev_wlan1="wlan1";
+ const char *dev_ecm0="ecm0";
+
+ /* ADD corresponding ipa_rm_resource_name of RX-endpoint before adding all IPV4V6 FT-rules */
+ if((IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat== WAN_IF) || (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat== EMBMS_IF))
+ {
+ IPACMDBG_H(" NOT add producer dependency on dev %s with registered rx-prop cat:%d \n", dev_name, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat);
+ }
+ else
+ {
+ if(rx_prop != NULL)
+ {
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+ IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe],false);
+ }
+ else
+ {
+ /* only wlan may take software-path, not register Rx-property*/
+ if(strcmp(dev_name,dev_wlan0) == 0 || strcmp(dev_name,dev_wlan1) == 0)
+ {
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got piperm index : %d \n", IPA_RM_RESOURCE_HSIC_PROD);
+ IPACM_Iface::ipacmcfg->AddRmDepend(IPA_RM_RESOURCE_HSIC_PROD,true);
+ }
+ if(strcmp(dev_name,dev_ecm0) == 0)
+ {
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got piperm index : %d \n", IPA_RM_RESOURCE_USB_PROD);
+ IPACM_Iface::ipacmcfg->AddRmDepend(IPA_RM_RESOURCE_USB_PROD,true);
+ }
+ }
+ }
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ /* construct ipa_ioc_add_flt_rule with default filter rules */
+ if (iptype == IPA_IP_v4)
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!m_pFilteringTable)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV4_DEFAULT_FILTERTING_RULES;
+
+ /* Configuring Fragment Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = false;
+ flt_rule_entry.rule.hashable = false;
+#endif
+ IPACMDBG_H("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring Multicast Filtering Rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xF0000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring Broadcast Filtering Rule */
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
+ /* copy filter hdls */
+ for (int i = 0; i < IPV4_DEFAULT_FILTERTING_RULES; i++)
+ {
+ if (m_pFilteringTable->rules[i].status == 0)
+ {
+ dft_v4fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ IPACMDBG_H("Default v4 filter Rule %d HDL:0x%x\n", i, dft_v4fl_rule_hdl[i]);
+ }
+ else
+ {
+ IPACMERR("Failed adding default v4 Filtering rule %d\n", i);
+ }
+ }
+ }
+ }
+ else
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!m_pFilteringTable)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ /* Configuring Multicast Filtering Rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFF000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0XFF000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring fe80::/10 Link-Scoped Unicast Filtering Rule */
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0XFFC00000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFE800000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring fec0::/10 Reserved by IETF Filtering Rule */
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0XFFC00000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFEC00000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring fd00::/8 Unique Local Ipv6 Address */
+ 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] = 0xFD000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&(m_pFilteringTable->rules[3]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+#ifdef FEATURE_IPA_ANDROID
+ IPACMDBG_H("Add TCP ctrl rules: total num %d\n", IPV6_DEFAULT_FILTERTING_RULES);
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap = 0;
+
+ if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA)
+ {
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<9);
+#else
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<14);
+#endif
+ flt_rule_entry.rule.eq_attrib.metadata_meq32_present = 1;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.offset = 0;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.value = rx_prop->rx[0].attrib.meta_data;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.mask = rx_prop->rx[0].attrib.meta_data_mask;
+ }
+
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
+ flt_rule_entry.rule.eq_attrib.protocol_eq_present = 1;
+ flt_rule_entry.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
+
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<7);
+#else
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
+#endif
+ flt_rule_entry.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
+
+ /* add TCP FIN rule*/
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
+ memcpy(&(m_pFilteringTable->rules[4]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* add TCP SYN rule*/
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_SYN_SHIFT);
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_SYN_SHIFT);
+ memcpy(&(m_pFilteringTable->rules[5]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* add TCP RST rule*/
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
+ memcpy(&(m_pFilteringTable->rules[6]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+#endif
+ if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
+ /* copy filter hdls */
+ for (int i = 0;
+ i < IPV6_DEFAULT_FILTERTING_RULES;
+ i++)
+ {
+ if (m_pFilteringTable->rules[i].status == 0)
+ {
+ dft_v6fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ IPACMDBG_H("Default v6 Filter Rule %d HDL:0x%x\n", i, dft_v6fl_rule_hdl[i]);
+ }
+ else
+ {
+ IPACMERR("Failing adding v6 default IPV6 rule %d\n", i);
+ }
+ }
+ }
+ }
+
+
+fail:
+ free(m_pFilteringTable);
+
+ return res;
+}
+
+/* get ipa interface name */
+int IPACM_Iface::ipa_get_if_index
+(
+ char * if_name,
+ int * if_index
+)
+{
+ int fd;
+ struct ifreq ifr;
+
+ if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ IPACMERR("get interface index socket create failed \n");
+ return IPACM_FAILURE;
+ }
+
+ if(strlen(if_name) >= sizeof(ifr.ifr_name))
+ {
+ IPACMERR("interface name overflows: len %zu\n", strlen(if_name));
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+ IPACMDBG_H("interface name (%s)\n", if_name);
+
+ if(ioctl(fd,SIOCGIFINDEX , &ifr) < 0)
+ {
+ IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name);
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ *if_index = ifr.ifr_ifindex;
+ IPACMDBG_H("Interface index %d\n", *if_index);
+ close(fd);
+ return IPACM_SUCCESS;
+}
+
+void IPACM_Iface::config_ip_type(ipa_ip_type iptype)
+{
+ /* update the iface ip-type to be IPA_IP_v4, IPA_IP_v6 or both*/
+ if (iptype == IPA_IP_v4)
+ {
+ if ((ip_type == IPA_IP_v4) || (ip_type == IPA_IP_MAX))
+ {
+ IPACMDBG_H(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+ return;
+ }
+
+ if (ip_type == IPA_IP_v6)
+ {
+ ip_type = IPA_IP_MAX;
+ }
+ else
+ {
+ ip_type = IPA_IP_v4;
+ }
+ IPACMDBG_H(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+ }
+ else
+ {
+ if ((ip_type == IPA_IP_v6) || (ip_type == IPA_IP_MAX))
+ {
+ IPACMDBG_H(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+ return;
+ }
+
+ if (ip_type == IPA_IP_v4)
+ {
+ ip_type = IPA_IP_MAX;
+ }
+ else
+ {
+ ip_type = IPA_IP_v6;
+ }
+
+ IPACMDBG_H(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+ }
+
+ return;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_IfaceManager.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_IfaceManager.cpp
new file mode 100644
index 0000000..85033a3
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_IfaceManager.cpp
@@ -0,0 +1,579 @@
+/*
+Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_IfaceManager.cpp
+
+ @brief
+ This file implements the IPAM iface_manager functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <IPACM_IfaceManager.h>
+#include <IPACM_EvtDispatcher.h>
+#include <IPACM_Defs.h>
+#include <IPACM_Wlan.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Log.h>
+
+iface_instances *IPACM_IfaceManager::head = NULL;
+
+IPACM_IfaceManager::IPACM_IfaceManager()
+{
+ IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, this); // register for IPA_CFG_CHANGE event
+ IPACM_EvtDispatcher::registr(IPA_LINK_UP_EVENT, this);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_AP_LINK_UP_EVENT, this); // register for wlan AP-iface
+ IPACM_EvtDispatcher::registr(IPA_WLAN_STA_LINK_UP_EVENT, this); // register for wlan STA-iface
+#ifndef FEATURE_IPA_ANDROID
+ /* only MDM targets support device on bridge mode */
+ IPACM_EvtDispatcher::registr(IPA_BRIDGE_LINK_UP_EVENT, this); // register for IPA_BRIDGE_LINK_UP_EVENT event
+#endif /* not defined(FEATURE_IPA_ANDROID)*/
+ IPACM_EvtDispatcher::registr(IPA_USB_LINK_UP_EVENT, this); // register for USB-iface
+ IPACM_EvtDispatcher::registr(IPA_WAN_EMBMS_LINK_UP_EVENT, this); // register for wan eMBMS-iface
+ return;
+}
+
+void IPACM_IfaceManager::event_callback(ipa_cm_event_id event, void *param)
+{
+ int ipa_interface_index;
+ ipacm_event_data_fid *evt_data = (ipacm_event_data_fid *)param;
+ ipacm_event_data_mac *StaData = (ipacm_event_data_mac *)param;
+ ipacm_event_data_all *data_all = (ipacm_event_data_all *)param;
+ ipacm_ifacemgr_data ifmgr_data;
+
+ memset(&ifmgr_data,0,sizeof(ifmgr_data));
+
+ switch(event)
+ {
+ case IPA_CFG_CHANGE_EVENT:
+ IPACMDBG_H(" RESET IPACM_cfg \n");
+ IPACM_Iface::ipacmcfg->Init();
+ break;
+ case IPA_BRIDGE_LINK_UP_EVENT:
+ IPACMDBG_H(" Save the bridge0 mac info in IPACM_cfg \n");
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("IPA_BRIDGE_LINK_UP_EVENT: not supported iface id: %d\n", data_all->if_index);
+ break;
+ }
+ /* check if iface is bridge interface*/
+ if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
+ {
+ IPACM_Iface::ipacmcfg->ipa_bridge_enable = true;
+ memcpy(IPACM_Iface::ipacmcfg->bridge_mac,
+ data_all->mac_addr,
+ sizeof(IPACM_Iface::ipacmcfg->bridge_mac));
+ IPACMDBG_H("cached bridge0 MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ IPACM_Iface::ipacmcfg->bridge_mac[0], IPACM_Iface::ipacmcfg->bridge_mac[1], IPACM_Iface::ipacmcfg->bridge_mac[2],
+ IPACM_Iface::ipacmcfg->bridge_mac[3], IPACM_Iface::ipacmcfg->bridge_mac[4], IPACM_Iface::ipacmcfg->bridge_mac[5]);
+ }
+ break;
+ case IPA_LINK_UP_EVENT:
+ IPACMDBG_H("Recieved IPA_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("IPA_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+ break;
+ }
+ /* LTE-backhaul */
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == EMBMS_IF)
+ {
+ IPACMDBG("WAN-EMBMS (%s) link already up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+ }
+ else if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
+ {
+ IPACMDBG_H("WAN-LTE (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+ ifmgr_data.if_index = evt_data->if_index;
+ ifmgr_data.if_type = Q6_WAN;
+ create_iface_instance(&ifmgr_data);
+ }
+ break;
+
+ case IPA_USB_LINK_UP_EVENT:
+ IPACMDBG_H("Recieved IPA_USB_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("IPA_USB_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+ break;
+ }
+ /* check if it's WAN_IF */
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
+ {
+ /* usb-backhaul using sta_mode ECM_WAN*/
+ IPACMDBG_H("WAN-usb (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name, evt_data->if_index);
+ ifmgr_data.if_index = evt_data->if_index;
+ ifmgr_data.if_type = ECM_WAN;
+ create_iface_instance(&ifmgr_data);
+ }
+ else
+ {
+ ifmgr_data.if_index = evt_data->if_index;
+ ifmgr_data.if_type = Q6_WAN;
+ create_iface_instance(&ifmgr_data);
+ }
+ break;
+
+ case IPA_WLAN_AP_LINK_UP_EVENT:
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("IPA_WLAN_AP_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+ break;
+ }
+ /* change iface category from unknown to WLAN_IF */
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
+ {
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat = WLAN_IF;
+ IPACMDBG_H("WLAN AP (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+ ifmgr_data.if_index = evt_data->if_index;
+ ifmgr_data.if_type = Q6_WAN;
+ create_iface_instance(&ifmgr_data);
+ }
+ else
+ {
+ IPACMDBG_H("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+ }
+ break;
+
+ case IPA_WLAN_STA_LINK_UP_EVENT:
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(StaData->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("IPA_WLAN_STA_LINK_UP_EVENT: not supported iface id: %d\n", StaData->if_index);
+ break;
+ }
+ /* change iface category from unknown to WAN_IF */
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
+ {
+ /* wlan-backhaul using sta_mode WLAN_WAN */
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat = WAN_IF;
+ IPACMDBG_H("WLAN STA (%s) link up, iface: %d: \n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name, StaData->if_index);
+
+ ifmgr_data.if_index = StaData->if_index;
+ ifmgr_data.if_type = WLAN_WAN;
+ memcpy(ifmgr_data.mac_addr, StaData->mac_addr, sizeof(ifmgr_data.mac_addr));
+ create_iface_instance(&ifmgr_data);
+ }
+ else
+ {
+ IPACMDBG_H("iface %s already up and act as %d mode: \n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+ }
+ break;
+
+ /* Add new instance open for eMBMS iface and wan iface */
+ case IPA_WAN_EMBMS_LINK_UP_EVENT:
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("IPA_WAN_EMBMS_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
+ break;
+ }
+ /* change iface category from unknown to EMBMS_IF */
+ if ((IPACM_Iface::ipacmcfg->ipacm_odu_enable == true) && (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true))
+ {
+ IPACMDBG(" ODU-mode enable or not (%d) \n",IPACM_Iface::ipacmcfg->ipacm_odu_enable);
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
+ {
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat=EMBMS_IF;
+ IPACMDBG("WAN eMBMS (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
+ ifmgr_data.if_index = StaData->if_index;
+ ifmgr_data.if_type = Q6_WAN;
+ create_iface_instance(&ifmgr_data);
+ }
+ else
+ {
+ IPACMDBG("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return;
+}
+
+int IPACM_IfaceManager::create_iface_instance(ipacm_ifacemgr_data *param)
+{
+ int if_index = param->if_index;
+ ipacm_wan_iface_type is_sta_mode = param->if_type;
+
+ int ipa_interface_index;
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(if_index);
+
+ if(ipa_interface_index == INVALID_IFACE)
+ {
+ IPACMDBG_H("Unhandled interface received, fid: %d\n",if_index);
+ return IPACM_SUCCESS;
+ }
+
+ /* check if duplicate instance*/
+ if(SearchInstance(ipa_interface_index) == IPA_INSTANCE_NOT_FOUND)
+ {
+ /* IPA_INSTANCE_NOT_FOUND */
+ switch(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat)
+ {
+
+ case LAN_IF:
+ {
+ IPACMDBG_H("Creating Lan interface\n");
+ IPACM_Lan *lan = new IPACM_Lan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, lan);
+ //IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, lan);
+ //IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, lan);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, lan);
+#ifdef FEATURE_IPA_ANDROID
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_TETHER, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6_TETHER, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_TETHER, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6_TETHER, lan);
+#ifdef FEATURE_IPACM_HAL
+ IPACM_EvtDispatcher::registr(IPA_DOWNSTREAM_ADD, lan);
+ IPACM_EvtDispatcher::registr(IPA_DOWNSTREAM_DEL, lan);
+#endif
+#else
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, lan);
+#endif
+ IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, lan); // register for IPA_CFG_CHANGE event
+ IPACM_EvtDispatcher::registr(IPA_PRIVATE_SUBNET_CHANGE_EVENT, lan); // register for IPA_PRIVATE_SUBNET_CHANGE_EVENT event
+#ifdef FEATURE_IPA_ANDROID
+ IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, lan);
+#endif
+ IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, lan);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
+ /* IPA_LAN_DELETE_SELF should be always last */
+ IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, lan);
+ IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", lan->dev_name, lan->ipa_if_num);
+ registr(ipa_interface_index, lan);
+ /* solve the new_addr comes earlier issue */
+ IPACM_Iface::iface_addr_query(if_index);
+ }
+ break;
+
+ case ETH_IF:
+ {
+ IPACMDBG_H("Creating ETH interface in router mode\n");
+ IPACM_Lan *ETH = new IPACM_Lan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, ETH);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, ETH);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, ETH);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, ETH);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, ETH);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, ETH);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, ETH);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, ETH);
+ IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, ETH);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, ETH);
+ /* IPA_LAN_DELETE_SELF should be always last */
+ IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, ETH);
+ IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", ETH->dev_name, ETH->ipa_if_num);
+ registr(ipa_interface_index, ETH);
+ /* solve the new_addr comes earlier issue */
+ IPACM_Iface::iface_addr_query(if_index);
+ }
+ break;
+
+ case ODU_IF:
+ {
+ if(IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == true)
+ {
+ IPACMDBG_H("Creating ODU interface in router mode\n");
+ IPACM_Lan *odu = new IPACM_Lan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, odu);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, odu);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, odu);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, odu);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, odu);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, odu);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, odu);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, odu);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, odu);
+ IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, odu);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, odu);
+ /* IPA_LAN_DELETE_SELF should be always last */
+ IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
+ IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
+ registr(ipa_interface_index, odu);
+ /* solve the new_addr comes earlier issue */
+ IPACM_Iface::iface_addr_query(if_index);
+ }
+ else
+ {
+ IPACMDBG_H("Creating ODU interface in bridge mode\n");
+ IPACM_Lan *odu = new IPACM_Lan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, odu);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, odu);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, odu);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, odu);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, odu);
+ /* IPA_LAN_DELETE_SELF should be always last */
+ IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, odu);
+ IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", odu->dev_name, odu->ipa_if_num);
+ registr(ipa_interface_index, odu);
+ /* solve the new_addr comes earlier issue */
+ IPACM_Iface::iface_addr_query(if_index);
+ }
+ }
+ break;
+
+ case WLAN_IF:
+ {
+ IPACMDBG_H("Creating WLan interface\n");
+ IPACM_Wlan *wl = new IPACM_Wlan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT_EX, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_DEL_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_POWER_SAVE_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_RECOVER_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, wl);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, wl);
+#ifdef FEATURE_IPA_ANDROID
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_TETHER, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6_TETHER, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_TETHER, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6_TETHER, wl);
+#ifdef FEATURE_IPACM_HAL
+ IPACM_EvtDispatcher::registr(IPA_DOWNSTREAM_ADD, wl);
+ IPACM_EvtDispatcher::registr(IPA_DOWNSTREAM_DEL, wl);
+ IPACM_EvtDispatcher::registr(IPA_SSR_NOTICE, wl);
+#endif
+#else
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP_V6, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN_V6, wl);
+#endif
+ IPACM_EvtDispatcher::registr(IPA_PRIVATE_SUBNET_CHANGE_EVENT, wl); // register for IPA_PRIVATE_SUBNET_CHANGE_EVENT event
+#ifdef FEATURE_ETH_BRIDGE_LE
+ IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, wl);
+#endif
+ IPACM_EvtDispatcher::registr(IPA_CRADLE_WAN_MODE_SWITCH, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_LINK_DOWN_EVENT, wl);
+#ifndef FEATURE_IPA_ANDROID
+ IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, wl);
+#else
+ IPACM_EvtDispatcher::registr(IPA_TETHERING_STATS_UPDATE_EVENT, wl);
+#endif
+ /* IPA_LAN_DELETE_SELF should be always last */
+ IPACM_EvtDispatcher::registr(IPA_LAN_DELETE_SELF, wl);
+ IPACMDBG_H("ipa_WLAN (%s):ipa_index (%d) instance open/registr ok\n", wl->dev_name, wl->ipa_if_num);
+ registr(ipa_interface_index, wl);
+ /* solve the new_addr comes earlier issue */
+ IPACM_Iface::iface_addr_query(if_index);
+ }
+ break;
+
+ case WAN_IF:
+ {
+ if((IPACM_Iface::ipacmcfg->ipacm_odu_enable == false) || (IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == true))
+ {
+ IPACMDBG_H("Creating Wan interface\n");
+ IPACM_Wan *w;
+ if(is_sta_mode == WLAN_WAN)
+ {
+ w = new IPACM_Wan(ipa_interface_index, is_sta_mode, param->mac_addr);
+ }
+ else
+ {
+ w = new IPACM_Wan(ipa_interface_index, is_sta_mode, NULL);
+ }
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, w);
+#ifdef FEATURE_IPA_ANDROID
+ IPACM_EvtDispatcher::registr(IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, w);
+ if(is_sta_mode == Q6_WAN)
+ {
+ IPACM_EvtDispatcher::registr(IPA_NETWORK_STATS_UPDATE_EVENT, w);
+ };
+#else/* defined(FEATURE_IPA_ANDROID) */
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, w);
+#endif /* not defined(FEATURE_IPA_ANDROID)*/
+ IPACM_EvtDispatcher::registr(IPA_FIREWALL_CHANGE_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, w);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, w);
+ IPACM_EvtDispatcher::registr(IPA_CFG_CHANGE_EVENT, w); // register for IPA_CFG_CHANGE event
+ IPACM_EvtDispatcher::registr(IPA_WAN_XLAT_CONNECT_EVENT, w);
+ if(is_sta_mode == WLAN_WAN)
+ {
+ IPACM_EvtDispatcher::registr(IPA_WLAN_LINK_DOWN_EVENT, w); // for STA mode
+#ifndef FEATURE_IPA_ANDROID
+ IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_SCC, w);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_SWITCH_TO_MCC, w);
+#ifdef FEATURE_IPACM_HAL
+ IPACM_EvtDispatcher::registr(IPA_SSR_NOTICE, w);
+#endif
+#endif
+ }
+ else
+ {
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, w);
+ }
+
+ IPACMDBG_H("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", w->dev_name, w->ipa_if_num);
+ registr(ipa_interface_index, w);
+ /* solve the new_addr comes earlier issue */
+ IPACM_Iface::iface_addr_query(if_index);
+ }
+ }
+ break;
+
+ /* WAN-eMBMS instance */
+ case EMBMS_IF:
+ {
+ IPACMDBG("Creating Wan-eMBSM interface\n");
+ IPACM_Wan *embms = new IPACM_Wan(ipa_interface_index, is_sta_mode, NULL);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, embms);
+ IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", embms->dev_name, embms->ipa_if_num);
+ registr(ipa_interface_index, embms);
+ }
+ break;
+
+ default:
+ IPACMDBG_H("Unhandled interface category received iface name: %s, category: %d\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
+ return IPACM_SUCCESS;
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+
+int IPACM_IfaceManager::registr(int ipa_if_index, IPACM_Listener *obj)
+{
+ iface_instances *tmp = head,*nw;
+
+ nw = (iface_instances *)malloc(sizeof(iface_instances));
+ if(nw != NULL)
+ {
+ nw->ipa_if_index = ipa_if_index;
+ nw->obj = obj;
+ nw->next = NULL;
+ }
+ else
+ {
+ return IPACM_FAILURE;
+ }
+
+ if(head == NULL)
+ {
+ head = nw;
+ }
+ else
+ {
+ while(tmp->next)
+ {
+ tmp = tmp->next;
+ }
+ tmp->next = nw;
+ }
+ return IPACM_SUCCESS;
+}
+
+int IPACM_IfaceManager::deregistr(IPACM_Listener *param)
+{
+ iface_instances *tmp = head,*tmp1,*prev = head;
+
+ while(tmp != NULL)
+ {
+ if(tmp->obj == param)
+ {
+ tmp1 = tmp;
+ if(tmp == head)
+ {
+ head = head->next;
+ }
+ else if(tmp->next == NULL)
+ {
+ prev->next = NULL;
+ }
+ else
+ {
+ prev->next = tmp->next;
+ }
+
+ tmp = tmp->next;
+ free(tmp1);
+ }
+ else
+ {
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+
+int IPACM_IfaceManager::SearchInstance(int ipa_if_index)
+{
+
+ iface_instances *tmp = head;
+
+ while(tmp != NULL)
+ {
+ if(ipa_if_index == tmp->ipa_if_index)
+ {
+ IPACMDBG_H("Find existed iface-instance name: %s\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+ return IPA_INSTANCE_FOUND;
+ }
+ tmp = tmp->next;
+ }
+
+ IPACMDBG_H("No existed iface-instance name: %s,\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+
+ return IPA_INSTANCE_NOT_FOUND;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Lan.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Lan.cpp
new file mode 100644
index 0000000..7503df1
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Lan.cpp
@@ -0,0 +1,5568 @@
+/*
+Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials provided
+with the distribution.
+
+* Neither the name of The Linux Foundation nor the names of its
+contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Lan.cpp
+
+ @brief
+ This file implements the LAN iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "IPACM_Netlink.h"
+#include "IPACM_Lan.h"
+#include "IPACM_Wan.h"
+#include "IPACM_IfaceManager.h"
+#include "linux/rmnet_ipa_fd_ioctl.h"
+#include "linux/ipa_qmi_service_v01.h"
+#include "linux/msm_ipa.h"
+#include "IPACM_ConntrackListener.h"
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#ifdef FEATURE_IPACM_HAL
+#include "IPACM_OffloadManager.h"
+#endif
+bool IPACM_Lan::odu_up = false;
+
+IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index)
+{
+ num_eth_client = 0;
+ header_name_count = 0;
+ ipv6_set = 0;
+ ipv4_header_set = false;
+ ipv6_header_set = false;
+ odu_route_rule_v4_hdl = NULL;
+ odu_route_rule_v6_hdl = NULL;
+ eth_client = NULL;
+ int m_fd_odu, ret = IPACM_SUCCESS;
+ uint32_t i;
+
+ Nat_App = NatApp::GetInstance();
+ if (Nat_App == NULL)
+ {
+ IPACMERR("unable to get Nat App instance \n");
+ return;
+ }
+
+ num_wan_ul_fl_rule_v4 = 0;
+ num_wan_ul_fl_rule_v6 = 0;
+ is_active = true;
+ modem_ul_v4_set = false;
+ v4_mux_id = 0;
+ modem_ul_v6_set = false;
+ v6_mux_id = 0;
+
+ sta_ul_v4_set = false;
+ sta_ul_v6_set = false;
+
+ is_mode_switch = false;
+ if_ipv4_subnet =0;
+ each_client_rt_rule_count[IPA_IP_v4] = 0;
+ each_client_rt_rule_count[IPA_IP_v6] = 0;
+ eth_client_len = 0;
+
+ /* support eth multiple clients */
+ if(iface_query != NULL)
+ {
+ if(ipa_if_cate != WLAN_IF)
+ {
+ eth_client_len = (sizeof(ipa_eth_client)) + (iface_query->num_tx_props * sizeof(eth_client_rt_hdl));
+ eth_client = (ipa_eth_client *)calloc(IPA_MAX_NUM_ETH_CLIENTS, eth_client_len);
+ if (eth_client == NULL)
+ {
+ IPACMERR("unable to allocate memory\n");
+ return;
+ }
+ }
+
+ IPACMDBG_H(" IPACM->IPACM_Lan(%d) constructor: Tx:%d Rx:%d \n", ipa_if_num,
+ iface_query->num_tx_props, iface_query->num_rx_props);
+
+ /* ODU routing table initilization */
+ if(ipa_if_cate == ODU_IF)
+ {
+ odu_route_rule_v4_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+ odu_route_rule_v6_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+ if ((odu_route_rule_v4_hdl == NULL) || (odu_route_rule_v6_hdl == NULL))
+ {
+ IPACMERR("unable to allocate memory\n");
+ return;
+ }
+ }
+ }
+
+ memset(wan_ul_fl_rule_hdl_v4, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
+ memset(wan_ul_fl_rule_hdl_v6, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
+
+ memset(ipv4_icmp_flt_rule_hdl, 0, NUM_IPV4_ICMP_FLT_RULE * sizeof(uint32_t));
+
+ memset(private_fl_rule_hdl, 0, IPA_MAX_PRIVATE_SUBNET_ENTRIES * sizeof(uint32_t));
+ memset(ipv6_prefix_flt_rule_hdl, 0, NUM_IPV6_PREFIX_FLT_RULE * sizeof(uint32_t));
+ memset(ipv6_icmp_flt_rule_hdl, 0, NUM_IPV6_ICMP_FLT_RULE * sizeof(uint32_t));
+ memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
+
+ /* ODU routing table initilization */
+ if(ipa_if_cate == ODU_IF)
+ {
+ /* only do one time ioctl to odu-driver to infrom in router or bridge mode*/
+ if (IPACM_Lan::odu_up != true)
+ {
+ m_fd_odu = open(IPACM_Iface::ipacmcfg->DEVICE_NAME_ODU, O_RDWR);
+ if (0 == m_fd_odu)
+ {
+ IPACMERR("Failed opening %s.\n", IPACM_Iface::ipacmcfg->DEVICE_NAME_ODU);
+ return ;
+ }
+
+ if(IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == true)
+ {
+ ret = ioctl(m_fd_odu, ODU_BRIDGE_IOC_SET_MODE, ODU_BRIDGE_MODE_ROUTER);
+ IPACM_Iface::ipacmcfg->ipacm_odu_enable = true;
+ }
+ else
+ {
+ ret = ioctl(m_fd_odu, ODU_BRIDGE_IOC_SET_MODE, ODU_BRIDGE_MODE_BRIDGE);
+ IPACM_Iface::ipacmcfg->ipacm_odu_enable = true;
+ }
+
+ if (ret)
+ {
+ IPACMERR("Failed tell odu-driver the mode\n");
+ }
+ IPACMDBG("Tell odu-driver in router-mode(%d)\n", IPACM_Iface::ipacmcfg->ipacm_odu_router_mode);
+ IPACMDBG_H("odu is up: odu-driver in router-mode(%d) \n", IPACM_Iface::ipacmcfg->ipacm_odu_router_mode);
+ close(m_fd_odu);
+ IPACM_Lan::odu_up = true;
+ }
+ }
+
+ if(iface_query != NULL && tx_prop != NULL)
+ {
+ for(i=0; i<iface_query->num_tx_props; i++)
+ each_client_rt_rule_count[tx_prop->tx[i].ip]++;
+ }
+ IPACMDBG_H("Need to add %d IPv4 and %d IPv6 routing rules for eth bridge for each client.\n", each_client_rt_rule_count[IPA_IP_v4], each_client_rt_rule_count[IPA_IP_v6]);
+
+#ifdef FEATURE_IPA_ANDROID
+ /* set the IPA-client pipe enum */
+ if(ipa_if_cate == LAN_IF)
+ {
+#ifdef FEATURE_IPACM_HAL
+ handle_tethering_client(false, IPACM_CLIENT_MAX);
+#else
+ handle_tethering_client(false, IPACM_CLIENT_USB);
+#endif
+ }
+#endif
+
+ memset(is_downstream_set, 0, sizeof(is_downstream_set));
+ memset(is_upstream_set, 0, sizeof(is_upstream_set));
+ memset(&prefix, 0, sizeof(prefix));
+
+#ifdef FEATURE_IPACM_HAL
+ /* check if Upstream was set before */
+ if (IPACM_Wan::isWanUP(ipa_if_num))
+ {
+ IPACMDBG_H("Upstream was set previously for ipv4, change is_upstream_set flag\n");
+ is_upstream_set[IPA_IP_v4] = true;
+ }
+
+ if (IPACM_Wan::isWanUP_V6(ipa_if_num))
+ {
+ IPACMDBG_H("Upstream was set previously for ipv6, change is_upstream_set flag\n");
+ is_upstream_set[IPA_IP_v6] = true;
+ }
+#endif
+ return;
+}
+
+IPACM_Lan::~IPACM_Lan()
+{
+ IPACM_EvtDispatcher::deregistr(this);
+ IPACM_IfaceManager::deregistr(this);
+ return;
+}
+
+
+/* LAN-iface's callback function */
+void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param)
+{
+ if(is_active == false && event != IPA_LAN_DELETE_SELF)
+ {
+ IPACMDBG_H("The interface is no longer active, return.\n");
+ return;
+ }
+
+ int ipa_interface_index;
+ ipacm_ext_prop* ext_prop;
+ ipacm_event_iface_up_tehter* data_wan_tether;
+
+ 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_H("Received IPA_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ return;
+ }
+ }
+ break;
+
+ case IPA_CFG_CHANGE_EVENT:
+ {
+ if ( IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat != ipa_if_cate)
+ {
+ IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT and category changed\n");
+ /* delete previous instance */
+ handle_down_evt();
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ is_mode_switch = true; // need post internal usb-link up event
+ return;
+ }
+ /* Add Natting iface to IPACM_Config if there is Rx/Tx property */
+ if (rx_prop != NULL || tx_prop != NULL)
+ {
+ IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
+ IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
+ }
+ }
+ break;
+
+ case IPA_PRIVATE_SUBNET_CHANGE_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ /* internel event: data->if_index is ipa_if_index */
+ if (data->if_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from itself posting, ignore\n");
+ return;
+ }
+ else
+ {
+ IPACMDBG_H("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from other LAN iface \n");
+#ifdef FEATURE_IPA_ANDROID
+ handle_private_subnet_android(IPA_IP_v4);
+#endif
+ IPACMDBG_H(" delete old private subnet rules, use new sets \n");
+ return;
+ }
+ }
+ break;
+
+ case IPA_LAN_DELETE_SELF:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ if(data->if_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_LAN_DELETE_SELF event.\n");
+ IPACMDBG_H("ipa_LAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ /* posting link-up event for cradle use-case */
+ if(is_mode_switch)
+ {
+ IPACMDBG_H("Posting IPA_USB_LINK_UP_EVENT event for (%s)\n", dev_name);
+ ipacm_cmd_q_data evt_data;
+ memset(&evt_data, 0, sizeof(evt_data));
+
+ ipacm_event_data_fid *data_fid = NULL;
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for IPA_USB_LINK_UP_EVENT data_fid\n");
+ return;
+ }
+ if(IPACM_Iface::ipa_get_if_index(dev_name, &(data_fid->if_index)))
+ {
+ IPACMERR("Error while getting interface index for %s device", dev_name);
+ }
+ evt_data.event = IPA_USB_LINK_UP_EVENT;
+ evt_data.evt_data = data_fid;
+ //IPACMDBG_H("Posting event:%d\n", evt_data.event);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+#ifndef FEATURE_IPA_ANDROID
+ if(rx_prop != NULL)
+ {
+ if(IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4) != 0)
+ {
+ IPACMDBG_DMESG("### WARNING ### num ipv4 flt rules on client %d is not expected: %d expected value: 0",
+ rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4));
+ }
+ if(IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6) != 0)
+ {
+ IPACMDBG_DMESG("### WARNING ### num ipv6 flt rules on client %d is not expected: %d expected value: 0",
+ rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6));
+ }
+ }
+#endif
+ delete this;
+ }
+ break;
+ }
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ if ( (data->iptype == IPA_IP_v4 && data->ipv4_addr == 0) ||
+ (data->iptype == IPA_IP_v6 &&
+ data->ipv6_addr[0] == 0 && data->ipv6_addr[1] == 0 &&
+ data->ipv6_addr[2] == 0 && data->ipv6_addr[3] == 0) )
+ {
+ IPACMDBG_H("Invalid address, ignore IPA_ADDR_ADD_EVENT event\n");
+ return;
+ }
+#ifdef FEATURE_L2TP
+ if(data->iptype == IPA_IP_v6 && is_vlan_event(data->iface_name) && is_unique_local_ipv6_addr(data->ipv6_addr))
+ {
+ IPACMDBG_H("Got IPv6 new addr event for a vlan iface %s.\n", data->iface_name);
+ eth_bridge_post_event(IPA_HANDLE_VLAN_IFACE_INFO, data->iptype, NULL,
+ data->ipv6_addr, data->iface_name);
+ }
+#endif
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_ADDR_ADD_EVENT\n");
+
+ /* only call ioctl for ODU iface with bridge mode */
+ if(IPACM_Iface::ipacmcfg->ipacm_odu_enable == true && IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == false
+ && ipa_if_cate == ODU_IF)
+ {
+ if((data->iptype == IPA_IP_v6) && (num_dft_rt_v6 == 0))
+ {
+ handle_addr_evt_odu_bridge(data);
+ }
+#ifdef FEATURE_IPA_ANDROID
+ add_dummy_private_subnet_flt_rule(data->iptype);
+ handle_private_subnet_android(data->iptype);
+#else
+ handle_private_subnet(data->iptype);
+#endif
+ }
+ else
+ {
+
+ /* check v4 not setup before, v6 can have 2 iface ip */
+ if( ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX))
+ || ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
+ {
+ IPACMDBG_H("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
+ if(handle_addr_evt(data) == IPACM_FAILURE)
+ {
+ return;
+ }
+
+#ifdef FEATURE_IPA_ANDROID
+ add_dummy_private_subnet_flt_rule(data->iptype);
+ handle_private_subnet_android(data->iptype);
+#else
+ handle_private_subnet(data->iptype);
+#endif
+
+#ifndef FEATURE_IPACM_HAL
+ if (IPACM_Wan::isWanUP(ipa_if_num))
+ {
+ if(data->iptype == IPA_IP_v4 || data->iptype == IPA_IP_MAX)
+ {
+ if(IPACM_Wan::backhaul_is_sta_mode == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+ handle_wan_up_ex(ext_prop, IPA_IP_v4,
+ IPACM_Wan::getXlat_Mux_Id());
+ }
+ else
+ {
+ handle_wan_up(IPA_IP_v4);
+ }
+ }
+ IPACMDBG_H("Finished checking wan_up\n");
+ } else {
+ IPACMDBG_H("Wan_V4 haven't up yet\n");
+ }
+
+ if(IPACM_Wan::isWanUP_V6(ipa_if_num))
+ {
+ if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
+ {
+ memcpy(ipv6_prefix, IPACM_Wan::backhaul_ipv6_prefix, sizeof(ipv6_prefix));
+ install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
+ if(IPACM_Wan::backhaul_is_sta_mode == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+ handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+ }
+ else
+ {
+ handle_wan_up(IPA_IP_v6);
+ }
+ }
+ IPACMDBG_H("Finished checking wan_up_v6\n");
+ } else {
+ IPACMDBG_H("Wan_V6 haven't up yet\n");
+ }
+#endif
+ /* 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_H("posting IPA_HANDLE_LAN_UP for IPv4 with below information\n");
+ IPACMDBG_H("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+ info->ipv4_addr, info->addr_mask);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ IPACMDBG_H("Finish handling IPA_ADDR_ADD_EVENT for ip-family(%d)\n", data->iptype);
+ }
+
+ IPACMDBG_H("Finish handling IPA_ADDR_ADD_EVENT for ip-family(%d)\n", data->iptype);
+ /* checking if SW-RT_enable */
+ if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true)
+ {
+ /* handle software routing enable event*/
+ IPACMDBG_H("IPA_SW_ROUTING_ENABLE for iface: %s \n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+ handle_software_routing_enable();
+ }
+
+ }
+ }
+ }
+ break;
+#ifdef FEATURE_IPA_ANDROID
+ case IPA_HANDLE_WAN_UP_TETHER:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP_TETHER event\n");
+
+ data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+ if(data_wan_tether == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+ data_wan_tether->if_index_tether,
+ IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+#ifndef FEATURE_IPACM_HAL
+ if (data_wan_tether->if_index_tether != ipa_if_num)
+ {
+ IPACMERR("IPA_HANDLE_WAN_UP_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num);
+ return;
+ }
+#endif
+ if (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+#ifdef FEATURE_IPACM_HAL
+ if (is_upstream_set[IPA_IP_v4] == false)
+ {
+ IPACMDBG_H("Add upstream for IPv4.\n");
+ is_upstream_set[IPA_IP_v4] = true;
+ if (is_downstream_set[IPA_IP_v4] == true)
+ {
+ IPACMDBG_H("Downstream was set before, adding UL rules.\n");
+ if (data_wan_tether->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+ handle_wan_up_ex(ext_prop, IPA_IP_v4, 0);
+ } else {
+ handle_wan_up(IPA_IP_v4);
+ }
+ }
+ }
+#else
+ if (data_wan_tether->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+ handle_wan_up_ex(ext_prop, IPA_IP_v4, 0);
+ } else {
+ handle_wan_up(IPA_IP_v4);
+ }
+#endif
+ }
+ break;
+
+ case IPA_HANDLE_WAN_UP_V6_TETHER:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6_TETHER event\n");
+
+ data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+ if (data_wan_tether == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+ data_wan_tether->if_index_tether,
+ IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+#ifndef FEATURE_IPACM_HAL
+ if (data_wan_tether->if_index_tether != ipa_if_num)
+ {
+ IPACMERR("IPA_HANDLE_WAN_UP_V6_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num);
+ return;
+ }
+#endif
+ if (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+#ifdef FEATURE_IPACM_HAL
+ if (is_upstream_set[IPA_IP_v6] == false)
+ {
+ IPACMDBG_H("Add upstream for IPv6.\n");
+ is_upstream_set[IPA_IP_v6] = true;
+
+ if (is_downstream_set[IPA_IP_v6] == true)
+ {
+ IPACMDBG_H("Downstream was set before, adding UL rules.\n");
+ memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix));
+ install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix);
+ if (data_wan_tether->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+ handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+ }
+ else
+ {
+ handle_wan_up(IPA_IP_v6);
+ }
+ }
+ }
+#else
+ if (data_wan_tether->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+ handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+ } else {
+ handle_wan_up(IPA_IP_v6);
+ }
+#endif
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN_TETHER:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_TETHER event\n");
+ data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+ if (data_wan_tether == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+ data_wan_tether->if_index_tether,
+ IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+#ifndef FEATURE_IPACM_HAL
+ if (data_wan_tether->if_index_tether != ipa_if_num)
+ {
+ IPACMERR("IPA_HANDLE_WAN_DOWN_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num);
+ return;
+ }
+#endif
+ if (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+#ifdef FEATURE_IPACM_HAL
+ if(is_upstream_set[IPA_IP_v4] == true)
+ {
+ IPACMDBG_H("Del upstream for IPv4.\n");
+ is_upstream_set[IPA_IP_v4] = false;
+ if(is_downstream_set[IPA_IP_v4] == true)
+ {
+ IPACMDBG_H("Downstream was set before, deleting UL rules.\n");
+ handle_wan_down(data_wan_tether->is_sta);
+ }
+ }
+#else
+ handle_wan_down(data_wan_tether->is_sta);
+#endif
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN_V6_TETHER:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6_TETHER event\n");
+ data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+ if(data_wan_tether == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+ data_wan_tether->if_index_tether,
+ IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+#ifndef FEATURE_IPACM_HAL
+ if (data_wan_tether->if_index_tether != ipa_if_num)
+ {
+ IPACMERR("IPA_HANDLE_WAN_DOWN_V6_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num);
+ return;
+ }
+#endif
+ if (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+#ifdef FEATURE_IPACM_HAL
+ if (is_upstream_set[IPA_IP_v6] == true)
+ {
+ IPACMDBG_H("Del upstream for IPv6.\n");
+ is_upstream_set[IPA_IP_v6] = false;
+ if(is_downstream_set[IPA_IP_v6] == true)
+ {
+ IPACMDBG_H("Downstream was set before, deleting UL rules.\n");
+ /* reset usb-client ipv6 rt-rules */
+ handle_lan_client_reset_rt(IPA_IP_v6);
+ handle_wan_down_v6(data_wan_tether->is_sta);
+ }
+ }
+#else
+ /* reset usb-client ipv6 rt-rules */
+ handle_lan_client_reset_rt(IPA_IP_v6);
+ handle_wan_down_v6(data_wan_tether->is_sta);
+#endif
+ }
+ break;
+
+ case IPA_DOWNSTREAM_ADD:
+ {
+ ipacm_event_ipahal_stream *data = (ipacm_event_ipahal_stream *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_DOWNSTREAM_ADD event.\n");
+ if (is_downstream_set[data->prefix.iptype] == false)
+ {
+ IPACMDBG_H("Add downstream for IP iptype %d\n", data->prefix.iptype);
+ is_downstream_set[data->prefix.iptype] = true;
+ memcpy(&prefix[data->prefix.iptype], &data->prefix,
+ sizeof(prefix[data->prefix.iptype]));
+
+ if (is_upstream_set[data->prefix.iptype] == true)
+ {
+ IPACMDBG_H("Upstream was set before, adding UL rules.\n");
+ if (ip_type == IPA_IP_MAX || ip_type == data->prefix.iptype)
+ {
+ if (data->prefix.iptype == IPA_IP_v6) /* ipv6 only */
+ {
+ /* Only offload clients has same prefix as Andorid gave */
+ ipv6_prefix[0] = data->prefix.v6Addr[0];
+ ipv6_prefix[1] = data->prefix.v6Addr[1];
+ IPACMDBG_H("ipv6_prefix0x%x:%x\n", ipv6_prefix[0], ipv6_prefix[1]);
+ install_ipv6_prefix_flt_rule(ipv6_prefix);
+ }
+
+ if (IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(data->prefix.iptype);
+ handle_wan_up_ex(ext_prop, data->prefix.iptype, 0);
+ } else {
+ handle_wan_up(data->prefix.iptype); /* STA */
+ }
+ }
+ }
+ } else {
+ IPACMDBG_H("downstream for IP iptype %d already set \n", data->prefix.iptype);
+ }
+ }
+ break;
+ }
+
+ case IPA_DOWNSTREAM_DEL:
+ {
+ ipacm_event_ipahal_stream *data = (ipacm_event_ipahal_stream *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_DOWNSTREAM_DEL event.\n");
+ if (is_downstream_set[data->prefix.iptype] == true)
+ {
+ IPACMDBG_H("Del downstream for IP iptype %d.\n", data->prefix.iptype);
+ is_downstream_set[data->prefix.iptype] = false;
+
+ if (is_upstream_set[data->prefix.iptype] == true)
+ {
+ IPACMDBG_H("Upstream was set before, deleting UL rules.\n");
+ if (data->prefix.iptype == IPA_IP_v4)
+ {
+ handle_wan_down(IPACM_Wan::backhaul_is_sta_mode); /* LTE STA */
+ } else {
+ handle_lan_client_reset_rt(IPA_IP_v6);
+ handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode); /* LTE STA */
+ }
+ }
+ }
+ }
+ break;
+ }
+
+#else
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n");
+
+ ipacm_event_iface_up* data_wan = (ipacm_event_iface_up*)param;
+ if (data_wan == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+ if (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+ if (data_wan->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+ handle_wan_up_ex(ext_prop, IPA_IP_v4, data_wan->xlat_mux_id);
+ }
+ else
+ {
+ handle_wan_up(IPA_IP_v4);
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_UP_V6:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6 event\n");
+
+ data_wan = (ipacm_event_iface_up*)param;
+ if (data_wan == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+ if (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+ memcpy(ipv6_prefix, data_wan->ipv6_prefix, sizeof(ipv6_prefix));
+ install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
+ if (data_wan->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+ handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+ }
+ else
+ {
+ handle_wan_up(IPA_IP_v6);
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN event\n");
+ data_wan = (ipacm_event_iface_up*)param;
+ if (data_wan == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+ if (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+ handle_wan_down(data_wan->is_sta);
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN_V6:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6 event\n");
+ data_wan = (ipacm_event_iface_up*)param;
+ if (data_wan == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ /* clean up v6 RT rules*/
+ IPACMDBG_H("Received IPA_WAN_V6_DOWN in LAN-instance and need clean up client IPv6 address \n");
+ /* reset usb-client ipv6 rt-rules */
+ handle_lan_client_reset_rt(IPA_IP_v6);
+
+ IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+ if (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+ handle_wan_down_v6(data_wan->is_sta);
+ }
+ break;
+#endif
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ IPACMDBG_H("Recieved IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT event \n");
+ IPACMDBG_H("check iface %s category: %d\n", dev_name, ipa_if_cate);
+
+ if (ipa_interface_index == ipa_if_num && ipa_if_cate == ODU_IF)
+ {
+ IPACMDBG_H("ODU iface got v4-ip \n");
+ /* first construc ODU full header */
+ if ((ipv4_header_set == false) && (ipv6_header_set == false))
+ {
+ /* construct ODU RT tbl */
+ handle_odu_hdr_init(data->mac_addr);
+ if (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true)
+ {
+ handle_odu_route_add();
+ IPACMDBG_H("construct ODU header and route rules, embms_flag (%d) \n", IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable);
+ }
+ else
+ {
+ IPACMDBG_H("construct ODU header only, embms_flag (%d) \n", IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable);
+ }
+ }
+ /* if ODU in bridge mode, directly return */
+ if(IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == false)
+ {
+ IPACMDBG_H("ODU is in bridge mode, no action \n");
+ return;
+ }
+ }
+
+ if (ipa_interface_index == ipa_if_num
+#ifdef FEATURE_L2TP
+ || is_vlan_event(data->iface_name) ||
+ || (is_l2tp_event(data->iface_name) && ipa_if_cate == ODU_IF)
+#endif
+ )
+ {
+ IPACMDBG_H("ETH iface got client \n");
+ if(ipa_interface_index == ipa_if_num)
+ {
+ /* first construc ETH full header */
+ handle_eth_hdr_init(data->mac_addr);
+ IPACMDBG_H("construct ETH header and route rules \n");
+ /* Associate with IP and construct RT-rule */
+ if (handle_eth_client_ipaddr(data) == IPACM_FAILURE)
+ {
+ return;
+ }
+ handle_eth_client_route_rule(data->mac_addr, data->iptype);
+ if (data->iptype == IPA_IP_v4)
+ {
+ /* Add NAT rules after ipv4 RT rules are set */
+ CtList->HandleNeighIpAddrAddEvt(data);
+ }
+ eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_ADD, IPA_IP_MAX, data->mac_addr, NULL, data->iface_name);
+ }
+#ifdef FEATURE_L2TP
+ else if(is_l2tp_event(data->iface_name) && ipa_if_cate == ODU_IF)
+ {
+ if(tx_prop != NULL)
+ {
+ IPACMDBG_H("add rm dependency for L2TP interface.\n");
+ IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+ }
+ eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_ADD, IPA_IP_MAX, data->mac_addr, NULL, data->iface_name);
+ }
+ else
+ {
+ if(data->iptype == IPA_IP_v6 && is_unique_local_ipv6_addr(data->ipv6_addr))
+ {
+ eth_bridge_post_event(IPA_HANDLE_VLAN_CLIENT_INFO, IPA_IP_MAX, data->mac_addr, data->ipv6_addr, data->iface_name);
+ }
+ }
+#endif
+ return;
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ IPACMDBG_H("Received IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT event. \n");
+ IPACMDBG_H("check iface %s category: %d\n", dev_name, ipa_if_cate);
+ /* if ODU in bridge mode, directly return */
+ if (ipa_if_cate == ODU_IF && IPACM_Iface::ipacmcfg->ipacm_odu_router_mode == false)
+ {
+ IPACMDBG_H("ODU is in bridge mode, no action \n");
+ return;
+ }
+
+ if (ipa_interface_index == ipa_if_num
+#ifdef FEATURE_L2TP
+ || (is_l2tp_event(data->iface_name) && ipa_if_cate == ODU_IF)
+#endif
+ )
+ {
+ if(ipa_interface_index == ipa_if_num)
+ {
+ if (data->iptype == IPA_IP_v6)
+ {
+ handle_del_ipv6_addr(data);
+ return;
+ }
+ IPACMDBG_H("LAN iface delete client \n");
+ handle_eth_client_down_evt(data->mac_addr);
+ }
+ else
+ {
+ eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_DEL, IPA_IP_MAX, data->mac_addr, NULL, data->iface_name);
+ }
+ return;
+ }
+ }
+ break;
+
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG_H("Received IPA_SW_ROUTING_ENABLE\n");
+ /* handle software routing enable event*/
+ handle_software_routing_enable();
+ break;
+
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG_H("Received IPA_SW_ROUTING_DISABLE\n");
+ /* handle software routing disable event*/
+ handle_software_routing_disable();
+ break;
+
+ case IPA_CRADLE_WAN_MODE_SWITCH:
+ {
+ IPACMDBG_H("Received IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+ ipacm_event_cradle_wan_mode* wan_mode = (ipacm_event_cradle_wan_mode*)param;
+ if(wan_mode == NULL)
+ {
+ IPACMERR("Event data is empty.\n");
+ return;
+ }
+
+ if(wan_mode->cradle_wan_mode == BRIDGE)
+ {
+ handle_cradle_wan_mode_switch(true);
+ }
+ else
+ {
+ handle_cradle_wan_mode_switch(false);
+ }
+ }
+ break;
+
+ case IPA_TETHERING_STATS_UPDATE_EVENT:
+ {
+ IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_EVENT event.\n");
+ if (IPACM_Wan::isWanUP(ipa_if_num) || IPACM_Wan::isWanUP_V6(ipa_if_num))
+ {
+ if(IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
+ {
+ ipa_get_data_stats_resp_msg_v01 *data = (ipa_get_data_stats_resp_msg_v01 *)param;
+ IPACMDBG("Received IPA_TETHERING_STATS_UPDATE_STATS ipa_stats_type: %d\n",data->ipa_stats_type);
+ IPACMDBG("Received %d UL, %d DL pipe stats\n",data->ul_src_pipe_stats_list_len,
+ data->dl_dst_pipe_stats_list_len);
+ if (data->ipa_stats_type != QMI_IPA_STATS_TYPE_PIPE_V01)
+ {
+ IPACMERR("not valid pipe stats enum(%d)\n", data->ipa_stats_type);
+ return;
+ }
+ handle_tethering_stats_event(data);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+int IPACM_Lan::handle_del_ipv6_addr(ipacm_event_data_all *data)
+{
+ uint32_t tx_index;
+ uint32_t rt_hdl;
+ int num_v6 =0, clnt_indx;
+
+ clnt_indx = get_eth_client_index(data->mac_addr);
+ if (clnt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMERR("eth client not found/attached \n");
+ return IPACM_FAILURE;
+ }
+
+ if(data->iptype == IPA_IP_v6)
+ {
+ if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+ (data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] != 0))
+ {
+ IPACMDBG_H("ipv6 address got: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+ for(num_v6=0;num_v6 < get_client_memptr(eth_client, clnt_indx)->ipv6_set;num_v6++)
+ {
+ if( data->ipv6_addr[0] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][0] &&
+ data->ipv6_addr[1] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][1] &&
+ data->ipv6_addr[2]== get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][2] &&
+ data->ipv6_addr[3] == get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][3])
+ {
+ IPACMDBG_H("ipv6 addr is found at position:%d for client:%d\n", num_v6, clnt_indx);
+ break;
+ }
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Invalid ipv6 address\n");
+ return IPACM_FAILURE;
+ }
+ if (num_v6 == IPV6_NUM_ADDR)
+ {
+ IPACMDBG_H("ipv6 addr is not found. \n");
+ return IPACM_FAILURE;
+ }
+
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if((tx_prop->tx[tx_index].ip == IPA_IP_v6) && (get_client_memptr(eth_client, clnt_indx)->route_rule_set_v6 != 0))
+ {
+ IPACMDBG_H("Delete client index %d ipv6 RT-rules for %d-st ipv6 for tx:%d\n", clnt_indx, num_v6, tx_index);
+ rt_hdl = get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6];
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ rt_hdl = get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6];
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ get_client_memptr(eth_client, clnt_indx)->ipv6_set--;
+ get_client_memptr(eth_client, clnt_indx)->route_rule_set_v6--;
+
+ for(;num_v6< get_client_memptr(eth_client, clnt_indx)->ipv6_set;num_v6++)
+ {
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][0] =
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][0];
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][1] =
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][1];
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][2] =
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][2];
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6][3] =
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[num_v6+1][3];
+ get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6] =
+ get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6+1];
+ get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6] =
+ get_client_memptr(eth_client, clnt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6+1];
+ }
+ }
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+/* delete filter rule for wan_down event for IPv4*/
+int IPACM_Lan::handle_wan_down(bool is_sta_mode)
+{
+ ipa_fltr_installed_notif_req_msg_v01 flt_index;
+ int fd;
+
+ fd = open(IPA_DEVICE_NAME, O_RDWR);
+ if (0 == fd)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+
+ if(is_sta_mode == false && modem_ul_v4_set == true)
+ {
+ if (num_wan_ul_fl_rule_v4 > MAX_WAN_UL_FILTER_RULES)
+ {
+ IPACMERR("number of wan_ul_fl_rule_v4 (%d) > MAX_WAN_UL_FILTER_RULES (%d), aborting...\n", num_wan_ul_fl_rule_v4, MAX_WAN_UL_FILTER_RULES);
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ if (num_wan_ul_fl_rule_v4 == 0)
+ {
+ IPACMERR("No modem UL rules were installed, return...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ if (m_filtering.DeleteFilteringHdls(wan_ul_fl_rule_hdl_v4,
+ IPA_IP_v4, num_wan_ul_fl_rule_v4) == false)
+ {
+ IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_wan_ul_fl_rule_v4);
+
+ memset(wan_ul_fl_rule_hdl_v4, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
+ num_wan_ul_fl_rule_v4 = 0;
+ modem_ul_v4_set = false;
+
+ memset(&flt_index, 0, sizeof(flt_index));
+ flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
+ if ((int)flt_index.source_pipe_index == -1)
+ {
+ IPACMERR("Error Query src pipe idx, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
+ flt_index.filter_index_list_len = 0;
+#else /* defined (FEATURE_IPA_V3) */
+ flt_index.rule_id_valid = 1;
+ flt_index.rule_id_len = 0;
+#endif
+ flt_index.embedded_pipe_index_valid = 1;
+ flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
+ if ((int)flt_index.embedded_pipe_index == -1)
+ {
+ IPACMERR("Error Query emb pipe idx, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ flt_index.retain_header_valid = 1;
+ flt_index.retain_header = 0;
+ flt_index.embedded_call_mux_id_valid = 1;
+ flt_index.embedded_call_mux_id = v4_mux_id;
+ v4_mux_id = 0;
+ if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
+ {
+ IPACMERR("Error sending filtering rule index, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ if (m_filtering.DeleteFilteringHdls(&lan_wan_fl_rule_hdl[0], IPA_IP_v4, 1) == false)
+ {
+ IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ sta_ul_v4_set = false;
+ }
+
+ close(fd);
+ return IPACM_SUCCESS;
+}
+
+/* handle new_address event*/
+int IPACM_Lan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ const int NUM_RULES = 1;
+ uint32_t num_ipv6_addr;
+ int res = IPACM_SUCCESS;
+#ifdef FEATURE_IPACM_HAL
+ IPACM_OffloadManager* OffloadMng;
+#endif
+
+ IPACMDBG_H("set route/filter rule ip-type: %d \n", data->iptype);
+
+/* Add private subnet*/
+#ifdef FEATURE_IPA_ANDROID
+ if (data->iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("current IPACM private subnet_addr number(%d)\n", IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+ if_ipv4_subnet = (data->ipv4_addr >> 8) << 8;
+ IPACMDBG_H(" Add IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+ if(IPACM_Iface::ipacmcfg->AddPrivateSubnet(if_ipv4_subnet, ipa_if_num) == false)
+ {
+ IPACMERR(" can't Add IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+ }
+ }
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+ /* Update the IP Type. */
+ config_ip_type(data->iptype);
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = data->iptype;
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = false;
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS; //go to A5
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name));
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG_H("ipv4 iface rt-rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
+ /* initial multicast/broadcast/fragment filter rule */
+
+ init_fl_rule(data->iptype);
+ install_ipv4_icmp_flt_rule();
+
+ /* populate the flt rule offset for eth bridge */
+ eth_bridge_flt_rule_offset[data->iptype] = ipv4_icmp_flt_rule_hdl[0];
+ eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_UP, IPA_IP_v4, NULL, NULL, NULL);
+ }
+ else
+ {
+ /* check if see that v6-addr already or not*/
+ for(num_ipv6_addr=0;num_ipv6_addr<num_dft_rt_v6;num_ipv6_addr++)
+ {
+ if((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
+ (ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
+ (ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
+ (ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
+ {
+ return IPACM_FAILURE;
+ break;
+ }
+ }
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = data->iptype;
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = false;
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS; //go to A5
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ ipv6_addr[num_dft_rt_v6][0] = data->ipv6_addr[0];
+ ipv6_addr[num_dft_rt_v6][1] = data->ipv6_addr[1];
+ ipv6_addr[num_dft_rt_v6][2] = data->ipv6_addr[2];
+ ipv6_addr[num_dft_rt_v6][3] = data->ipv6_addr[3];
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
+
+ /* setup same rule for v6_wan table*/
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1] = rt_rule_entry->rt_rule_hdl;
+
+ IPACMDBG_H("ipv6 wan iface rt-rule hdl=0x%x hdl=0x%x, num_dft_rt_v6: %d \n",
+ dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6],
+ dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1],num_dft_rt_v6);
+
+ if (num_dft_rt_v6 == 0)
+ {
+ install_ipv6_icmp_flt_rule();
+
+ /* populate the flt rule offset for eth bridge */
+ eth_bridge_flt_rule_offset[data->iptype] = ipv6_icmp_flt_rule_hdl[0];
+ eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_UP, IPA_IP_v6, NULL, NULL, NULL);
+
+ init_fl_rule(data->iptype);
+ }
+ num_dft_rt_v6++;
+ IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
+ }
+
+#ifdef FEATURE_IPACM_HAL
+ /* check if having pending add_downstream cache*/
+ OffloadMng = IPACM_OffloadManager::GetInstance();
+ if (OffloadMng == NULL) {
+ IPACMERR("failed to get IPACM_OffloadManager instance !\n");
+ } else {
+ IPACMDBG_H(" check iface %s if having add_downstream cache events\n", dev_name);
+ OffloadMng->search_framwork_cache(dev_name);
+ }
+#endif
+
+ IPACMDBG_H("finish route/filter rule ip-type: %d, res(%d)\n", data->iptype, res);
+
+fail:
+ free(rt_rule);
+ return res;
+}
+
+/* configure private subnet filter rules*/
+int IPACM_Lan::handle_private_subnet(ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i;
+
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG_H("lan->handle_private_subnet(); set route/filter rule \n");
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ if (iptype == IPA_IP_v4)
+ {
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
+ );
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+ /* Make LAN-traffic always go A5, use default IPA-RT table */
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4))
+ {
+ IPACMERR("LAN m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_default_v4);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ /* Support private subnet feature including guest-AP can't talk to primary AP etc */
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
+ IPACMDBG_H(" private filter rule use table: %s\n",IPACM_Iface::ipacmcfg->rt_tbl_default_v4.name);
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+ memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACMDBG_H("Loop %d 5\n", i);
+ }
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+
+ /* copy filter rule hdls */
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
+ {
+ private_fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ }
+ free(m_pFilteringTable);
+ }
+ else
+ {
+ IPACMDBG_H("No private subnet rules for ipv6 iface %s\n", dev_name);
+ }
+ return IPACM_SUCCESS;
+}
+
+
+/* for STA mode wan up: configure filter rule for wan_up event*/
+int IPACM_Lan::handle_wan_up(ipa_ip_type ip_type)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int len = 0;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG_H("set WAN interface as default filter rule\n");
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ if(ip_type == IPA_IP_v4)
+ {
+ if(sta_ul_v4_set == true)
+ {
+ IPACMDBG_H("Filetring rule for IPV4 of STA mode is already configured, sta_ul_v4_set: %d\n",sta_ul_v4_set);
+ return IPACM_FAILURE;
+ }
+ 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_H("Retrieving routing hanle for table: %s\n",
+ IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
+ &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("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;
+ if(IPACM_Wan::isWan_Bridge_Mode())
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ 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;
+
+/* only offload UL traffic of certain clients */
+#ifdef FEATURE_IPACM_HAL
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.src_addr_mask = prefix[IPA_IP_v4].v4Mask;
+ flt_rule_entry.rule.attrib.u.v4.src_addr = prefix[IPA_IP_v4].v4Addr;
+#endif
+ memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[0].flt_rule_hdl,
+ m_pFilteringTable->rules[0].status);
+ }
+
+ sta_ul_v4_set = true;
+ /* copy filter hdls */
+ lan_wan_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+ else if(ip_type == IPA_IP_v6)
+ {
+ if(sta_ul_v6_set == true)
+ {
+ IPACMDBG_H("Filetring rule for IPV6 of STA mode is already configured, sta_ul_v6_set: %d\n",sta_ul_v6_set);
+ return IPACM_FAILURE;
+ }
+ /* add default v6 filter rule */
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add));
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_v6);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ 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;
+
+/* only offload UL traffic of certain clients */
+#ifdef FEATURE_IPACM_HAL
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.src_addr_mask[0] = ntohl(prefix[IPA_IP_v6].v6Mask[0]);
+ flt_rule_entry.rule.attrib.u.v6.src_addr_mask[1] = ntohl(prefix[IPA_IP_v6].v6Mask[1]);
+ flt_rule_entry.rule.attrib.u.v6.src_addr_mask[2] = ntohl(prefix[IPA_IP_v6].v6Mask[2]);
+ flt_rule_entry.rule.attrib.u.v6.src_addr_mask[3] = ntohl(prefix[IPA_IP_v6].v6Mask[3]);
+ flt_rule_entry.rule.attrib.u.v6.src_addr[0] = ntohl(prefix[IPA_IP_v6].v6Addr[0]);
+ flt_rule_entry.rule.attrib.u.v6.src_addr[1] = ntohl(prefix[IPA_IP_v6].v6Addr[1]);
+ flt_rule_entry.rule.attrib.u.v6.src_addr[2] = ntohl(prefix[IPA_IP_v6].v6Addr[2]);
+ flt_rule_entry.rule.attrib.u.v6.src_addr[3] = ntohl(prefix[IPA_IP_v6].v6Addr[3]);
+
+#endif
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ sta_ul_v6_set = true;
+ /* copy filter hdls */
+ dft_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::handle_wan_up_ex(ipacm_ext_prop *ext_prop, ipa_ip_type iptype, uint8_t xlat_mux_id)
+{
+ int fd, ret = IPACM_SUCCESS;
+ uint32_t cnt;
+ IPACM_Config* ipacm_config = IPACM_Iface::ipacmcfg;
+ struct ipa_ioc_write_qmapid mux;
+
+ if(rx_prop != NULL)
+ {
+ /* give mud ID to IPA-driver for WLAN/LAN pkts */
+ fd = open(IPA_DEVICE_NAME, O_RDWR);
+ if (0 == fd)
+ {
+ IPACMDBG_H("Failed opening %s.\n", IPA_DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+
+ mux.qmap_id = ipacm_config->GetQmapId();
+ for(cnt=0; cnt<rx_prop->num_rx_props; cnt++)
+ {
+ mux.client = rx_prop->rx[cnt].src_pipe;
+ ret = ioctl(fd, IPA_IOC_WRITE_QMAPID, &mux);
+ if (ret)
+ {
+ IPACMERR("Failed to write mux id %d\n", mux.qmap_id);
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ }
+ close(fd);
+ }
+
+ /* check only add static UL filter rule once */
+ if (iptype ==IPA_IP_v6 && modem_ul_v6_set == false)
+ {
+ IPACMDBG_H("IPA_IP_v6 num_dft_rt_v6 %d xlat_mux_id: %d modem_ul_v6_set: %d\n", num_dft_rt_v6, xlat_mux_id, modem_ul_v6_set);
+ ret = handle_uplink_filter_rule(ext_prop, iptype, xlat_mux_id);
+ modem_ul_v6_set = true;
+ } else if (iptype ==IPA_IP_v4 && modem_ul_v4_set == false) {
+ IPACMDBG_H("IPA_IP_v4 xlat_mux_id: %d, modem_ul_v4_set %d\n", xlat_mux_id, modem_ul_v4_set);
+ ret = handle_uplink_filter_rule(ext_prop, iptype, xlat_mux_id);
+ modem_ul_v4_set = true;
+ } else {
+ IPACMDBG_H("ip-type: %d modem_ul_v4_set: %d, modem_ul_v6_set %d\n", iptype, modem_ul_v4_set, modem_ul_v6_set);
+ }
+ return ret;
+}
+
+/* handle ETH client initial, construct full headers (tx property) */
+int IPACM_Lan::handle_eth_hdr_init(uint8_t *mac_addr)
+{
+
+#define ETH_IFACE_INDEX_LEN 2
+
+ int res = IPACM_SUCCESS, len = 0;
+ char index[ETH_IFACE_INDEX_LEN];
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+ uint32_t cnt;
+ int clnt_indx;
+
+ clnt_indx = get_eth_client_index(mac_addr);
+
+ if (clnt_indx != IPACM_INVALID_INDEX)
+ {
+ IPACMERR("eth client is found/attached already with index %d \n", clnt_indx);
+ return IPACM_FAILURE;
+ }
+
+ /* add header to IPA */
+ if (num_eth_client >= IPA_MAX_NUM_ETH_CLIENTS)
+ {
+ IPACMERR("Reached maximum number(%d) of eth clients\n", IPA_MAX_NUM_ETH_CLIENTS);
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("ETH client number: %d\n", num_eth_client);
+
+ memcpy(get_client_memptr(eth_client, num_eth_client)->mac,
+ mac_addr,
+ sizeof(get_client_memptr(eth_client, num_eth_client)->mac));
+
+
+ IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(eth_client, num_eth_client)->mac[0],
+ get_client_memptr(eth_client, num_eth_client)->mac[1],
+ get_client_memptr(eth_client, num_eth_client)->mac[2],
+ get_client_memptr(eth_client, num_eth_client)->mac[3],
+ get_client_memptr(eth_client, num_eth_client)->mac[4],
+ get_client_memptr(eth_client, num_eth_client)->mac[5]);
+
+ /* add header to IPA */
+ if(tx_prop != NULL)
+ {
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+
+ /* copy partial header for v4*/
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v4)
+ {
+ IPACMDBG_H("Got partial v4-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr,
+ sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ if (sCopyHeader.is_eth2_ofst_valid)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+ mac_addr,
+ IPA_MAC_ADDR_SIZE);
+ }
+ /* replace src mac to bridge mac_addr if any */
+ if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+ IPACM_Iface::ipacmcfg->bridge_mac,
+ IPA_MAC_ADDR_SIZE);
+ IPACMDBG_H("device is in bridge mode \n");
+ }
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ snprintf(index,sizeof(index), "%d", ipa_if_num);
+ strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+ pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_ETH_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ snprintf(index,sizeof(index), "%d", header_name_count);
+ if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = 0;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ pHeaderDescriptor->hdr[0].status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
+ IPACMDBG_H("eth-client(%d) v4 full header name:%s header handle:(0x%x)\n",
+ num_eth_client,
+ pHeaderDescriptor->hdr[0].name,
+ get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v4);
+ get_client_memptr(eth_client, num_eth_client)->ipv4_header_set=true;
+
+ break;
+ }
+ }
+
+
+ /* copy partial header for v6*/
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+ {
+
+ IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr,
+ sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ if (sCopyHeader.is_eth2_ofst_valid)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+ mac_addr,
+ IPA_MAC_ADDR_SIZE);
+ }
+ /* replace src mac to bridge mac_addr if any */
+ if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+ IPACM_Iface::ipacmcfg->bridge_mac,
+ IPA_MAC_ADDR_SIZE);
+ IPACMDBG_H("device is in bridge mode \n");
+ }
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ snprintf(index,sizeof(index), "%d", ipa_if_num);
+ strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+ pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_ETH_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ snprintf(index,sizeof(index), "%d", header_name_count);
+ if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = 0;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ pHeaderDescriptor->hdr[0].status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
+ IPACMDBG_H("eth-client(%d) v6 full header name:%s header handle:(0x%x)\n",
+ num_eth_client,
+ pHeaderDescriptor->hdr[0].name,
+ get_client_memptr(eth_client, num_eth_client)->hdr_hdl_v6);
+
+ get_client_memptr(eth_client, num_eth_client)->ipv6_header_set=true;
+
+ break;
+
+ }
+ }
+ /* initialize wifi client*/
+ get_client_memptr(eth_client, num_eth_client)->route_rule_set_v4 = false;
+ get_client_memptr(eth_client, num_eth_client)->route_rule_set_v6 = 0;
+ get_client_memptr(eth_client, num_eth_client)->ipv4_set = false;
+ get_client_memptr(eth_client, num_eth_client)->ipv6_set = 0;
+ num_eth_client++;
+ header_name_count++; //keep increasing header_name_count
+ res = IPACM_SUCCESS;
+ IPACMDBG_H("eth client number: %d\n", num_eth_client);
+ }
+ else
+ {
+ return res;
+ }
+fail:
+ free(pHeaderDescriptor);
+ return res;
+}
+
+/*handle eth client */
+int IPACM_Lan::handle_eth_client_ipaddr(ipacm_event_data_all *data)
+{
+ int clnt_indx;
+ int v6_num;
+ uint32_t ipv6_link_local_prefix = 0xFE800000;
+ uint32_t ipv6_link_local_prefix_mask = 0xFFC00000;
+
+ IPACMDBG_H("number of eth clients: %d\n", num_eth_client);
+ IPACMDBG_H("event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->mac_addr[0],
+ data->mac_addr[1],
+ data->mac_addr[2],
+ data->mac_addr[3],
+ data->mac_addr[4],
+ data->mac_addr[5]);
+
+ clnt_indx = get_eth_client_index(data->mac_addr);
+
+ if (clnt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMERR("eth client not found/attached \n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("Ip-type received %d\n", data->iptype);
+ if (data->iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("ipv4 address: 0x%x\n", data->ipv4_addr);
+ if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+ {
+ if (get_client_memptr(eth_client, clnt_indx)->ipv4_set == false)
+ {
+ get_client_memptr(eth_client, clnt_indx)->v4_addr = data->ipv4_addr;
+ get_client_memptr(eth_client, clnt_indx)->ipv4_set = true;
+ }
+ else
+ {
+ /* check if client got new IPv4 address*/
+ if(data->ipv4_addr == get_client_memptr(eth_client, clnt_indx)->v4_addr)
+ {
+ IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
+ /* delete NAT rules first */
+ CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, clnt_indx)->v4_addr);
+ delete_eth_rtrules(clnt_indx,IPA_IP_v4);
+ get_client_memptr(eth_client, clnt_indx)->route_rule_set_v4 = false;
+ get_client_memptr(eth_client, clnt_indx)->v4_addr = data->ipv4_addr;
+ }
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Invalid client IPv4 address \n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+ (data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] != 0)) /* check if all 0 not valid ipv6 address */
+ {
+ IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+ if( (data->ipv6_addr[0] & ipv6_link_local_prefix_mask) != (ipv6_link_local_prefix & ipv6_link_local_prefix_mask) &&
+ memcmp(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix)) != 0)
+ {
+ IPACMDBG_H("This IPv6 address is not global IPv6 address with correct prefix, ignore.\n");
+ return IPACM_FAILURE;
+ }
+
+ if(get_client_memptr(eth_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
+ {
+
+ for(v6_num=0;v6_num < get_client_memptr(eth_client, clnt_indx)->ipv6_set;v6_num++)
+ {
+ if( data->ipv6_addr[0] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][0] &&
+ data->ipv6_addr[1] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][1] &&
+ data->ipv6_addr[2]== get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][2] &&
+ data->ipv6_addr[3] == get_client_memptr(eth_client, clnt_indx)->v6_addr[v6_num][3])
+ {
+ IPACMDBG_H("Already see this ipv6 addr at position: %d for client:%d\n", v6_num, clnt_indx);
+ return IPACM_FAILURE; /* not setup the RT rules*/
+ }
+ }
+
+ /* not see this ipv6 before for wifi client*/
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][1] = data->ipv6_addr[1];
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][2] = data->ipv6_addr[2];
+ get_client_memptr(eth_client, clnt_indx)->v6_addr[get_client_memptr(eth_client, clnt_indx)->ipv6_set][3] = data->ipv6_addr[3];
+ get_client_memptr(eth_client, clnt_indx)->ipv6_set++;
+ }
+ else
+ {
+ IPACMDBG_H("Already got %d ipv6 addr for client:%d\n", IPV6_NUM_ADDR, clnt_indx);
+ return IPACM_FAILURE; /* not setup the RT rules*/
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Invalid IPV6 address\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle eth client routing rule*/
+int IPACM_Lan::handle_eth_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ uint32_t tx_index;
+ int eth_index,v6_num;
+ const int NUM = 1;
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ IPACMDBG_H("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ eth_index = get_eth_client_index(mac_addr);
+ if (eth_index == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG_H("eth client not found/attached \n");
+ return IPACM_SUCCESS;
+ }
+
+ if (iptype==IPA_IP_v4) {
+ IPACMDBG_H("eth client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", eth_index, iptype,
+ get_client_memptr(eth_client, eth_index)->ipv4_set,
+ get_client_memptr(eth_client, eth_index)->route_rule_set_v4);
+ } else {
+ IPACMDBG_H("eth client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", eth_index, iptype,
+ get_client_memptr(eth_client, eth_index)->ipv6_set,
+ get_client_memptr(eth_client, eth_index)->route_rule_set_v6);
+ }
+ /* Add default routing rules if not set yet */
+ if ((iptype == IPA_IP_v4
+ && get_client_memptr(eth_client, eth_index)->route_rule_set_v4 == false
+ && get_client_memptr(eth_client, eth_index)->ipv4_set == true)
+ || (iptype == IPA_IP_v6
+ && get_client_memptr(eth_client, eth_index)->route_rule_set_v6 < get_client_memptr(eth_client, eth_index)->ipv6_set
+ ))
+ {
+
+ /* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ if (tx_prop != NULL)
+ {
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+ }
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_add));
+
+ if (rt_rule == NULL)
+ {
+ PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)NUM;
+ rt_rule->ip = iptype;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if(iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+ tx_index, tx_prop->tx[tx_index].ip,iptype);
+ continue;
+ }
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 0;
+
+ if (iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", eth_index,
+ get_client_memptr(eth_client, eth_index)->v4_addr);
+
+ IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+ eth_index,
+ get_client_memptr(eth_client, eth_index)->hdr_hdl_v4);
+ strlcpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
+ sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(eth_client, eth_index)->hdr_hdl_v4;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(eth_client, eth_index)->v4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = false;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ /* copy ipv4 RT hdl */
+ get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4 =
+ rt_rule->rules[0].rt_rule_hdl;
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4, iptype);
+ } else {
+
+ for(v6_num = get_client_memptr(eth_client, eth_index)->route_rule_set_v6;v6_num < get_client_memptr(eth_client, eth_index)->ipv6_set;v6_num++)
+ {
+ IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+ eth_index,
+ get_client_memptr(eth_client, eth_index)->hdr_hdl_v6);
+
+ /* v6 LAN_RT_TBL */
+ strlcpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+ sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ /* Support QCMAP LAN traffic feature, send to A5 */
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+ memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.hdr_hdl = 0;
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[v6_num], iptype);
+
+ /*Copy same rule to v6 WAN RT TBL*/
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ /* Downlink traffic from Wan iface, directly through IPA */
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(eth_client, eth_index)->hdr_hdl_v6;
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(eth_client, eth_index)->v6_addr[v6_num][3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(eth_client, eth_index)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[v6_num], iptype);
+ }
+ }
+
+ } /* end of for loop */
+
+ free(rt_rule);
+
+ if (iptype == IPA_IP_v4)
+ {
+ get_client_memptr(eth_client, eth_index)->route_rule_set_v4 = true;
+ }
+ else
+ {
+ get_client_memptr(eth_client, eth_index)->route_rule_set_v6 = get_client_memptr(eth_client, eth_index)->ipv6_set;
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+/* handle odu client initial, construct full headers (tx property) */
+int IPACM_Lan::handle_odu_hdr_init(uint8_t *mac_addr)
+{
+ int res = IPACM_SUCCESS, len = 0;
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+ uint32_t cnt;
+
+ 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]);
+
+ /* add header to IPA */
+ if(tx_prop != NULL)
+ {
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+
+ /* copy partial header for v4*/
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v4)
+ {
+ IPACMDBG("Got partial v4-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+ IPACMDBG("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMDBG("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr,
+ sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+ /* copy client mac_addr to partial header */
+ if (sCopyHeader.is_eth2_ofst_valid)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+ mac_addr,
+ IPA_MAC_ADDR_SIZE);
+ }
+ /* replace src mac to bridge mac_addr if any */
+ if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+ IPACM_Iface::ipacmcfg->bridge_mac,
+ IPA_MAC_ADDR_SIZE);
+ IPACMDBG_H("device is in bridge mode \n");
+ }
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+ strlcpy(pHeaderDescriptor->hdr[0].name, IPA_ODU_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name));
+ 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;
+ }
+
+ ODU_hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
+ ipv4_header_set = true ;
+ IPACMDBG(" ODU v4 full header name:%s header handle:(0x%x)\n",
+ pHeaderDescriptor->hdr[0].name,
+ ODU_hdr_hdl_v4);
+ break;
+ }
+ }
+
+
+ /* copy partial header for v6*/
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+ {
+
+ IPACMDBG("Got partial v6-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr,
+ sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ if (sCopyHeader.is_eth2_ofst_valid)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+ mac_addr,
+ IPA_MAC_ADDR_SIZE);
+ }
+ /* replace src mac to bridge mac_addr if any */
+ if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+ IPACM_Iface::ipacmcfg->bridge_mac,
+ IPA_MAC_ADDR_SIZE);
+ IPACMDBG_H("device is in bridge mode \n");
+ }
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ strlcpy(pHeaderDescriptor->hdr[0].name, IPA_ODU_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name));
+ 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;
+ }
+
+ ODU_hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
+ ipv6_header_set = true ;
+ IPACMDBG(" ODU v4 full header name:%s header handle:(0x%x)\n",
+ pHeaderDescriptor->hdr[0].name,
+ ODU_hdr_hdl_v6);
+ break;
+ }
+ }
+ }
+fail:
+ free(pHeaderDescriptor);
+ return res;
+}
+
+
+/* handle odu default route rule configuration */
+int IPACM_Lan::handle_odu_route_add()
+{
+ /* add default WAN route */
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ uint32_t tx_index;
+ const int NUM = 1;
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No tx properties, ignore default route setting\n");
+ return IPACM_SUCCESS;
+ }
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)NUM;
+
+
+ IPACMDBG_H("WAN table created %s \n", rt_rule->rt_tbl_name);
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = true;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+
+ if (IPA_IP_v4 == tx_prop->tx[tx_index].ip)
+ {
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v4.name, sizeof(rt_rule->rt_tbl_name));
+ rt_rule_entry->rule.hdr_hdl = ODU_hdr_hdl_v4;
+ rt_rule->ip = IPA_IP_v4;
+ }
+ else
+ {
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v6.name, sizeof(rt_rule->rt_tbl_name));
+ rt_rule_entry->rule.hdr_hdl = ODU_hdr_hdl_v6;
+ rt_rule->ip = IPA_IP_v6;
+ }
+
+ 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 (IPA_IP_v4 == tx_prop->tx[tx_index].ip)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = 0;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ odu_route_rule_v4_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG_H("Got ipv4 ODU-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+ odu_route_rule_v4_hdl[tx_index],
+ tx_index,
+ IPA_IP_v4);
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ odu_route_rule_v6_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG_H("Set ipv6 ODU-route rule hdl for v6_lan_table:0x%x,tx:%d,ip-type: %d \n",
+ odu_route_rule_v6_hdl[tx_index],
+ tx_index,
+ IPA_IP_v6);
+ }
+ }
+ free(rt_rule);
+ return IPACM_SUCCESS;
+}
+
+/* handle odu default route rule deletion */
+int IPACM_Lan::handle_odu_route_del()
+{
+ uint32_t tx_index;
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No tx properties, ignore delete default route setting\n");
+ return IPACM_SUCCESS;
+ }
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (tx_prop->tx[tx_index].ip == IPA_IP_v4)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n",
+ tx_index, tx_prop->tx[tx_index].ip,IPA_IP_v4);
+
+ if (m_routing.DeleteRoutingHdl(odu_route_rule_v4_hdl[tx_index], IPA_IP_v4)
+ == false)
+ {
+ IPACMERR("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v4, odu_route_rule_v4_hdl[tx_index], tx_index);
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n",
+ tx_index, tx_prop->tx[tx_index].ip,IPA_IP_v6);
+
+ if (m_routing.DeleteRoutingHdl(odu_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, odu_route_rule_v6_hdl[tx_index], tx_index);
+ return IPACM_FAILURE;
+ }
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle eth client del mode*/
+int IPACM_Lan::handle_eth_client_down_evt(uint8_t *mac_addr)
+{
+ int clt_indx;
+ uint32_t tx_index;
+ int num_eth_client_tmp = num_eth_client;
+ int num_v6;
+
+ IPACMDBG_H("total client: %d\n", num_eth_client_tmp);
+
+ clt_indx = get_eth_client_index(mac_addr);
+ if (clt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG_H("eth client not attached\n");
+ return IPACM_SUCCESS;
+ }
+
+ /* First reset nat rules and then route rules */
+ if(get_client_memptr(eth_client, clt_indx)->ipv4_set == true)
+ {
+ IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(eth_client, clt_indx)->v4_addr);
+ CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, clt_indx)->v4_addr);
+ }
+
+ if (delete_eth_rtrules(clt_indx, IPA_IP_v4))
+ {
+ IPACMERR("unbale to delete ecm-client v4 route rules for index: %d\n", clt_indx);
+ return IPACM_FAILURE;
+ }
+
+ if (delete_eth_rtrules(clt_indx, IPA_IP_v6))
+ {
+ IPACMERR("unbale to delete ecm-client v6 route rules for index: %d\n", clt_indx);
+ return IPACM_FAILURE;
+ }
+
+ /* Delete eth client header */
+ if(get_client_memptr(eth_client, clt_indx)->ipv4_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, clt_indx)->hdr_hdl_v4)
+ == false)
+ {
+ return IPACM_FAILURE;
+ }
+ get_client_memptr(eth_client, clt_indx)->ipv4_header_set = false;
+ }
+
+ if(get_client_memptr(eth_client, clt_indx)->ipv6_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, clt_indx)->hdr_hdl_v6)
+ == false)
+ {
+ return IPACM_FAILURE;
+ }
+ get_client_memptr(eth_client, clt_indx)->ipv6_header_set = false;
+ }
+
+ /* Reset ip_set to 0*/
+ get_client_memptr(eth_client, clt_indx)->ipv4_set = false;
+ get_client_memptr(eth_client, clt_indx)->ipv6_set = 0;
+ get_client_memptr(eth_client, clt_indx)->ipv4_header_set = false;
+ get_client_memptr(eth_client, clt_indx)->ipv6_header_set = false;
+ get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = false;
+ get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = 0;
+
+ for (; clt_indx < num_eth_client_tmp - 1; clt_indx++)
+ {
+ memcpy(get_client_memptr(eth_client, clt_indx)->mac,
+ get_client_memptr(eth_client, (clt_indx + 1))->mac,
+ sizeof(get_client_memptr(eth_client, clt_indx)->mac));
+
+ get_client_memptr(eth_client, clt_indx)->hdr_hdl_v4 = get_client_memptr(eth_client, (clt_indx + 1))->hdr_hdl_v4;
+ get_client_memptr(eth_client, clt_indx)->hdr_hdl_v6 = get_client_memptr(eth_client, (clt_indx + 1))->hdr_hdl_v6;
+ get_client_memptr(eth_client, clt_indx)->v4_addr = get_client_memptr(eth_client, (clt_indx + 1))->v4_addr;
+
+ get_client_memptr(eth_client, clt_indx)->ipv4_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv4_set;
+ get_client_memptr(eth_client, clt_indx)->ipv6_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv6_set;
+ get_client_memptr(eth_client, clt_indx)->ipv4_header_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv4_header_set;
+ get_client_memptr(eth_client, clt_indx)->ipv6_header_set = get_client_memptr(eth_client, (clt_indx + 1))->ipv6_header_set;
+
+ get_client_memptr(eth_client, clt_indx)->route_rule_set_v4 = get_client_memptr(eth_client, (clt_indx + 1))->route_rule_set_v4;
+ get_client_memptr(eth_client, clt_indx)->route_rule_set_v6 = get_client_memptr(eth_client, (clt_indx + 1))->route_rule_set_v6;
+
+ for (num_v6=0;num_v6< get_client_memptr(eth_client, clt_indx)->ipv6_set;num_v6++)
+ {
+ get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][0] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][0];
+ get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][1] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][1];
+ get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][2] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][2];
+ get_client_memptr(eth_client, clt_indx)->v6_addr[num_v6][3] = get_client_memptr(eth_client, (clt_indx + 1))->v6_addr[num_v6][3];
+ }
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4 =
+ get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v4;
+
+ for(num_v6=0;num_v6< get_client_memptr(eth_client, clt_indx)->route_rule_set_v6;num_v6++)
+ {
+ get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6] =
+ get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6[num_v6];
+ get_client_memptr(eth_client, clt_indx)->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6] =
+ get_client_memptr(eth_client, (clt_indx + 1))->eth_rt_hdl[tx_index].eth_rt_rule_hdl_v6_wan[num_v6];
+ }
+ }
+ }
+
+ IPACMDBG_H(" %d eth client deleted successfully \n", num_eth_client);
+ num_eth_client = num_eth_client - 1;
+ IPACMDBG_H(" Number of eth client: %d\n", num_eth_client);
+
+ /* Del RM dependency */
+ if(num_eth_client == 0)
+ {
+ /* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete all IPV4V6 RT-rule*/
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ if (tx_prop != NULL)
+ {
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle LAN iface down event*/
+int IPACM_Lan::handle_down_evt()
+{
+ uint32_t i;
+ int res = IPACM_SUCCESS;
+
+ IPACMDBG_H("lan handle_down_evt\n ");
+ if (ipa_if_cate == ODU_IF)
+ {
+ /* delete ODU default RT rules */
+ if (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true)
+ {
+ IPACMDBG_H("eMBMS enable, delete eMBMS DL RT rule\n");
+ handle_odu_route_del();
+ }
+
+ /* delete full header */
+ if (ipv4_header_set)
+ {
+ if (m_header.DeleteHeaderHdl(ODU_hdr_hdl_v4)
+ == false)
+ {
+ IPACMERR("ODU ipv4 header delete fail\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMDBG_H("ODU ipv4 header delete success\n");
+ }
+
+ if (ipv6_header_set)
+ {
+ if (m_header.DeleteHeaderHdl(ODU_hdr_hdl_v6)
+ == false)
+ {
+ IPACMERR("ODU ipv6 header delete fail\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMERR("ODU ipv6 header delete success\n");
+ }
+ }
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ goto fail;
+ }
+
+ /* delete wan filter rule */
+ if (IPACM_Wan::isWanUP(ipa_if_num) && rx_prop != NULL)
+ {
+ IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
+ handle_wan_down(IPACM_Wan::backhaul_is_sta_mode);
+#ifdef FEATURE_IPA_ANDROID
+ /* Clean-up tethered-iface list */
+ IPACM_Wan::delete_tether_iface(IPA_IP_v4, ipa_if_num);
+#endif
+ }
+
+ if (IPACM_Wan::isWanUP_V6(ipa_if_num) && rx_prop != NULL)
+ {
+ IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
+ handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode);
+#ifdef FEATURE_IPA_ANDROID
+ /* Clean-up tethered-iface list */
+ IPACM_Wan::delete_tether_iface(IPA_IP_v6, ipa_if_num);
+#endif
+ }
+
+ /* delete default filter rules */
+ if (ip_type != IPA_IP_v6 && rx_prop != NULL)
+ {
+ if(m_filtering.DeleteFilteringHdls(ipv4_icmp_flt_rule_hdl, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE) == false)
+ {
+ IPACMERR("Error Deleting ICMPv4 Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE);
+
+ if(dft_v4fl_rule_hdl[0] != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl, IPA_IP_v4,
+ IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Deleting Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
+ }
+
+ /* free private-subnet ipv4 filter rules */
+ if (IPACM_Iface::ipacmcfg->ipa_num_private_subnet > IPA_PRIV_SUBNET_FILTER_RULE_HANDLES)
+ {
+ IPACMERR(" the number of rules are bigger than array, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+#ifdef FEATURE_IPA_ANDROID
+ if(m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES) == false)
+ {
+ IPACMERR("Error deleting private subnet IPv4 flt rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES);
+#else
+ if (m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
+ {
+ IPACMERR("Error deleting private subnet IPv4 flt rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+#endif
+ IPACMDBG_H("Deleted private subnet v4 filter rules successfully.\n");
+ }
+ IPACMDBG_H("Finished delete default iface ipv4 filtering rules \n ");
+
+ if (ip_type != IPA_IP_v4 && rx_prop != NULL)
+ {
+ if(m_filtering.DeleteFilteringHdls(ipv6_icmp_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE) == false)
+ {
+ IPACMERR("Error Deleting ICMPv6 Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE);
+
+ if (dft_v6fl_rule_hdl[0] != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
+ }
+ }
+ IPACMDBG_H("Finished delete default iface ipv6 filtering rules \n ");
+
+ if (ip_type != IPA_IP_v6)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ IPACMDBG_H("Finished delete default iface ipv4 rules \n ");
+
+ /* delete default v6 routing rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ /* may have multiple ipv6 iface-RT rules*/
+ for (i = 0; i < 2*num_dft_rt_v6; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + i], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+ IPACMDBG_H("Finished delete default iface ipv6 rules \n ");
+
+ /* free the edm clients cache */
+ IPACMDBG_H("Free ecm clients cache\n");
+
+ /* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete all IPV4V6 RT-rule */
+ IPACMDBG_H("dev %s delete producer dependency\n", dev_name);
+ if (tx_prop != NULL)
+ {
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ }
+
+ eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_DOWN, IPA_IP_MAX, NULL, NULL, NULL);
+
+/* Delete private subnet*/
+#ifdef FEATURE_IPA_ANDROID
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG_H("current IPACM private subnet_addr number(%d)\n", IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+ IPACMDBG_H(" Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+ if(IPACM_Iface::ipacmcfg->DelPrivateSubnet(if_ipv4_subnet, ipa_if_num) == false)
+ {
+ IPACMERR(" can't Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+ }
+ }
+
+ /* reset the IPA-client pipe enum */
+ if(ipa_if_cate != WAN_IF)
+ {
+#ifdef FEATURE_IPACM_HAL
+ handle_tethering_client(true, IPACM_CLIENT_MAX);
+#else
+ handle_tethering_client(true, IPACM_CLIENT_USB);
+#endif
+ }
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+fail:
+ /* clean eth-client header, routing rules */
+ IPACMDBG_H("left %d eth clients need to be deleted \n ", num_eth_client);
+ for (i = 0; i < num_eth_client; i++)
+ {
+ /* First reset nat rules and then route rules */
+ if(get_client_memptr(eth_client, i)->ipv4_set == true)
+ {
+ IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(eth_client, i)->v4_addr);
+ CtList->HandleNeighIpAddrDelEvt(get_client_memptr(eth_client, i)->v4_addr);
+ }
+
+ if (delete_eth_rtrules(i, IPA_IP_v4))
+ {
+ IPACMERR("unbale to delete ecm-client v4 route rules for index %d\n", i);
+ res = IPACM_FAILURE;
+ }
+
+ if (delete_eth_rtrules(i, IPA_IP_v6))
+ {
+ IPACMERR("unbale to delete ecm-client v6 route rules for index %d\n", i);
+ res = IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("Delete %d client header\n", num_eth_client);
+
+ if(get_client_memptr(eth_client, i)->ipv4_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, i)->hdr_hdl_v4)
+ == false)
+ {
+ res = IPACM_FAILURE;
+ }
+ }
+
+ if(get_client_memptr(eth_client, i)->ipv6_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(eth_client, i)->hdr_hdl_v6)
+ == false)
+ {
+ res = IPACM_FAILURE;
+ }
+ }
+ } /* end of for loop */
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true && rx_prop != NULL)
+ {
+ handle_software_routing_disable();
+ }
+
+ if (odu_route_rule_v4_hdl != NULL)
+ {
+ free(odu_route_rule_v4_hdl);
+ }
+ if (odu_route_rule_v6_hdl != NULL)
+ {
+ free(odu_route_rule_v6_hdl);
+ }
+ /* Delete corresponding ipa_rm_resource_name of RX-endpoint after delete all IPV4V6 FT-rule */
+ if (rx_prop != NULL)
+ {
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+ IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+ IPACMDBG_H("Finished delete dependency \n ");
+ free(rx_prop);
+ }
+
+ if (eth_client != NULL)
+ {
+ free(eth_client);
+ }
+
+ if (tx_prop != NULL)
+ {
+ free(tx_prop);
+ }
+ if (iface_query != NULL)
+ {
+ free(iface_query);
+ }
+
+ is_active = false;
+ post_del_self_evt();
+
+ return res;
+}
+
+/* install UL filter rule from Q6 */
+int IPACM_Lan::handle_uplink_filter_rule(ipacm_ext_prop *prop, ipa_ip_type iptype, uint8_t xlat_mux_id)
+{
+ ipa_flt_rule_add flt_rule_entry;
+ int len = 0, cnt, ret = IPACM_SUCCESS;
+ ipa_ioc_add_flt_rule *pFilteringTable;
+ ipa_fltr_installed_notif_req_msg_v01 flt_index;
+ int fd;
+ int i, index, eq_index;
+ uint32_t value = 0;
+ uint8_t qmap_id;
+
+ IPACMDBG_H("Set modem UL flt rules\n");
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ if(prop == NULL || prop->num_ext_props <= 0)
+ {
+ IPACMDBG_H("No extended property.\n");
+ return IPACM_SUCCESS;
+ }
+
+ fd = open(IPA_DEVICE_NAME, O_RDWR);
+ if (0 == fd)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+ if (prop->num_ext_props > MAX_WAN_UL_FILTER_RULES)
+ {
+ IPACMERR("number of modem UL rules > MAX_WAN_UL_FILTER_RULES, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ memset(&flt_index, 0, sizeof(flt_index));
+ flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
+ if ((int)flt_index.source_pipe_index == -1)
+ {
+ IPACMERR("Error Query src pipe idx, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
+ flt_index.filter_index_list_len = prop->num_ext_props;
+#else /* defined (FEATURE_IPA_V3) */
+ flt_index.rule_id_valid = 1;
+ flt_index.rule_id_len = prop->num_ext_props;
+#endif
+ flt_index.embedded_pipe_index_valid = 1;
+ flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
+ if ((int)flt_index.embedded_pipe_index == -1)
+ {
+ IPACMERR("Error Query emb pipe idx, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ flt_index.retain_header_valid = 1;
+ flt_index.retain_header = 0;
+ flt_index.embedded_call_mux_id_valid = 1;
+ qmap_id = IPACM_Iface::ipacmcfg->GetQmapId();
+ flt_index.embedded_call_mux_id = qmap_id;
+#ifndef FEATURE_IPA_V3
+ IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n",
+ flt_index.source_pipe_index, flt_index.filter_index_list_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
+#else /* defined (FEATURE_IPA_V3) */
+ IPACMDBG_H("flt_index: src pipe: %d, num of rules: %d, ebd pipe: %d, mux id: %d\n",
+ flt_index.source_pipe_index, flt_index.rule_id_len, flt_index.embedded_pipe_index, flt_index.embedded_call_mux_id);
+#endif
+ len = sizeof(struct ipa_ioc_add_flt_rule) + prop->num_ext_props * sizeof(struct ipa_flt_rule_add);
+ pFilteringTable = (struct ipa_ioc_add_flt_rule*)malloc(len);
+ if (pFilteringTable == NULL)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable, 0, len);
+
+ pFilteringTable->commit = 1;
+ pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable->global = false;
+ pFilteringTable->ip = iptype;
+ pFilteringTable->num_rules = prop->num_ext_props;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
+ flt_rule_entry.at_rear = 1;
+#ifdef FEATURE_IPA_V3
+ if (flt_rule_entry.rule.eq_attrib.ipv4_frag_eq_present)
+ flt_rule_entry.at_rear = 0;
+#endif
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ if(iptype == IPA_IP_v4)
+ {
+ if (ipa_if_cate == ODU_IF && IPACM_Wan::isWan_Bridge_Mode())
+ {
+ IPACMDBG_H("WAN, ODU are in bridge mode \n");
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+ }
+ }
+ else if(iptype == IPA_IP_v6)
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ else
+ {
+ IPACMERR("IP type is not expected.\n");
+ ret = IPACM_FAILURE;
+ goto fail;
+ }
+
+ index = IPACM_Iface::ipacmcfg->getFltRuleCount(rx_prop->rx[0].src_pipe, iptype);
+
+ for(cnt=0; cnt<prop->num_ext_props; cnt++)
+ {
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &prop->prop[cnt].eq_attrib,
+ sizeof(prop->prop[cnt].eq_attrib));
+ flt_rule_entry.rule.rt_tbl_idx = prop->prop[cnt].rt_tbl_idx;
+
+ /* Handle XLAT configuration */
+ if ((iptype == IPA_IP_v4) && prop->prop[cnt].is_xlat_rule && (xlat_mux_id != 0))
+ {
+ /* fill the value of meta-data */
+ value = xlat_mux_id;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32_present = 1;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.offset = 0;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.value = (value & 0xFF) << 16;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.mask = 0x00FF0000;
+ IPACMDBG_H("xlat meta-data is modified for rule: %d has index %d with xlat_mux_id: %d\n",
+ cnt, index, xlat_mux_id);
+ }
+
+#ifdef FEATURE_IPACM_HAL
+ /* add prefix equation in modem UL rules */
+ if(iptype == IPA_IP_v4)
+ {
+ flt_rule_entry.rule.eq_attrib.num_offset_meq_32++;
+ if(flt_rule_entry.rule.eq_attrib.num_offset_meq_32 <= IPA_IPFLTR_NUM_MEQ_32_EQNS)
+ {
+ eq_index = flt_rule_entry.rule.eq_attrib.num_offset_meq_32 - 1;
+#ifdef FEATURE_IPA_V3
+ if(eq_index == 0)
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<5);
+ }
+ else
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<6);
+ }
+#else
+ if(eq_index == 0)
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<2);
+ }
+ else
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<3);
+ }
+#endif
+ flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].offset = 12;
+ flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].mask = prefix[IPA_IP_v4].v4Mask;
+ flt_rule_entry.rule.eq_attrib.offset_meq_32[eq_index].value = prefix[IPA_IP_v4].v4Addr;
+ }
+ else
+ {
+ IPACMERR("Run out of MEQ32 equation.\n");
+ flt_rule_entry.rule.eq_attrib.num_offset_meq_32--;
+ }
+ }
+ else
+ {
+ flt_rule_entry.rule.eq_attrib.num_offset_meq_128++;
+ if(flt_rule_entry.rule.eq_attrib.num_offset_meq_128 <= IPA_IPFLTR_NUM_MEQ_128_EQNS)
+ {
+ eq_index = flt_rule_entry.rule.eq_attrib.num_offset_meq_128 - 1;
+#ifdef FEATURE_IPA_V3
+ if(eq_index == 0)
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<3);
+ }
+ else
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<4);
+ }
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 0)
+ = prefix[IPA_IP_v6].v6Mask[3];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 4)
+ = prefix[IPA_IP_v6].v6Mask[2];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 8)
+ = prefix[IPA_IP_v6].v6Mask[1];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 12)
+ = prefix[IPA_IP_v6].v6Mask[0];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 0)
+ = prefix[IPA_IP_v6].v6Addr[3];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 4)
+ = prefix[IPA_IP_v6].v6Addr[2];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 8)
+ = prefix[IPA_IP_v6].v6Addr[1];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 12)
+ = prefix[IPA_IP_v6].v6Addr[0];
+#else
+ if(eq_index == 0)
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<9);
+ }
+ else
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<10);
+ }
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 0)
+ = prefix[IPA_IP_v6].v6Mask[0];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 4)
+ = prefix[IPA_IP_v6].v6Mask[1];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 8)
+ = prefix[IPA_IP_v6].v6Mask[2];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].mask + 12)
+ = prefix[IPA_IP_v6].v6Mask[3];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 0)
+ = prefix[IPA_IP_v6].v6Addr[0];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 4)
+ = prefix[IPA_IP_v6].v6Addr[1];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 8)
+ = prefix[IPA_IP_v6].v6Addr[2];
+ *(uint32_t *)(flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].value + 12)
+ = prefix[IPA_IP_v6].v6Addr[3];
+#endif
+ flt_rule_entry.rule.eq_attrib.offset_meq_128[eq_index].offset = 8;
+ }
+ else
+ {
+ IPACMERR("Run out of MEQ128 equation.\n");
+ flt_rule_entry.rule.eq_attrib.num_offset_meq_128--;
+ }
+ }
+#endif
+
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = prop->prop[cnt].is_rule_hashable;
+ flt_rule_entry.rule.rule_id = prop->prop[cnt].rule_id;
+ if(rx_prop->rx[0].attrib.attrib_mask & IPA_FLT_META_DATA) //turn on meta-data equation
+ {
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<9);
+ flt_rule_entry.rule.eq_attrib.metadata_meq32_present = 1;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.offset = 0;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.value |= rx_prop->rx[0].attrib.meta_data;
+ flt_rule_entry.rule.eq_attrib.metadata_meq32.mask |= rx_prop->rx[0].attrib.meta_data_mask;
+ }
+#endif
+ memcpy(&pFilteringTable->rules[cnt], &flt_rule_entry, sizeof(flt_rule_entry));
+
+ IPACMDBG_H("Modem UL filtering rule %d has index %d\n", cnt, index);
+#ifndef FEATURE_IPA_V3
+ flt_index.filter_index_list[cnt].filter_index = index;
+ flt_index.filter_index_list[cnt].filter_handle = prop->prop[cnt].filter_hdl;
+#else /* defined (FEATURE_IPA_V3) */
+ flt_index.rule_id[cnt] = prop->prop[cnt].rule_id;
+#endif
+ index++;
+ }
+
+ if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
+ {
+ IPACMERR("Error sending filtering rule index, aborting...\n");
+ ret = IPACM_FAILURE;
+ goto fail;
+ }
+
+ if(false == m_filtering.AddFilteringRule(pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable to Filtering, aborting...\n");
+ ret = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ if(iptype == IPA_IP_v4)
+ {
+ for(i=0; i<pFilteringTable->num_rules; i++)
+ {
+ wan_ul_fl_rule_hdl_v4[num_wan_ul_fl_rule_v4] = pFilteringTable->rules[i].flt_rule_hdl;
+ num_wan_ul_fl_rule_v4++;
+ }
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, pFilteringTable->num_rules);
+ v4_mux_id = qmap_id;
+ }
+ else if(iptype == IPA_IP_v6)
+ {
+ for(i=0; i<pFilteringTable->num_rules; i++)
+ {
+ wan_ul_fl_rule_hdl_v6[num_wan_ul_fl_rule_v6] = pFilteringTable->rules[i].flt_rule_hdl;
+ num_wan_ul_fl_rule_v6++;
+ }
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, iptype, pFilteringTable->num_rules);
+ v6_mux_id = qmap_id;
+ }
+
+ else
+ {
+ IPACMERR("IP type is not expected.\n");
+ goto fail;
+ }
+ }
+
+fail:
+ free(pFilteringTable);
+ close(fd);
+ return ret;
+}
+
+int IPACM_Lan::handle_wan_down_v6(bool is_sta_mode)
+{
+ ipa_fltr_installed_notif_req_msg_v01 flt_index;
+ int fd;
+
+ fd = open(IPA_DEVICE_NAME, O_RDWR);
+ if (0 == fd)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+
+ delete_ipv6_prefix_flt_rule();
+
+ memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
+
+ if(is_sta_mode == false && modem_ul_v6_set == true)
+ {
+ if (num_wan_ul_fl_rule_v6 > MAX_WAN_UL_FILTER_RULES)
+ {
+ IPACMERR(" the number of rules (%d) are bigger than array (%d), aborting...\n", num_wan_ul_fl_rule_v6, MAX_WAN_UL_FILTER_RULES);
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ if (num_wan_ul_fl_rule_v6 == 0)
+ {
+ IPACMERR("No modem UL rules were installed, return...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ if (m_filtering.DeleteFilteringHdls(wan_ul_fl_rule_hdl_v6,
+ IPA_IP_v6, num_wan_ul_fl_rule_v6) == false)
+ {
+ IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_wan_ul_fl_rule_v6);
+ memset(wan_ul_fl_rule_hdl_v6, 0, MAX_WAN_UL_FILTER_RULES * sizeof(uint32_t));
+ num_wan_ul_fl_rule_v6 = 0;
+ modem_ul_v6_set = false;
+
+ memset(&flt_index, 0, sizeof(flt_index));
+ flt_index.source_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[0].src_pipe);
+ if ((int)flt_index.source_pipe_index == -1)
+ {
+ IPACMERR("Error Query src pipe idx, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ flt_index.install_status = IPA_QMI_RESULT_SUCCESS_V01;
+#ifndef FEATURE_IPA_V3
+ flt_index.filter_index_list_len = 0;
+#else /* defined (FEATURE_IPA_V3) */
+ flt_index.rule_id_valid = 1;
+ flt_index.rule_id_len = 0;
+#endif
+ flt_index.embedded_pipe_index_valid = 1;
+ flt_index.embedded_pipe_index = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, IPA_CLIENT_APPS_LAN_WAN_PROD);
+ if ((int)flt_index.embedded_pipe_index == -1)
+ {
+ IPACMERR("Error Query emb pipe idx, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ flt_index.retain_header_valid = 1;
+ flt_index.retain_header = 0;
+ flt_index.embedded_call_mux_id_valid = 1;
+ flt_index.embedded_call_mux_id = v6_mux_id;
+ v6_mux_id = 0;
+ if(false == m_filtering.SendFilteringRuleIndex(&flt_index))
+ {
+ IPACMERR("Error sending filtering rule index, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ if (m_filtering.DeleteFilteringHdls(&dft_v6fl_rule_hdl[IPV6_DEFAULT_FILTERTING_RULES],
+ IPA_IP_v6, 1) == false)
+ {
+ IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ sta_ul_v6_set = false;
+ }
+ close(fd);
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::reset_to_dummy_flt_rule(ipa_ip_type iptype, uint32_t rule_hdl)
+{
+ int len, res = IPACM_SUCCESS;
+ struct ipa_flt_rule_mdfy flt_rule;
+ struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
+
+ IPACMDBG_H("Reset flt rule to dummy, IP type: %d, hdl: %d\n", iptype, rule_hdl);
+ len = sizeof(struct ipa_ioc_mdfy_flt_rule) + sizeof(struct ipa_flt_rule_mdfy);
+ pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
+
+ if (pFilteringTable == NULL)
+ {
+ IPACMERR("Error allocate flt rule memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable, 0, len);
+
+ pFilteringTable->commit = 1;
+ pFilteringTable->ip = iptype;
+ pFilteringTable->num_rules = 1;
+
+ memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_mdfy));
+ flt_rule.status = -1;
+ flt_rule.rule_hdl = rule_hdl;
+
+ flt_rule.rule.retain_hdr = 0;
+ flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
+
+ if(iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("Reset IPv4 flt rule to dummy\n");
+
+ flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
+ flt_rule.rule.attrib.u.v4.dst_addr = ~0;
+ flt_rule.rule.attrib.u.v4.dst_addr_mask = ~0;
+ flt_rule.rule.attrib.u.v4.src_addr = ~0;
+ flt_rule.rule.attrib.u.v4.src_addr_mask = ~0;
+
+ memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+ if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
+ {
+ IPACMERR("Error modifying filtering rule.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ IPACMDBG_H("Flt rule reset to dummy, hdl: 0x%x, status: %d\n", pFilteringTable->rules[0].rule_hdl,
+ pFilteringTable->rules[0].status);
+ }
+ }
+ else if(iptype == IPA_IP_v6)
+ {
+ IPACMDBG_H("Reset IPv6 flt rule to dummy\n");
+
+ flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
+ flt_rule.rule.attrib.u.v6.src_addr[0] = ~0;
+ flt_rule.rule.attrib.u.v6.src_addr[1] = ~0;
+ flt_rule.rule.attrib.u.v6.src_addr[2] = ~0;
+ flt_rule.rule.attrib.u.v6.src_addr[3] = ~0;
+ flt_rule.rule.attrib.u.v6.src_addr_mask[0] = ~0;
+ flt_rule.rule.attrib.u.v6.src_addr_mask[1] = ~0;
+ flt_rule.rule.attrib.u.v6.src_addr_mask[2] = ~0;
+ flt_rule.rule.attrib.u.v6.src_addr_mask[3] = ~0;
+ flt_rule.rule.attrib.u.v6.dst_addr[0] = ~0;
+ flt_rule.rule.attrib.u.v6.dst_addr[1] = ~0;
+ flt_rule.rule.attrib.u.v6.dst_addr[2] = ~0;
+ flt_rule.rule.attrib.u.v6.dst_addr[3] = ~0;
+ flt_rule.rule.attrib.u.v6.dst_addr_mask[0] = ~0;
+ flt_rule.rule.attrib.u.v6.dst_addr_mask[1] = ~0;
+ flt_rule.rule.attrib.u.v6.dst_addr_mask[2] = ~0;
+ flt_rule.rule.attrib.u.v6.dst_addr_mask[3] = ~0;
+
+
+ memcpy(&(pFilteringTable->rules[0]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+ if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
+ {
+ IPACMERR("Error modifying filtering rule.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ IPACMDBG_H("Flt rule reset to dummy, hdl: 0x%x, status: %d\n", pFilteringTable->rules[0].rule_hdl,
+ pFilteringTable->rules[0].status);
+ }
+ }
+ else
+ {
+ IPACMERR("IP type is not expected.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+fail:
+ free(pFilteringTable);
+ return res;
+}
+
+void IPACM_Lan::post_del_self_evt()
+{
+ ipacm_cmd_q_data evt;
+ ipacm_event_data_fid* fid;
+ fid = (ipacm_event_data_fid*)malloc(sizeof(ipacm_event_data_fid));
+ if(fid == NULL)
+ {
+ IPACMERR("Failed to allocate fid memory.\n");
+ return;
+ }
+ memset(fid, 0, sizeof(ipacm_event_data_fid));
+ memset(&evt, 0, sizeof(ipacm_cmd_q_data));
+
+ fid->if_index = ipa_if_num;
+
+ evt.evt_data = (void*)fid;
+ evt.event = IPA_LAN_DELETE_SELF;
+
+ IPACMDBG_H("Posting event IPA_LAN_DELETE_SELF\n");
+ IPACM_EvtDispatcher::PostEvt(&evt);
+}
+
+/*handle reset usb-client rt-rules */
+int IPACM_Lan::handle_lan_client_reset_rt(ipa_ip_type iptype)
+{
+ uint32_t i;
+ int res = IPACM_SUCCESS;
+
+ /* clean eth-client routing rules */
+ IPACMDBG_H("left %d eth clients need to be deleted \n ", num_eth_client);
+ for (i = 0; i < num_eth_client; i++)
+ {
+ res = delete_eth_rtrules(i, iptype);
+ if (res != IPACM_SUCCESS)
+ {
+ IPACMERR("Failed to delete old iptype(%d) rules.\n", iptype);
+ return res;
+ }
+ } /* end of for loop */
+
+ /* Reset ip-address */
+ for (i = 0; i < num_eth_client; i++)
+ {
+ if(iptype == IPA_IP_v4)
+ {
+ get_client_memptr(eth_client, i)->ipv4_set = false;
+ }
+ else
+ {
+ get_client_memptr(eth_client, i)->ipv6_set = 0;
+ }
+ } /* end of for loop */
+ return res;
+}
+
+int IPACM_Lan::install_ipv4_icmp_flt_rule()
+{
+ int len;
+ struct ipa_ioc_add_flt_rule* flt_rule;
+ struct ipa_flt_rule_add flt_rule_entry;
+
+ if(rx_prop != NULL)
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+ flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!flt_rule)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ flt_rule->commit = 1;
+ flt_rule->ep = rx_prop->rx[0].src_pipe;
+ flt_rule->global = false;
+ flt_rule->ip = IPA_IP_v4;
+ flt_rule->num_rules = 1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+ flt_rule_entry.rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP;
+ memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (m_filtering.AddFilteringRule(flt_rule) == false)
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ free(flt_rule);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ ipv4_icmp_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
+ IPACMDBG_H("IPv4 icmp filter rule HDL:0x%x\n", ipv4_icmp_flt_rule_hdl[0]);
+ free(flt_rule);
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::install_ipv6_icmp_flt_rule()
+{
+
+ int len;
+ struct ipa_ioc_add_flt_rule* flt_rule;
+ struct ipa_flt_rule_add flt_rule_entry;
+
+ if(rx_prop != NULL)
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+ flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!flt_rule)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ flt_rule->commit = 1;
+ flt_rule->ep = rx_prop->rx[0].src_pipe;
+ flt_rule->global = false;
+ flt_rule->ip = IPA_IP_v6;
+ flt_rule->num_rules = 1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = false;
+#endif
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
+ memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (m_filtering.AddFilteringRule(flt_rule) == false)
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ free(flt_rule);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ ipv6_icmp_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
+ IPACMDBG_H("IPv6 icmp filter rule HDL:0x%x\n", ipv6_icmp_flt_rule_hdl[0]);
+ free(flt_rule);
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::add_dummy_private_subnet_flt_rule(ipa_ip_type iptype)
+{
+ if(rx_prop == NULL)
+ {
+ IPACMDBG_H("There is no rx_prop for iface %s, not able to add dummy private subnet filtering rule.\n", dev_name);
+ return 0;
+ }
+
+ if(iptype == IPA_IP_v6)
+ {
+ IPACMDBG_H("There is no ipv6 dummy filter rules needed for iface %s\n", dev_name);
+ return 0;
+ }
+ int i, len, res = IPACM_SUCCESS;
+ struct ipa_flt_rule_add flt_rule;
+ ipa_ioc_add_flt_rule* pFilteringTable;
+
+ len = sizeof(struct ipa_ioc_add_flt_rule) + IPA_MAX_PRIVATE_SUBNET_ENTRIES * sizeof(struct ipa_flt_rule_add);
+
+ pFilteringTable = (struct ipa_ioc_add_flt_rule *)malloc(len);
+ if (pFilteringTable == NULL)
+ {
+ IPACMERR("Error allocate flt table memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable, 0, len);
+
+ pFilteringTable->commit = 1;
+ pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable->global = false;
+ pFilteringTable->ip = iptype;
+ pFilteringTable->num_rules = IPA_MAX_PRIVATE_SUBNET_ENTRIES;
+
+ memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule.rule.retain_hdr = 0;
+ flt_rule.at_rear = true;
+ flt_rule.flt_rule_hdl = -1;
+ flt_rule.status = -1;
+ flt_rule.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule.rule.hashable = true;
+#endif
+ memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib,
+ sizeof(flt_rule.rule.attrib));
+
+ if(iptype == IPA_IP_v4)
+ {
+ flt_rule.rule.attrib.attrib_mask = IPA_FLT_SRC_ADDR | IPA_FLT_DST_ADDR;
+ flt_rule.rule.attrib.u.v4.src_addr_mask = ~0;
+ flt_rule.rule.attrib.u.v4.src_addr = ~0;
+ flt_rule.rule.attrib.u.v4.dst_addr_mask = ~0;
+ flt_rule.rule.attrib.u.v4.dst_addr = ~0;
+
+ for(i=0; i<IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
+ {
+ memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_add));
+ }
+
+ if (false == m_filtering.AddFilteringRule(pFilteringTable))
+ {
+ IPACMERR("Error adding dummy private subnet v4 flt rule\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES);
+ /* copy filter rule hdls */
+ for (int i = 0; i < IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
+ {
+ if (pFilteringTable->rules[i].status == 0)
+ {
+ private_fl_rule_hdl[i] = pFilteringTable->rules[i].flt_rule_hdl;
+ IPACMDBG_H("Private subnet v4 flt rule %d hdl:0x%x\n", i, private_fl_rule_hdl[i]);
+ }
+ else
+ {
+ IPACMERR("Failed adding lan2lan v4 flt rule %d\n", i);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+ }
+fail:
+ free(pFilteringTable);
+ return res;
+}
+
+int IPACM_Lan::handle_private_subnet_android(ipa_ip_type iptype)
+{
+ int i, len, res = IPACM_SUCCESS;
+ struct ipa_flt_rule_mdfy flt_rule;
+ struct ipa_ioc_mdfy_flt_rule* pFilteringTable;
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ if(iptype == IPA_IP_v6)
+ {
+ IPACMDBG_H("There is no ipv6 dummy filter rules needed for iface %s\n", dev_name);
+ return 0;
+ }
+ else
+ {
+ for(i=0; i<IPA_MAX_PRIVATE_SUBNET_ENTRIES; i++)
+ {
+ reset_to_dummy_flt_rule(IPA_IP_v4, private_fl_rule_hdl[i]);
+ }
+
+ len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_mdfy);
+ pFilteringTable = (struct ipa_ioc_mdfy_flt_rule*)malloc(len);
+ if (!pFilteringTable)
+ {
+ IPACMERR("Failed to allocate ipa_ioc_mdfy_flt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable, 0, len);
+
+ pFilteringTable->commit = 1;
+ pFilteringTable->ip = iptype;
+ pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+ /* Make LAN-traffic always go A5, use default IPA-RT table */
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_default_v4))
+ {
+ IPACMERR("Failed to get routing table handle.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memset(&flt_rule, 0, sizeof(struct ipa_flt_rule_mdfy));
+ flt_rule.status = -1;
+
+ flt_rule.rule.retain_hdr = 1;
+ flt_rule.rule.to_uc = 0;
+ flt_rule.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule.rule.eq_attrib_type = 0;
+ flt_rule.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_default_v4.hdl;
+ IPACMDBG_H("Private filter rule use table: %s\n",IPACM_Iface::ipacmcfg->rt_tbl_default_v4.name);
+
+ memcpy(&flt_rule.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule.rule.attrib));
+ flt_rule.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+ for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+ {
+ flt_rule.rule_hdl = private_fl_rule_hdl[i];
+ flt_rule.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+ flt_rule.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+ memcpy(&(pFilteringTable->rules[i]), &flt_rule, sizeof(struct ipa_flt_rule_mdfy));
+ IPACMDBG_H(" IPACM private subnet_addr as: 0x%x entry(%d)\n", flt_rule.rule.attrib.u.v4.dst_addr, i);
+ }
+
+ if (false == m_filtering.ModifyFilteringRule(pFilteringTable))
+ {
+ IPACMERR("Failed to modify private subnet filtering rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+fail:
+ if(pFilteringTable != NULL)
+ {
+ free(pFilteringTable);
+ }
+ return res;
+}
+
+int IPACM_Lan::install_ipv6_prefix_flt_rule(uint32_t* prefix)
+{
+ if(prefix == NULL)
+ {
+ IPACMERR("IPv6 prefix is empty.\n");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("Receive IPv6 prefix: 0x%08x%08x.\n", prefix[0], prefix[1]);
+
+ int len;
+ struct ipa_ioc_add_flt_rule* flt_rule;
+ struct ipa_flt_rule_add flt_rule_entry;
+
+ if(rx_prop != NULL)
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+ flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!flt_rule)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ flt_rule->commit = 1;
+ flt_rule->ep = rx_prop->rx[0].src_pipe;
+ flt_rule->global = false;
+ flt_rule->ip = IPA_IP_v6;
+ flt_rule->num_rules = 1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = prefix[0];
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = prefix[1];
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x0;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x0;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x0;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x0;
+ memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (m_filtering.AddFilteringRule(flt_rule) == false)
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ free(flt_rule);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ ipv6_prefix_flt_rule_hdl[0] = flt_rule->rules[0].flt_rule_hdl;
+ IPACMDBG_H("IPv6 prefix filter rule HDL:0x%x\n", ipv6_prefix_flt_rule_hdl[0]);
+ free(flt_rule);
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+void IPACM_Lan::delete_ipv6_prefix_flt_rule()
+{
+ if(m_filtering.DeleteFilteringHdls(ipv6_prefix_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE) == false)
+ {
+ IPACMERR("Failed to delete ipv6 prefix flt rule.\n");
+ return;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_PREFIX_FLT_RULE);
+ return;
+}
+
+int IPACM_Lan::handle_addr_evt_odu_bridge(ipacm_event_data_addr* data)
+{
+ int fd, res = IPACM_SUCCESS;
+ struct in6_addr ipv6_addr;
+ if(data == NULL)
+ {
+ IPACMERR("Failed to get interface IP address.\n");
+ return IPACM_FAILURE;
+ }
+
+ if(data->iptype == IPA_IP_v6)
+ {
+ fd = open(IPACM_Iface::ipacmcfg->DEVICE_NAME_ODU, O_RDWR);
+ if(fd == 0)
+ {
+ IPACMERR("Failed to open %s.\n", IPACM_Iface::ipacmcfg->DEVICE_NAME_ODU);
+ return IPACM_FAILURE;
+ }
+
+ memcpy(&ipv6_addr, data->ipv6_addr, sizeof(struct in6_addr));
+
+ if( ioctl(fd, ODU_BRIDGE_IOC_SET_LLV6_ADDR, &ipv6_addr) )
+ {
+ IPACMERR("Failed to write IPv6 address to odu driver.\n");
+ res = IPACM_FAILURE;
+ }
+ num_dft_rt_v6++;
+ close(fd);
+ }
+
+ return res;
+}
+
+ipa_hdr_proc_type IPACM_Lan::eth_bridge_get_hdr_proc_type(ipa_hdr_l2_type t1, ipa_hdr_l2_type t2)
+{
+ if(t1 == IPA_HDR_L2_ETHERNET_II)
+ {
+ if(t2 == IPA_HDR_L2_ETHERNET_II)
+ {
+ return IPA_HDR_PROC_ETHII_TO_ETHII;
+ }
+ if(t2 == IPA_HDR_L2_802_3)
+ {
+ return IPA_HDR_PROC_ETHII_TO_802_3;
+ }
+ }
+
+ if(t1 == IPA_HDR_L2_802_3)
+ {
+ if(t2 == IPA_HDR_L2_ETHERNET_II)
+ {
+ return IPA_HDR_PROC_802_3_TO_ETHII;
+ }
+ if(t2 == IPA_HDR_L2_802_3)
+ {
+ return IPA_HDR_PROC_802_3_TO_802_3;
+ }
+ }
+
+ return IPA_HDR_PROC_NONE;
+}
+
+int IPACM_Lan::eth_bridge_get_hdr_template_hdl(uint32_t* hdr_hdl)
+{
+ if(hdr_hdl == NULL)
+ {
+ IPACMDBG_H("Hdr handle pointer is empty.\n");
+ return IPACM_FAILURE;
+ }
+
+ struct ipa_ioc_get_hdr hdr;
+ memset(&hdr, 0, sizeof(hdr));
+
+ memcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+ if(m_header.GetHeaderHandle(&hdr) == false)
+ {
+ IPACMERR("Failed to get template hdr hdl.\n");
+ return IPACM_FAILURE;
+ }
+
+ *hdr_hdl = hdr.hdl;
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::handle_cradle_wan_mode_switch(bool is_wan_bridge_mode)
+{
+ struct ipa_flt_rule_mdfy flt_rule_entry;
+ int len = 0;
+ ipa_ioc_mdfy_flt_rule *m_pFilteringTable;
+
+ IPACMDBG_H("Handle wan mode swtich: is wan bridge mode?%d\n", is_wan_bridge_mode);
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ len = sizeof(struct ipa_ioc_mdfy_flt_rule) + (1 * sizeof(struct ipa_flt_rule_mdfy));
+ m_pFilteringTable = (struct ipa_ioc_mdfy_flt_rule *)calloc(1, len);
+ if (m_pFilteringTable == NULL)
+ {
+ PERROR("Error Locate ipa_ioc_mdfy_flt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ IPACMDBG_H("Retrieving routing hanle for table: %s\n",
+ IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
+ &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("Routing handle for table: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl);
+
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_mdfy)); // Zero All Fields
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule_hdl = lan_wan_fl_rule_hdl[0];
+
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ if(is_wan_bridge_mode)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT;
+ }
+ 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.ModifyFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Modifying RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG_H("flt rule hdl = %d, status = %d\n",
+ m_pFilteringTable->rules[0].rule_hdl,
+ m_pFilteringTable->rules[0].status);
+ }
+ free(m_pFilteringTable);
+ return IPACM_SUCCESS;
+}
+
+/*handle reset usb-client rt-rules */
+int IPACM_Lan::handle_tethering_stats_event(ipa_get_data_stats_resp_msg_v01 *data)
+{
+ int fd;
+ uint32_t pipe_len, cnt;
+ uint64_t num_ul_packets, num_ul_bytes;
+ uint64_t num_dl_packets, num_dl_bytes;
+ bool ul_pipe_found, dl_pipe_found;
+ FILE *fp = NULL;
+
+ fd = open(IPA_DEVICE_NAME, O_RDWR);
+ if (fd < 0)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+
+
+ ul_pipe_found = false;
+ dl_pipe_found = false;
+ num_ul_packets = 0;
+ num_dl_packets = 0;
+ num_ul_bytes = 0;
+ num_dl_bytes = 0;
+
+ if (data->dl_dst_pipe_stats_list_valid)
+ {
+ if(tx_prop != NULL)
+ {
+ for (pipe_len = 0; pipe_len < data->dl_dst_pipe_stats_list_len; pipe_len++)
+ {
+ IPACMDBG_H("Check entry(%d) dl_dst_pipe(%d)\n", pipe_len, data->dl_dst_pipe_stats_list[pipe_len].pipe_index);
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ IPACMDBG_H("Check Tx_prop_entry(%d) pipe(%d)\n", cnt, ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe));
+ if(ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe) == (int)data->dl_dst_pipe_stats_list[pipe_len].pipe_index)
+ {
+ /* update the DL stats */
+ dl_pipe_found = true;
+ num_dl_packets += data->dl_dst_pipe_stats_list[pipe_len].num_ipv4_packets;
+ num_dl_packets += data->dl_dst_pipe_stats_list[pipe_len].num_ipv6_packets;
+ num_dl_bytes += data->dl_dst_pipe_stats_list[pipe_len].num_ipv4_bytes;
+ num_dl_bytes += data->dl_dst_pipe_stats_list[pipe_len].num_ipv6_bytes;
+ IPACMDBG_H("Got matched dst-pipe (%d) from %d tx props\n", data->dl_dst_pipe_stats_list[pipe_len].pipe_index, cnt);
+ IPACMDBG_H("DL_packets:(%llu) DL_bytes:(%llu) \n", (long long)num_dl_packets, (long long)num_dl_bytes);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (data->ul_src_pipe_stats_list_valid)
+ {
+ if(rx_prop != NULL)
+ {
+ for (pipe_len = 0; pipe_len < data->ul_src_pipe_stats_list_len; pipe_len++)
+ {
+ IPACMDBG_H("Check entry(%d) dl_dst_pipe(%d)\n", pipe_len, data->ul_src_pipe_stats_list[pipe_len].pipe_index);
+ for (cnt=0; cnt < rx_prop->num_rx_props; cnt++)
+ {
+ IPACMDBG_H("Check Rx_prop_entry(%d) pipe(%d)\n", cnt, ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe));
+ //Typecasting to avoid -Wall -Werror errors
+ if(ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe) == (int)data->ul_src_pipe_stats_list[pipe_len].pipe_index)
+ {
+ /* update the UL stats */
+ ul_pipe_found = true;
+ num_ul_packets += data->ul_src_pipe_stats_list[pipe_len].num_ipv4_packets;
+ num_ul_packets += data->ul_src_pipe_stats_list[pipe_len].num_ipv6_packets;
+ num_ul_bytes += data->ul_src_pipe_stats_list[pipe_len].num_ipv4_bytes;
+ num_ul_bytes += data->ul_src_pipe_stats_list[pipe_len].num_ipv6_bytes;
+ IPACMDBG_H("Got matched dst-pipe (%d) from %d tx props\n", data->ul_src_pipe_stats_list[pipe_len].pipe_index, cnt);
+ IPACMDBG_H("UL_packets:(%llu) UL_bytes:(%llu) \n", (long long)num_ul_packets, (long long)num_ul_bytes);
+ break;
+ }
+ }
+ }
+ }
+ }
+ close(fd);
+
+ if (ul_pipe_found || dl_pipe_found)
+ {
+ IPACMDBG_H("Update IPA_TETHERING_STATS_UPDATE_EVENT, TX(P%llu/B%llu) RX(P%llu/B%llu) DEV(%s) to LTE(%s) \n",
+ (long long)num_ul_packets,
+ (long long)num_ul_bytes,
+ (long long)num_dl_packets,
+ (long long)num_dl_bytes,
+ dev_name,
+ IPACM_Wan::wan_up_dev_name);
+ fp = fopen(IPA_PIPE_STATS_FILE_NAME, "w");
+ if ( fp == NULL )
+ {
+ IPACMERR("Failed to write pipe stats to %s, error is %d - %s\n",
+ IPA_PIPE_STATS_FILE_NAME, errno, strerror(errno));
+ return IPACM_FAILURE;
+ }
+
+ fprintf(fp, PIPE_STATS,
+ dev_name,
+ IPACM_Wan::wan_up_dev_name,
+ (long long)num_ul_bytes,
+ (long long)num_ul_packets,
+ (long long)num_dl_bytes,
+ (long long)num_dl_packets);
+ fclose(fp);
+ }
+ return IPACM_SUCCESS;
+}
+
+/*handle tether client */
+int IPACM_Lan::handle_tethering_client(bool reset, ipacm_client_enum ipa_client)
+{
+ int fd, ret = IPACM_SUCCESS;
+ uint32_t cnt;
+ int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
+ wan_ioctl_set_tether_client_pipe tether_client;
+
+ if(fd_wwan_ioctl < 0)
+ {
+ IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+
+ fd = open(IPA_DEVICE_NAME, O_RDWR);
+ if (fd < 0)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+ close(fd_wwan_ioctl);
+ return IPACM_FAILURE;
+ }
+
+ memset(&tether_client, 0, sizeof(tether_client));
+ tether_client.reset_client = reset;
+ tether_client.ipa_client = ipa_client;
+
+ if(tx_prop != NULL)
+ {
+ tether_client.dl_dst_pipe_len = tx_prop->num_tx_props;
+ for (cnt = 0; cnt < tx_prop->num_tx_props; cnt++)
+ {
+ IPACMDBG_H("Tx(%d), dst_pipe: %d, ipa_pipe: %d\n",
+ cnt, tx_prop->tx[cnt].dst_pipe,
+ ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe));
+ tether_client.dl_dst_pipe_list[cnt] = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, tx_prop->tx[cnt].dst_pipe);
+ }
+ }
+
+ if(rx_prop != NULL)
+ {
+ tether_client.ul_src_pipe_len = rx_prop->num_rx_props;
+ for (cnt = 0; cnt < rx_prop->num_rx_props; cnt++)
+ {
+ IPACMDBG_H("Rx(%d), src_pipe: %d, ipa_pipe: %d\n",
+ cnt, rx_prop->rx[cnt].src_pipe,
+ ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe));
+ tether_client.ul_src_pipe_list[cnt] = ioctl(fd, IPA_IOC_QUERY_EP_MAPPING, rx_prop->rx[cnt].src_pipe);
+ }
+ }
+
+ ret = ioctl(fd_wwan_ioctl, WAN_IOC_SET_TETHER_CLIENT_PIPE, &tether_client);
+ if (ret != 0)
+ {
+ IPACMERR("Failed set tether-client-pipe %p with ret %d\n ", &tether_client, ret);
+ }
+ IPACMDBG("Set tether-client-pipe %p\n", &tether_client);
+ close(fd);
+ close(fd_wwan_ioctl);
+ return ret;
+}
+
+/* mac address has to be provided for client related events */
+void IPACM_Lan::eth_bridge_post_event(ipa_cm_event_id evt, ipa_ip_type iptype, uint8_t *mac, uint32_t *ipv6_addr, char *iface_name)
+{
+ ipacm_cmd_q_data eth_bridge_evt;
+ ipacm_event_eth_bridge *evt_data_eth_bridge;
+ const char *eventName = IPACM_Iface::ipacmcfg->getEventName(evt);
+#ifdef FEATURE_L2TP
+ ipacm_event_data_all *evt_data_all;
+#endif
+ if(ipv6_addr)
+ {
+ IPACMDBG_H("IPv6 addr: %08x:%08x:%08x:%08x \n", ipv6_addr[0],
+ ipv6_addr[1], ipv6_addr[2], ipv6_addr[3]);
+ }
+ memset(&eth_bridge_evt, 0, sizeof(ipacm_cmd_q_data));
+ eth_bridge_evt.event = evt;
+
+#ifdef FEATURE_L2TP
+ if(evt == IPA_HANDLE_VLAN_CLIENT_INFO || evt == IPA_HANDLE_VLAN_IFACE_INFO)
+ {
+ evt_data_all = (ipacm_event_data_all*)malloc(sizeof(*evt_data_all));
+ if(evt_data_all == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return;
+ }
+ memset(evt_data_all, 0, sizeof(*evt_data_all));
+
+ if(ipv6_addr)
+ {
+ IPACMDBG_H("IPv6 addr: %08x:%08x:%08x:%08x \n", ipv6_addr[0],
+ ipv6_addr[1], ipv6_addr[2], ipv6_addr[3]);
+ memcpy(evt_data_all->ipv6_addr, ipv6_addr, sizeof(evt_data_all->ipv6_addr));
+ }
+ if(mac)
+ {
+ IPACMDBG_H("Mac: 0x%02x%02x%02x%02x%02x%02x \n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ memcpy(evt_data_all->mac_addr, mac, sizeof(evt_data_all->mac_addr));
+ }
+ if(iface_name)
+ {
+ IPACMDBG_H("Iface: %s\n", iface_name);
+ memcpy(evt_data_all->iface_name, iface_name, sizeof(evt_data_all->iface_name));
+ }
+ eth_bridge_evt.evt_data = (void*)evt_data_all;
+ }
+ else
+#endif
+ {
+ evt_data_eth_bridge = (ipacm_event_eth_bridge*)malloc(sizeof(*evt_data_eth_bridge));
+ if(evt_data_eth_bridge == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return;
+ }
+ memset(evt_data_eth_bridge, 0, sizeof(*evt_data_eth_bridge));
+
+ evt_data_eth_bridge->p_iface = this;
+ evt_data_eth_bridge->iptype = iptype;
+ if(mac)
+ {
+ IPACMDBG_H("Mac: 0x%02x%02x%02x%02x%02x%02x \n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ memcpy(evt_data_eth_bridge->mac_addr, mac, sizeof(evt_data_eth_bridge->mac_addr));
+ }
+ if(iface_name)
+ {
+ IPACMDBG_H("Iface: %s\n", iface_name);
+ memcpy(evt_data_eth_bridge->iface_name, iface_name,
+ sizeof(evt_data_eth_bridge->iface_name));
+ }
+ eth_bridge_evt.evt_data = (void*)evt_data_eth_bridge;
+ }
+ if (eventName != NULL)
+ {
+ IPACMDBG_H("Posting event %s\n",
+ eventName);
+ }
+ IPACM_EvtDispatcher::PostEvt(&eth_bridge_evt);
+}
+
+/* add header processing context and return handle to lan2lan controller */
+int IPACM_Lan::eth_bridge_add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_hdr_type, uint32_t *hdl)
+{
+ int len, res = IPACM_SUCCESS;
+ uint32_t hdr_template;
+ ipa_ioc_add_hdr_proc_ctx* pHeaderProcTable = NULL;
+
+ if(tx_prop == NULL)
+ {
+ IPACMERR("No tx prop.\n");
+ return IPACM_FAILURE;
+ }
+
+ len = sizeof(struct ipa_ioc_add_hdr_proc_ctx) + sizeof(struct ipa_hdr_proc_ctx_add);
+ pHeaderProcTable = (ipa_ioc_add_hdr_proc_ctx*)malloc(len);
+ if(pHeaderProcTable == NULL)
+ {
+ IPACMERR("Cannot allocate header processing context table.\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(pHeaderProcTable, 0, len);
+ pHeaderProcTable->commit = 1;
+ pHeaderProcTable->num_proc_ctxs = 1;
+ pHeaderProcTable->proc_ctx[0].type = eth_bridge_get_hdr_proc_type(peer_l2_hdr_type, tx_prop->tx[0].hdr_l2_type);
+ eth_bridge_get_hdr_template_hdl(&hdr_template);
+ pHeaderProcTable->proc_ctx[0].hdr_hdl = hdr_template;
+ if (m_header.AddHeaderProcCtx(pHeaderProcTable) == false)
+ {
+ IPACMERR("Adding hdr proc ctx failed with status: %d\n", pHeaderProcTable->proc_ctx[0].status);
+ res = IPACM_FAILURE;
+ goto end;
+ }
+
+ *hdl = pHeaderProcTable->proc_ctx[0].proc_ctx_hdl;
+
+end:
+ free(pHeaderProcTable);
+ return res;
+}
+
+/* add routing rule and return handle to lan2lan controller */
+int IPACM_Lan::eth_bridge_add_rt_rule(uint8_t *mac, char *rt_tbl_name, uint32_t hdr_proc_ctx_hdl,
+ ipa_hdr_l2_type peer_l2_hdr_type, ipa_ip_type iptype, uint32_t *rt_rule_hdl, int *rt_rule_count)
+{
+ int len, res = IPACM_SUCCESS;
+ uint32_t i, position, num_rt_rule;
+ struct ipa_ioc_add_rt_rule* rt_rule_table = NULL;
+ struct ipa_rt_rule_add rt_rule;
+
+ IPACMDBG_H("Received client MAC 0x%02x%02x%02x%02x%02x%02x.\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ num_rt_rule = each_client_rt_rule_count[iptype];
+
+ len = sizeof(ipa_ioc_add_rt_rule) + num_rt_rule * sizeof(ipa_rt_rule_add);
+ rt_rule_table = (ipa_ioc_add_rt_rule*)malloc(len);
+ if (rt_rule_table == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memset(rt_rule_table, 0, len);
+
+ rt_rule_table->commit = 1;
+ rt_rule_table->ip = iptype;
+ rt_rule_table->num_rules = num_rt_rule;
+ strlcpy(rt_rule_table->rt_tbl_name, rt_tbl_name, sizeof(rt_rule_table->rt_tbl_name));
+ rt_rule_table->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = 0;
+
+ memset(&rt_rule, 0, sizeof(ipa_rt_rule_add));
+ rt_rule.at_rear = false;
+ rt_rule.status = -1;
+ rt_rule.rt_rule_hdl = -1;
+#ifdef FEATURE_IPA_V3
+ rt_rule.rule.hashable = true;
+#endif
+ rt_rule.rule.hdr_hdl = 0;
+ rt_rule.rule.hdr_proc_ctx_hdl = hdr_proc_ctx_hdl;
+
+ position = 0;
+ for(i=0; i<iface_query->num_tx_props; i++)
+ {
+ if(tx_prop->tx[i].ip == iptype)
+ {
+ if(position >= num_rt_rule || position >= MAX_NUM_PROP)
+ {
+ IPACMERR("Number of routing rules already exceeds limit.\n");
+ res = IPACM_FAILURE;
+ goto end;
+ }
+
+ if(ipa_if_cate == WLAN_IF && IPACM_Iface::ipacmcfg->isMCC_Mode)
+ {
+ IPACMDBG_H("In WLAN MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[i].alt_dst_pipe);
+ rt_rule.rule.dst = tx_prop->tx[i].alt_dst_pipe;
+ }
+ else
+ {
+ IPACMDBG_H("It is not WLAN MCC mode, use dst pipe: %d\n",
+ tx_prop->tx[i].dst_pipe);
+ rt_rule.rule.dst = tx_prop->tx[i].dst_pipe;
+ }
+
+ memcpy(&rt_rule.rule.attrib, &tx_prop->tx[i].attrib, sizeof(rt_rule.rule.attrib));
+ if(peer_l2_hdr_type == IPA_HDR_L2_ETHERNET_II)
+ rt_rule.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+ else
+ rt_rule.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+ memcpy(rt_rule.rule.attrib.dst_mac_addr, mac, sizeof(rt_rule.rule.attrib.dst_mac_addr));
+ memset(rt_rule.rule.attrib.dst_mac_addr_mask, 0xFF, sizeof(rt_rule.rule.attrib.dst_mac_addr_mask));
+
+ memcpy(&(rt_rule_table->rules[position]), &rt_rule, sizeof(rt_rule_table->rules[position]));
+ position++;
+ }
+ }
+ if(false == m_routing.AddRoutingRule(rt_rule_table))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto end;
+ }
+ else
+ {
+ *rt_rule_count = position;
+ for(i=0; i<position; i++)
+ rt_rule_hdl[i] = rt_rule_table->rules[i].rt_rule_hdl;
+ }
+
+end:
+ free(rt_rule_table);
+ return res;
+}
+
+/* modify routing rule*/
+int IPACM_Lan::eth_bridge_modify_rt_rule(uint8_t *mac, uint32_t hdr_proc_ctx_hdl,
+ ipa_hdr_l2_type peer_l2_hdr_type, ipa_ip_type iptype, uint32_t *rt_rule_hdl, int rt_rule_count)
+{
+ struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+ struct ipa_rt_rule_mdfy *rt_rule_entry;
+ int len, res = IPACM_SUCCESS;
+ uint32_t index;
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No tx properties \n");
+ return IPACM_FAILURE;
+ }
+
+ if(ipa_if_cate != WLAN_IF)
+ {
+ IPACMDBG_H("This is not WLAN IF, no need to modify rt rule.\n");
+ return IPACM_SUCCESS;
+ }
+
+ IPACMDBG_H("Receive WLAN client MAC 0x%02x%02x%02x%02x%02x%02x.\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ len = sizeof(struct ipa_ioc_mdfy_rt_rule) + rt_rule_count * sizeof(struct ipa_rt_rule_mdfy);
+ rt_rule = (struct ipa_ioc_mdfy_rt_rule *)malloc(len);
+ if(rt_rule == NULL)
+ {
+ IPACMERR("Unable to allocate memory for modify rt rule\n");
+ return IPACM_FAILURE;
+ }
+ memset(rt_rule, 0, len);
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = 0;
+ rt_rule->ip = iptype;
+
+ for (index = 0; index < tx_prop->num_tx_props; index++)
+ {
+ if (tx_prop->tx[index].ip == iptype)
+ {
+ if (rt_rule->num_rules >= rt_rule_count ||
+ rt_rule->num_rules >= MAX_NUM_PROP)
+ {
+ IPACMERR("Number of routing rules exceeds limit.\n");
+ res = IPACM_FAILURE;
+ goto end;
+ }
+
+ rt_rule_entry = &rt_rule->rules[rt_rule->num_rules];
+
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+ {
+ IPACMDBG_H("In WLAN MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[index].alt_dst_pipe;
+ }
+ else
+ {
+ IPACMDBG_H("In WLAN SCC mode, use dst pipe: %d\n",
+ tx_prop->tx[index].dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[index].dst_pipe;
+ }
+
+ rt_rule_entry->rule.hdr_hdl = 0;
+ rt_rule_entry->rule.hdr_proc_ctx_hdl = hdr_proc_ctx_hdl;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ memcpy(&rt_rule_entry->rule.attrib, &tx_prop->tx[index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ if(peer_l2_hdr_type == IPA_HDR_L2_ETHERNET_II)
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+ else
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+ memcpy(rt_rule_entry->rule.attrib.dst_mac_addr, mac,
+ sizeof(rt_rule_entry->rule.attrib.dst_mac_addr));
+ memset(rt_rule_entry->rule.attrib.dst_mac_addr_mask, 0xFF,
+ sizeof(rt_rule_entry->rule.attrib.dst_mac_addr_mask));
+
+ rt_rule_entry->rt_rule_hdl = rt_rule_hdl[rt_rule->num_rules];
+ rt_rule->num_rules++;
+ }
+ }
+
+ if(m_routing.ModifyRoutingRule(rt_rule) == false)
+ {
+ IPACMERR("Failed to modify routing rules.\n");
+ res = IPACM_FAILURE;
+ goto end;
+ }
+ if(m_routing.Commit(iptype) == false)
+ {
+ IPACMERR("Failed to commit routing rules.\n");
+ res = IPACM_FAILURE;
+ goto end;
+ }
+ IPACMDBG("Modified routing rules successfully.\n");
+
+end:
+ free(rt_rule);
+ return res;
+}
+
+int IPACM_Lan::eth_bridge_add_flt_rule(uint8_t *mac, uint32_t rt_tbl_hdl, ipa_ip_type iptype, uint32_t *flt_rule_hdl)
+{
+ int res = IPACM_SUCCESS;
+
+ IPACMDBG_H("Received client MAC 0x%02x%02x%02x%02x%02x%02x.\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ IPACMDBG_H("Received rt_tbl_hdl :%d iptype %d\n", rt_tbl_hdl,iptype);
+ *flt_rule_hdl = 0;
+
+#ifdef FEATURE_IPA_V3
+ int len;
+ struct ipa_flt_rule_add flt_rule_entry;
+ struct ipa_ioc_add_flt_rule_after *pFilteringTable = NULL;
+
+ if (rx_prop == NULL || tx_prop == NULL)
+ {
+ IPACMDBG_H("No rx or tx properties registered for iface %s\n", dev_name);
+ return IPACM_FAILURE;
+ }
+
+
+ len = sizeof(struct ipa_ioc_add_flt_rule_after) + sizeof(struct ipa_flt_rule_add);
+ pFilteringTable = (struct ipa_ioc_add_flt_rule_after*)malloc(len);
+ if (!pFilteringTable)
+ {
+ IPACMERR("Failed to allocate ipa_ioc_add_flt_rule_after memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable, 0, len);
+
+ /* add mac based rule*/
+ pFilteringTable->commit = 1;
+ pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable->ip = iptype;
+ pFilteringTable->num_rules = 1;
+ pFilteringTable->add_after_hdl = eth_bridge_flt_rule_offset[iptype];
+
+ memset(&flt_rule_entry, 0, sizeof(flt_rule_entry));
+ flt_rule_entry.at_rear = 1;
+
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.rule.rt_tbl_hdl = rt_tbl_hdl;
+ flt_rule_entry.rule.hashable = true;
+
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+ if(tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_ETHERNET_II)
+ {
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+ }
+ else
+ {
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+ }
+
+ memcpy(flt_rule_entry.rule.attrib.dst_mac_addr, mac, sizeof(flt_rule_entry.rule.attrib.dst_mac_addr));
+ memset(flt_rule_entry.rule.attrib.dst_mac_addr_mask, 0xFF, sizeof(flt_rule_entry.rule.attrib.dst_mac_addr_mask));
+
+ memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(flt_rule_entry));
+ if (false == m_filtering.AddFilteringRuleAfter(pFilteringTable))
+ {
+ IPACMERR("Failed to add client filtering rules.\n");
+ res = IPACM_FAILURE;
+ goto end;
+ }
+ *flt_rule_hdl = pFilteringTable->rules[0].flt_rule_hdl;
+
+end:
+ free(pFilteringTable);
+#endif
+ return res;
+}
+
+int IPACM_Lan::eth_bridge_del_flt_rule(uint32_t flt_rule_hdl, ipa_ip_type iptype)
+{
+ if(m_filtering.DeleteFilteringHdls(&flt_rule_hdl, iptype, 1) == false)
+ {
+ IPACMERR("Failed to delete the client specific flt rule.\n");
+ return IPACM_FAILURE;
+ }
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::eth_bridge_del_rt_rule(uint32_t rt_rule_hdl, ipa_ip_type iptype)
+{
+ if(m_routing.DeleteRoutingHdl(rt_rule_hdl, iptype) == false)
+ {
+ IPACMERR("Failed to delete routing rule.\n");
+ return IPACM_FAILURE;
+ }
+ return IPACM_SUCCESS;
+}
+
+/* delete header processing context */
+int IPACM_Lan::eth_bridge_del_hdr_proc_ctx(uint32_t hdr_proc_ctx_hdl)
+{
+ if(m_header.DeleteHeaderProcCtx(hdr_proc_ctx_hdl) == false)
+ {
+ IPACMERR("Failed to delete hdr proc ctx.\n");
+ return IPACM_FAILURE;
+ }
+ return IPACM_SUCCESS;
+}
+
+#ifdef FEATURE_L2TP
+/* check if the event is associated with vlan interface */
+bool IPACM_Lan::is_vlan_event(char *event_iface_name)
+{
+ int self_name_len, event_iface_name_len;
+ if(event_iface_name == NULL)
+ {
+ IPACMERR("Invalid input\n");
+ return false;
+ }
+
+ IPACMDBG_H("Self iface %s, event iface %s\n", dev_name, event_iface_name);
+ self_name_len = strlen(dev_name);
+ event_iface_name_len = strlen(event_iface_name);
+
+ if(event_iface_name_len > self_name_len && strncmp(dev_name, event_iface_name, self_name_len) == 0)
+ {
+ IPACMDBG_H("This is vlan event.\n");
+ return true;
+ }
+ return false;
+}
+
+/* check if the event is associated with l2tp interface */
+bool IPACM_Lan::is_l2tp_event(char *event_iface_name)
+{
+ if(event_iface_name == NULL)
+ {
+ IPACMERR("Invalid input\n");
+ return false;
+ }
+
+ IPACMDBG_H("Self iface %s, event iface %s\n", dev_name, event_iface_name);
+ if(strncmp(event_iface_name, "l2tp", 4) == 0)
+ {
+ IPACMDBG_H("This is l2tp event.\n");
+ return true;
+ }
+ return false;
+}
+
+/* add l2tp rt rule for l2tp client */
+int IPACM_Lan::add_l2tp_rt_rule(ipa_ip_type iptype, uint8_t *dst_mac, ipa_hdr_l2_type peer_l2_hdr_type,
+ uint32_t l2tp_session_id, uint32_t vlan_id, uint8_t *vlan_client_mac, uint32_t *vlan_iface_ipv6_addr,
+ uint32_t *vlan_client_ipv6_addr, uint32_t *first_pass_hdr_hdl, uint32_t *first_pass_hdr_proc_ctx_hdl,
+ uint32_t *second_pass_hdr_hdl, int *num_rt_hdl, uint32_t *first_pass_rt_rule_hdl, uint32_t *second_pass_rt_rule_hdl)
+{
+ int i, size, position;
+ uint32_t tx_index;
+ uint32_t vlan_iface_ipv6_addr_network[4], vlan_client_ipv6_addr_network[4];
+ ipa_ioc_add_hdr *hdr_table;
+ ipa_hdr_add *hdr;
+ ipa_ioc_add_hdr_proc_ctx *hdr_proc_ctx_table;
+ ipa_hdr_proc_ctx_add *hdr_proc_ctx;
+ ipa_ioc_add_rt_rule* rt_rule_table;
+ ipa_rt_rule_add *rt_rule;
+ ipa_ioc_copy_hdr copy_hdr;
+
+ if(tx_prop == NULL)
+ {
+ IPACMERR("No tx prop.\n");
+ return IPACM_FAILURE;
+ }
+
+ /* =========== install first pass hdr template (IPv6 + L2TP + inner ETH header = 62 bytes) ============= */
+ if(*first_pass_hdr_hdl != 0)
+ {
+ IPACMDBG_H("First pass hdr template was added before.\n");
+ }
+ else
+ {
+ size = sizeof(ipa_ioc_add_hdr) + sizeof(ipa_hdr_add);
+ hdr_table = (ipa_ioc_add_hdr*)malloc(size);
+ if(hdr_table == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memset(hdr_table, 0, size);
+
+ hdr_table->commit = 1;
+ hdr_table->num_hdrs = 1;
+ hdr = &hdr_table->hdr[0];
+
+ if(iptype == IPA_IP_v4)
+ {
+ snprintf(hdr->name, sizeof(hdr->name), "vlan_%d_l2tp_%d_v4", vlan_id, l2tp_session_id);
+ }
+ else
+ {
+ snprintf(hdr->name, sizeof(hdr->name), "vlan_%d_l2tp_%d_v6", vlan_id, l2tp_session_id);
+ }
+ hdr->hdr_len = 62;
+ hdr->type = IPA_HDR_L2_ETHERNET_II;
+ hdr->is_partial = 0;
+
+ hdr->hdr[0] = 0x60; /* version */
+ hdr->hdr[6] = 0x73; /* next header = L2TP */
+ hdr->hdr[7] = 0x40; /* hop limit = 64 */
+ for(i = 0; i < 4; i++)
+ {
+ vlan_iface_ipv6_addr_network[i] = htonl(vlan_iface_ipv6_addr[i]);
+ vlan_client_ipv6_addr_network[i] = htonl(vlan_client_ipv6_addr[i]);
+ }
+ memcpy(hdr->hdr + 8, vlan_iface_ipv6_addr_network, 16); /* source IPv6 addr */
+ memcpy(hdr->hdr + 24, vlan_client_ipv6_addr_network, 16); /* dest IPv6 addr */
+ hdr->hdr[43] = (uint8_t)(l2tp_session_id & 0xFF); /* l2tp header */
+ hdr->hdr[42] = (uint8_t)(l2tp_session_id >> 8 & 0xFF);
+ hdr->hdr[41] = (uint8_t)(l2tp_session_id >> 16 & 0xFF);
+ hdr->hdr[40] = (uint8_t)(l2tp_session_id >> 24 & 0xFF);
+
+ if(m_header.AddHeader(hdr_table) == false)
+ {
+ IPACMERR("Failed to add hdr with status: %d\n", hdr_table->hdr[0].status);
+ free(hdr_table);
+ return IPACM_FAILURE;
+ }
+ *first_pass_hdr_hdl = hdr_table->hdr[0].hdr_hdl;
+ IPACMDBG_H("Installed first pass hdr: hdl %d\n", *first_pass_hdr_hdl);
+ free(hdr_table);
+ }
+
+ /* =========== install first pass hdr proc ctx (populate src/dst MAC and Ether type) ============= */
+ size = sizeof(ipa_ioc_add_hdr_proc_ctx) + sizeof(ipa_hdr_proc_ctx_add);
+ hdr_proc_ctx_table = (ipa_ioc_add_hdr_proc_ctx*)malloc(size);
+ if(hdr_proc_ctx_table == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memset(hdr_proc_ctx_table, 0, size);
+
+ hdr_proc_ctx_table->commit = 1;
+ hdr_proc_ctx_table->num_proc_ctxs = 1;
+ hdr_proc_ctx = &hdr_proc_ctx_table->proc_ctx[0];
+
+ hdr_proc_ctx->type = IPA_HDR_PROC_L2TP_HEADER_ADD;
+ hdr_proc_ctx->hdr_hdl = *first_pass_hdr_hdl;
+ hdr_proc_ctx->l2tp_params.hdr_add_param.eth_hdr_retained = 1;
+ hdr_proc_ctx->l2tp_params.hdr_add_param.input_ip_version = iptype;
+ hdr_proc_ctx->l2tp_params.hdr_add_param.output_ip_version = IPA_IP_v6;
+ if(m_header.AddHeaderProcCtx(hdr_proc_ctx_table) == false)
+ {
+ IPACMERR("Failed to add hdr proc ctx with status: %d\n", hdr_proc_ctx_table->proc_ctx[0].status);
+ free(hdr_proc_ctx_table);
+ return IPACM_FAILURE;
+ }
+ *first_pass_hdr_proc_ctx_hdl = hdr_proc_ctx_table->proc_ctx[0].proc_ctx_hdl;
+ IPACMDBG_H("Installed first pass hdr proc ctx: hdl %d\n", *first_pass_hdr_proc_ctx_hdl);
+ free(hdr_proc_ctx_table);
+
+ /* =========== install first pass rt rules (match dst MAC then doing UCP) ============= */
+ *num_rt_hdl = each_client_rt_rule_count[iptype];
+ size = sizeof(ipa_ioc_add_rt_rule) + (*num_rt_hdl) * sizeof(ipa_rt_rule_add);
+ rt_rule_table = (ipa_ioc_add_rt_rule*)malloc(size);
+ if (rt_rule_table == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memset(rt_rule_table, 0, size);
+
+ rt_rule_table->commit = 1;
+ rt_rule_table->ip = iptype;
+ rt_rule_table->num_rules = *num_rt_hdl;
+ snprintf(rt_rule_table->rt_tbl_name, sizeof(rt_rule_table->rt_tbl_name), "l2tp");
+ rt_rule_table->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = 0;
+
+ position = 0;
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if(tx_prop->tx[tx_index].ip == iptype)
+ {
+ if(position >= *num_rt_hdl || position >= MAX_NUM_PROP)
+ {
+ IPACMERR("Number of routing rules already exceeds limit.\n");
+ free(rt_rule_table);
+ return IPACM_FAILURE;
+ }
+
+ rt_rule = &rt_rule_table->rules[position];
+ rt_rule->at_rear = false;
+ rt_rule->status = -1;
+ rt_rule->rt_rule_hdl = -1;
+ rt_rule->rule.hashable = false; //WLAN->ETH direction rules are set to non-hashable to keep consistent with the other direction
+ rt_rule->rule.hdr_hdl = 0;
+ rt_rule->rule.hdr_proc_ctx_hdl = *first_pass_hdr_proc_ctx_hdl;
+ rt_rule->rule.dst = IPA_CLIENT_DUMMY_CONS;
+
+ memcpy(&rt_rule->rule.attrib, &tx_prop->tx[tx_index].attrib, sizeof(rt_rule->rule.attrib));
+ if(peer_l2_hdr_type == IPA_HDR_L2_ETHERNET_II)
+ rt_rule->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+ else
+ rt_rule->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+ memcpy(rt_rule->rule.attrib.dst_mac_addr, dst_mac, sizeof(rt_rule->rule.attrib.dst_mac_addr));
+ memset(rt_rule->rule.attrib.dst_mac_addr_mask, 0xFF, sizeof(rt_rule->rule.attrib.dst_mac_addr_mask));
+ position++;
+ }
+ }
+ if(m_routing.AddRoutingRule(rt_rule_table) == false)
+ {
+ IPACMERR("Failed to add first pass rt rules.\n");
+ free(rt_rule_table);
+ return IPACM_FAILURE;
+ }
+ for(i = 0; i < position; i++)
+ {
+ first_pass_rt_rule_hdl[i] = rt_rule_table->rules[i].rt_rule_hdl;
+ }
+ free(rt_rule_table);
+
+ /* =========== install second pass hdr (Ethernet header with L2TP tag = 18 bytes) ============= */
+ if(*second_pass_hdr_hdl != 0)
+ {
+ IPACMDBG_H("Second pass hdr was added before.\n");
+ }
+ else
+ {
+ size = sizeof(ipa_ioc_add_hdr) + sizeof(ipa_hdr_add);
+ hdr_table = (ipa_ioc_add_hdr*)malloc(size);
+ if(hdr_table == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memset(hdr_table, 0, size);
+
+ hdr_table->commit = 1;
+ hdr_table->num_hdrs = 1;
+ hdr = &hdr_table->hdr[0];
+
+ if(iptype == IPA_IP_v4)
+ {
+ snprintf(hdr->name, sizeof(hdr->name), "vlan_%d_v4", vlan_id);
+ }
+ else
+ {
+ snprintf(hdr->name, sizeof(hdr->name), "vlan_%d_v6", vlan_id);
+ }
+ hdr->type = IPA_HDR_L2_ETHERNET_II;
+ hdr->is_partial = 0;
+ for(tx_index = 0; tx_index < tx_prop->num_tx_props; tx_index++)
+ {
+ if(tx_prop->tx[tx_index].ip == IPA_IP_v6)
+ {
+ memset(&copy_hdr, 0, sizeof(copy_hdr));
+ strlcpy(copy_hdr.name, tx_prop->tx[tx_index].hdr_name,
+ sizeof(copy_hdr.name));
+ IPACMDBG_H("Header name: %s in tx:%d\n", copy_hdr.name, tx_index);
+ if(m_header.CopyHeader(&copy_hdr) == false)
+ {
+ IPACMERR("Failed to get partial header.\n");
+ free(hdr_table);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("Header length: %d\n", copy_hdr.hdr_len);
+ hdr->hdr_len = copy_hdr.hdr_len;
+ memcpy(hdr->hdr, copy_hdr.hdr, hdr->hdr_len);
+ break;
+ }
+ }
+ /* copy vlan client mac */
+ memcpy(hdr->hdr + hdr->hdr_len - 18, vlan_client_mac, 6);
+ hdr->hdr[hdr->hdr_len - 3] = (uint8_t)vlan_id & 0xFF;
+ hdr->hdr[hdr->hdr_len - 4] = (uint8_t)(vlan_id >> 8) & 0xFF;
+
+ if(m_header.AddHeader(hdr_table) == false)
+ {
+ IPACMERR("Failed to add hdr with status: %d\n", hdr->status);
+ free(hdr_table);
+ return IPACM_FAILURE;
+ }
+ *second_pass_hdr_hdl = hdr->hdr_hdl;
+ IPACMDBG_H("Installed second pass hdr: hdl %d\n", *second_pass_hdr_hdl);
+ free(hdr_table);
+ }
+
+ /* =========== install second pass rt rules (match VLAN interface IPv6 address at dst client side) ============= */
+ if(second_pass_rt_rule_hdl[0] != 0)
+ {
+ IPACMDBG_H("Second pass rt rule was added before, return.\n");
+ return IPACM_SUCCESS;
+ }
+
+ *num_rt_hdl = each_client_rt_rule_count[IPA_IP_v6];
+ size = sizeof(ipa_ioc_add_rt_rule) + (*num_rt_hdl) * sizeof(ipa_rt_rule_add);
+ rt_rule_table = (ipa_ioc_add_rt_rule*)malloc(size);
+ if (rt_rule_table == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memset(rt_rule_table, 0, size);
+
+ rt_rule_table->commit = 1;
+ rt_rule_table->ip = IPA_IP_v6;
+ rt_rule_table->num_rules = *num_rt_hdl;
+ snprintf(rt_rule_table->rt_tbl_name, sizeof(rt_rule_table->rt_tbl_name), "l2tp");
+ rt_rule_table->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = 0;
+
+ position = 0;
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if(tx_prop->tx[tx_index].ip == IPA_IP_v6)
+ {
+ if(position >= *num_rt_hdl || position >= MAX_NUM_PROP)
+ {
+ IPACMERR("Number of routing rules already exceeds limit.\n");
+ free(rt_rule_table);
+ return IPACM_FAILURE;
+ }
+
+ rt_rule = &rt_rule_table->rules[position];
+ rt_rule->at_rear = false;
+ rt_rule->status = -1;
+ rt_rule->rt_rule_hdl = -1;
+ rt_rule->rule.hashable = false; //WLAN->ETH direction rules are set to non-hashable to keep consistent with the other direction
+ rt_rule->rule.hdr_hdl = *second_pass_hdr_hdl;
+ rt_rule->rule.hdr_proc_ctx_hdl = 0;
+ rt_rule->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+
+ memcpy(&rt_rule->rule.attrib, &tx_prop->tx[tx_index].attrib, sizeof(rt_rule->rule.attrib));
+ rt_rule->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ memcpy(rt_rule->rule.attrib.u.v6.dst_addr, vlan_client_ipv6_addr,
+ sizeof(rt_rule->rule.attrib.u.v6.dst_addr));
+ memset(rt_rule->rule.attrib.u.v6.dst_addr_mask, 0xFF, sizeof(rt_rule->rule.attrib.u.v6.dst_addr_mask));
+ position++;
+ }
+ }
+ if(m_routing.AddRoutingRule(rt_rule_table) == false)
+ {
+ IPACMERR("Failed to add second pass rt rules.\n");
+ free(rt_rule_table);
+ return IPACM_FAILURE;
+ }
+ for(i = 0; i < position; i++)
+ {
+ second_pass_rt_rule_hdl[i] = rt_rule_table->rules[i].rt_rule_hdl;
+ }
+ free(rt_rule_table);
+
+ return IPACM_SUCCESS;
+}
+
+/* delete l2tp rt rule for l2tp client */
+int IPACM_Lan::del_l2tp_rt_rule(ipa_ip_type iptype, uint32_t first_pass_hdr_hdl, uint32_t first_pass_hdr_proc_ctx_hdl,
+ uint32_t second_pass_hdr_hdl, int num_rt_hdl, uint32_t *first_pass_rt_rule_hdl, uint32_t *second_pass_rt_rule_hdl)
+{
+ int i;
+
+ if(num_rt_hdl < 0)
+ {
+ IPACMERR("Invalid num rt rule: %d\n", num_rt_hdl);
+ return IPACM_FAILURE;
+ }
+
+ for(i = 0; i < num_rt_hdl; i++)
+ {
+ if(first_pass_rt_rule_hdl != NULL)
+ {
+ if(m_routing.DeleteRoutingHdl(first_pass_rt_rule_hdl[i], iptype) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ if(second_pass_rt_rule_hdl != NULL)
+ {
+ if(m_routing.DeleteRoutingHdl(second_pass_rt_rule_hdl[i], IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ }
+
+ if(first_pass_hdr_proc_ctx_hdl != 0)
+ {
+ if(m_header.DeleteHeaderProcCtx(first_pass_hdr_proc_ctx_hdl) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+
+ if(first_pass_hdr_hdl != 0)
+ {
+ if(m_header.DeleteHeaderHdl(first_pass_hdr_hdl) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ if(second_pass_hdr_hdl != 0)
+ {
+ if(m_header.DeleteHeaderHdl(second_pass_hdr_hdl) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* add l2tp rt rule for non l2tp client */
+int IPACM_Lan::add_l2tp_rt_rule(ipa_ip_type iptype, uint8_t *dst_mac, uint32_t *hdr_proc_ctx_hdl,
+ int *num_rt_hdl, uint32_t *rt_rule_hdl)
+{
+ int i, size, position;
+ uint32_t tx_index;
+ ipa_ioc_add_hdr_proc_ctx *hdr_proc_ctx_table;
+ ipa_hdr_proc_ctx_add *hdr_proc_ctx;
+ ipa_ioc_add_rt_rule* rt_rule_table;
+ ipa_rt_rule_add *rt_rule;
+ ipa_ioc_get_hdr hdr;
+
+ if(tx_prop == NULL)
+ {
+ IPACMERR("No tx prop.\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ for(tx_index = 0; tx_index < tx_prop->num_tx_props; tx_index++)
+ {
+ if(tx_prop->tx[tx_index].ip == iptype)
+ {
+ strlcpy(hdr.name, tx_prop->tx[tx_index].hdr_name,
+ sizeof(hdr.name));
+ break;
+ }
+ }
+ if(m_header.GetHeaderHandle(&hdr) == false)
+ {
+ IPACMERR("Failed to get template hdr hdl.\n");
+ return IPACM_FAILURE;
+ }
+
+ /* =========== install hdr proc ctx (uc needs to remove IPv6 + L2TP + inner ETH header = 62 bytes) ============= */
+ if(*hdr_proc_ctx_hdl != 0)
+ {
+ IPACMDBG_H("Hdr proc ctx was added before.\n");
+ }
+ else
+ {
+ size = sizeof(ipa_ioc_add_hdr_proc_ctx) + sizeof(ipa_hdr_proc_ctx_add);
+ hdr_proc_ctx_table = (ipa_ioc_add_hdr_proc_ctx*)malloc(size);
+ if(hdr_proc_ctx_table == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memset(hdr_proc_ctx_table, 0, size);
+
+ hdr_proc_ctx_table->commit = 1;
+ hdr_proc_ctx_table->num_proc_ctxs = 1;
+ hdr_proc_ctx = &hdr_proc_ctx_table->proc_ctx[0];
+
+ hdr_proc_ctx->type = IPA_HDR_PROC_L2TP_HEADER_REMOVE;
+ hdr_proc_ctx->hdr_hdl = hdr.hdl;
+ hdr_proc_ctx->l2tp_params.hdr_remove_param.hdr_len_remove = 62;
+ hdr_proc_ctx->l2tp_params.hdr_remove_param.eth_hdr_retained = 1;
+ if(m_header.AddHeaderProcCtx(hdr_proc_ctx_table) == false)
+ {
+ IPACMERR("Failed to add hdr proc ctx with status: %d\n", hdr_proc_ctx_table->proc_ctx[0].status);
+ free(hdr_proc_ctx_table);
+ return IPACM_FAILURE;
+ }
+ *hdr_proc_ctx_hdl = hdr_proc_ctx_table->proc_ctx[0].proc_ctx_hdl;
+ IPACMDBG_H("Installed hdr proc ctx: hdl %d\n", *hdr_proc_ctx_hdl);
+ free(hdr_proc_ctx_table);
+ }
+
+ /* =========== install rt rules (match dst MAC within 62 bytes header) ============= */
+ *num_rt_hdl = each_client_rt_rule_count[iptype];
+ size = sizeof(ipa_ioc_add_rt_rule) + (*num_rt_hdl) * sizeof(ipa_rt_rule_add);
+ rt_rule_table = (ipa_ioc_add_rt_rule*)malloc(size);
+ if (rt_rule_table == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memset(rt_rule_table, 0, size);
+
+ rt_rule_table->commit = 1;
+ rt_rule_table->ip = iptype;
+ rt_rule_table->num_rules = *num_rt_hdl;
+ snprintf(rt_rule_table->rt_tbl_name, sizeof(rt_rule_table->rt_tbl_name), "l2tp");
+ rt_rule_table->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = 0;
+
+ position = 0;
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if(tx_prop->tx[tx_index].ip == iptype)
+ {
+ if(position >= *num_rt_hdl || position >= MAX_NUM_PROP)
+ {
+ IPACMERR("Number of routing rules already exceeds limit.\n");
+ free(rt_rule_table);
+ return IPACM_FAILURE;
+ }
+
+ rt_rule = &rt_rule_table->rules[position];
+ rt_rule->at_rear = false;
+ rt_rule->status = -1;
+ rt_rule->rt_rule_hdl = -1;
+ rt_rule->rule.hashable = false; //ETH->WLAN direction rules need to be non-hashable due to encapsulation
+
+ rt_rule->rule.hdr_hdl = 0;
+ rt_rule->rule.hdr_proc_ctx_hdl = *hdr_proc_ctx_hdl;
+ rt_rule->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+
+ memcpy(&rt_rule->rule.attrib, &tx_prop->tx[tx_index].attrib, sizeof(rt_rule->rule.attrib));
+
+ rt_rule->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_L2TP;
+ memset(rt_rule->rule.attrib.dst_mac_addr_mask, 0xFF, sizeof(rt_rule->rule.attrib.dst_mac_addr_mask));
+ memcpy(rt_rule->rule.attrib.dst_mac_addr, dst_mac, sizeof(rt_rule->rule.attrib.dst_mac_addr));
+
+ position++;
+ }
+ }
+ if(m_routing.AddRoutingRule(rt_rule_table) == false)
+ {
+ IPACMERR("Failed to add first pass rt rules.\n");
+ free(rt_rule_table);
+ return IPACM_FAILURE;
+ }
+ for(i = 0; i < position; i++)
+ rt_rule_hdl[i] = rt_rule_table->rules[i].rt_rule_hdl;
+
+ free(rt_rule_table);
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Lan::del_l2tp_rt_rule(ipa_ip_type iptype, int num_rt_hdl, uint32_t *rt_rule_hdl)
+{
+ int i;
+
+ if(num_rt_hdl < 0)
+ {
+ IPACMERR("Invalid num rt rule: %d\n", num_rt_hdl);
+ return IPACM_FAILURE;
+ }
+
+ for(i = 0; i < num_rt_hdl; i++)
+ {
+ if(m_routing.DeleteRoutingHdl(rt_rule_hdl[i], iptype) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* add l2tp flt rule on l2tp interface */
+int IPACM_Lan::add_l2tp_flt_rule(uint8_t *dst_mac, uint32_t *flt_rule_hdl)
+{
+ int len;
+ int fd_ipa;
+ struct ipa_flt_rule_add flt_rule_entry;
+ struct ipa_ioc_add_flt_rule_after *pFilteringTable = NULL;
+ ipa_ioc_get_rt_tbl rt_tbl;
+
+#ifdef FEATURE_IPA_V3
+ if (rx_prop == NULL || tx_prop == NULL)
+ {
+ IPACMDBG_H("No rx or tx properties registered for iface %s\n", dev_name);
+ return IPACM_FAILURE;
+ }
+
+ len = sizeof(struct ipa_ioc_add_flt_rule_after) + sizeof(struct ipa_flt_rule_add);
+ pFilteringTable = (struct ipa_ioc_add_flt_rule_after*)malloc(len);
+ if (!pFilteringTable)
+ {
+ IPACMERR("Failed to allocate ipa_ioc_add_flt_rule_after memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable, 0, len);
+
+ pFilteringTable->commit = 1;
+ pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable->ip = IPA_IP_v6;
+ pFilteringTable->num_rules = 1;
+ pFilteringTable->add_after_hdl = eth_bridge_flt_rule_offset[IPA_IP_v6];
+
+ fd_ipa = open(IPA_DEVICE_NAME, O_RDWR);
+ if(fd_ipa == 0)
+ {
+ IPACMERR("Failed to open %s\n",IPA_DEVICE_NAME);
+ free(pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ rt_tbl.ip = IPA_IP_v6;
+ snprintf(rt_tbl.name, sizeof(rt_tbl.name), "l2tp");
+ rt_tbl.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ IPACMDBG_H("This flt rule points to rt tbl %s.\n", rt_tbl.name);
+ if(m_routing.GetRoutingTable(&rt_tbl) == false)
+ {
+ IPACMERR("Failed to get routing table from name\n");
+ free(pFilteringTable);
+ close(fd_ipa);
+ return IPACM_FAILURE;
+ }
+
+ memset(&flt_rule_entry, 0, sizeof(flt_rule_entry));
+ flt_rule_entry.at_rear = 1;
+
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.rule.rt_tbl_hdl = rt_tbl.hdl;
+ flt_rule_entry.rule.hashable = false; //ETH->WLAN direction rules need to be non-hashable due to encapsulation
+
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+
+ /* flt rule is matching dst MAC within 62 bytes header */
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_L2TP;
+ memset(flt_rule_entry.rule.attrib.dst_mac_addr_mask, 0xFF, sizeof(flt_rule_entry.rule.attrib.dst_mac_addr_mask));
+ memcpy(flt_rule_entry.rule.attrib.dst_mac_addr, dst_mac, sizeof(flt_rule_entry.rule.attrib.dst_mac_addr));
+
+ memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(flt_rule_entry));
+ if(m_filtering.AddFilteringRuleAfter(pFilteringTable) == false)
+ {
+ IPACMERR("Failed to add client filtering rules.\n");
+ free(pFilteringTable);
+ close(fd_ipa);
+ return IPACM_FAILURE;
+ }
+ *flt_rule_hdl = pFilteringTable->rules[0].flt_rule_hdl;
+
+ free(pFilteringTable);
+ close(fd_ipa);
+#endif
+ return IPACM_SUCCESS;
+}
+
+/* delete l2tp flt rule on l2tp interface */
+int IPACM_Lan::del_l2tp_flt_rule(uint32_t flt_rule_hdl)
+{
+ if(m_filtering.DeleteFilteringHdls(&flt_rule_hdl, IPA_IP_v6, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* add l2tp flt rule on non l2tp interface */
+int IPACM_Lan::add_l2tp_flt_rule(ipa_ip_type iptype, uint8_t *dst_mac, uint32_t *vlan_client_ipv6_addr,
+ uint32_t *first_pass_flt_rule_hdl, uint32_t *second_pass_flt_rule_hdl)
+{
+ int len;
+ struct ipa_flt_rule_add flt_rule_entry;
+ struct ipa_ioc_add_flt_rule_after *pFilteringTable = NULL;
+ ipa_ioc_get_rt_tbl rt_tbl;
+
+#ifdef FEATURE_IPA_V3
+ if (rx_prop == NULL || tx_prop == NULL)
+ {
+ IPACMDBG_H("No rx or tx properties registered for iface %s\n", dev_name);
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("Dst client MAC 0x%02x%02x%02x%02x%02x%02x.\n", dst_mac[0], dst_mac[1],
+ dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5]);
+
+ len = sizeof(struct ipa_ioc_add_flt_rule_after) + sizeof(struct ipa_flt_rule_add);
+ pFilteringTable = (struct ipa_ioc_add_flt_rule_after*)malloc(len);
+ if (!pFilteringTable)
+ {
+ IPACMERR("Failed to allocate ipa_ioc_add_flt_rule_after memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable, 0, len);
+
+ pFilteringTable->commit = 1;
+ pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable->ip = iptype;
+ pFilteringTable->num_rules = 1;
+ pFilteringTable->add_after_hdl = eth_bridge_flt_rule_offset[iptype];
+
+ /* =========== add first pass flt rule (match dst MAC) ============= */
+ rt_tbl.ip = iptype;
+ snprintf(rt_tbl.name, sizeof(rt_tbl.name), "l2tp");
+ IPACMDBG_H("This flt rule points to rt tbl %s.\n", rt_tbl.name);
+
+ if(m_routing.GetRoutingTable(&rt_tbl) == false)
+ {
+ IPACMERR("Failed to get routing table.\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(&flt_rule_entry, 0, sizeof(flt_rule_entry));
+ flt_rule_entry.at_rear = 1;
+
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.rule.rt_tbl_hdl = rt_tbl.hdl;
+ flt_rule_entry.rule.hashable = false; //WLAN->ETH direction rules are set to non-hashable to keep consistent with the other direction
+
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+ if(tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_ETHERNET_II)
+ {
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+ }
+ else
+ {
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+ }
+
+ memcpy(flt_rule_entry.rule.attrib.dst_mac_addr, dst_mac, sizeof(flt_rule_entry.rule.attrib.dst_mac_addr));
+ memset(flt_rule_entry.rule.attrib.dst_mac_addr_mask, 0xFF, sizeof(flt_rule_entry.rule.attrib.dst_mac_addr_mask));
+
+ memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(flt_rule_entry));
+ if (false == m_filtering.AddFilteringRuleAfter(pFilteringTable))
+ {
+ IPACMERR("Failed to add first pass filtering rules.\n");
+ free(pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ *first_pass_flt_rule_hdl = pFilteringTable->rules[0].flt_rule_hdl;
+
+ /* =========== add second pass flt rule (match VLAN interface IPv6 address at client side) ============= */
+ if(*second_pass_flt_rule_hdl != 0)
+ {
+ IPACMDBG_H("Second pass flt rule was added before, return.\n");
+ free(pFilteringTable);
+ return IPACM_SUCCESS;
+ }
+
+ rt_tbl.ip = IPA_IP_v6;
+ snprintf(rt_tbl.name, sizeof(rt_tbl.name), "l2tp");
+ IPACMDBG_H("This flt rule points to rt tbl %s.\n", rt_tbl.name);
+
+ if(m_routing.GetRoutingTable(&rt_tbl) == false)
+ {
+ IPACMERR("Failed to get routing table.\n");
+ return IPACM_FAILURE;
+ }
+
+ pFilteringTable->ip = IPA_IP_v6;
+ pFilteringTable->add_after_hdl = eth_bridge_flt_rule_offset[IPA_IP_v6];
+
+ memset(&flt_rule_entry, 0, sizeof(flt_rule_entry));
+ flt_rule_entry.at_rear = 1;
+
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.rule.rt_tbl_hdl = rt_tbl.hdl;
+ flt_rule_entry.rule.hashable = false; //WLAN->ETH direction rules are set to non-hashable to keep consistent with the other direction
+
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+ memcpy(flt_rule_entry.rule.attrib.u.v6.dst_addr, vlan_client_ipv6_addr, sizeof(flt_rule_entry.rule.attrib.u.v6.dst_addr));
+ memset(flt_rule_entry.rule.attrib.u.v6.dst_addr_mask, 0xFF, sizeof(flt_rule_entry.rule.attrib.u.v6.dst_addr_mask));
+
+ memcpy(&(pFilteringTable->rules[0]), &flt_rule_entry, sizeof(flt_rule_entry));
+ if (false == m_filtering.AddFilteringRuleAfter(pFilteringTable))
+ {
+ IPACMERR("Failed to add client filtering rules.\n");
+ free(pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ *second_pass_flt_rule_hdl = pFilteringTable->rules[0].flt_rule_hdl;
+
+ free(pFilteringTable);
+#endif
+ return IPACM_SUCCESS;
+}
+
+/* delete l2tp flt rule on non l2tp interface */
+int IPACM_Lan::del_l2tp_flt_rule(ipa_ip_type iptype, uint32_t first_pass_flt_rule_hdl, uint32_t second_pass_flt_rule_hdl)
+{
+ if(first_pass_flt_rule_hdl != 0)
+ {
+ if(m_filtering.DeleteFilteringHdls(&first_pass_flt_rule_hdl, iptype, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+
+ if(second_pass_flt_rule_hdl != 0)
+ {
+ if(m_filtering.DeleteFilteringHdls(&second_pass_flt_rule_hdl, iptype, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+bool IPACM_Lan::is_unique_local_ipv6_addr(uint32_t* ipv6_addr)
+{
+ uint32_t ipv6_unique_local_prefix, ipv6_unique_local_prefix_mask;
+
+ if(ipv6_addr == NULL)
+ {
+ IPACMERR("IPv6 address is empty.\n");
+ return false;
+ }
+ IPACMDBG_H("Get ipv6 address with first word 0x%08x.\n", ipv6_addr[0]);
+
+ ipv6_unique_local_prefix = 0xFD000000;
+ ipv6_unique_local_prefix_mask = 0xFF000000;
+ if((ipv6_addr[0] & ipv6_unique_local_prefix_mask) == (ipv6_unique_local_prefix & ipv6_unique_local_prefix_mask))
+ {
+ IPACMDBG_H("This IPv6 address is unique local IPv6 address.\n");
+ return true;
+ }
+ return false;
+}
+#endif
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_LanToLan.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_LanToLan.cpp
new file mode 100644
index 0000000..092af64
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_LanToLan.cpp
@@ -0,0 +1,2081 @@
+/*
+Copyright (c) 2014-2017, 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_LanToLan.cpp
+
+ @brief
+ This file implements the functionality of offloading LAN to LAN traffic.
+
+ @Author
+ Shihuan Liu
+
+*/
+
+#include <stdlib.h>
+#include "IPACM_LanToLan.h"
+#include "IPACM_Wlan.h"
+
+#define __stringify(x...) #x
+
+const char *ipa_l2_hdr_type[] = {
+ __stringify(NONE),
+ __stringify(ETH_II),
+ __stringify(802_3),
+ __stringify(L2_MAX)
+};
+
+IPACM_LanToLan* IPACM_LanToLan::p_instance;
+
+IPACM_LanToLan_Iface::IPACM_LanToLan_Iface(IPACM_Lan *p_iface)
+{
+ int i;
+
+ m_p_iface = p_iface;
+ memset(m_is_ip_addr_assigned, 0, sizeof(m_is_ip_addr_assigned));
+ m_support_inter_iface_offload = true;
+ m_support_intra_iface_offload = false;
+ m_is_l2tp_iface = false;
+ for(i = 0; i < IPA_HDR_L2_MAX; i++)
+ {
+ ref_cnt_peer_l2_hdr_type[i] = 0;
+ hdr_proc_ctx_for_inter_interface[i] = 0;
+ }
+ hdr_proc_ctx_for_intra_interface = 0;
+ hdr_proc_ctx_for_l2tp = 0;
+
+ if(p_iface->ipa_if_cate == WLAN_IF)
+ {
+ IPACMDBG_H("Interface %s is WLAN interface.\n", p_iface->dev_name);
+ m_support_intra_iface_offload = true;
+ if( ((IPACM_Wlan*)p_iface)->is_guest_ap() )
+ {
+ IPACMDBG_H("Interface %s is guest AP.\n", p_iface->dev_name);
+ m_support_inter_iface_offload = false;
+ }
+ }
+ return;
+}
+
+IPACM_LanToLan_Iface::~IPACM_LanToLan_Iface()
+{
+}
+
+IPACM_LanToLan::IPACM_LanToLan()
+{
+ IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_IFACE_UP, this);
+ IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_IFACE_DOWN, this);
+ IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_CLIENT_ADD, this);
+ IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_CLIENT_DEL, this);
+ IPACM_EvtDispatcher::registr(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH, this);
+#ifdef FEATURE_L2TP
+ IPACM_EvtDispatcher::registr(IPA_ADD_VLAN_IFACE, this);
+ IPACM_EvtDispatcher::registr(IPA_DEL_VLAN_IFACE, this);
+ IPACM_EvtDispatcher::registr(IPA_ADD_L2TP_VLAN_MAPPING, this);
+ IPACM_EvtDispatcher::registr(IPA_DEL_L2TP_VLAN_MAPPING, this);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_VLAN_CLIENT_INFO, this);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_VLAN_IFACE_INFO, this);
+#endif
+ m_has_l2tp_iface = false;
+ return;
+}
+
+IPACM_LanToLan::~IPACM_LanToLan()
+{
+ IPACMDBG_DMESG("WARNING: UNEXPECTEDLY KILL LAN2LAN CONTROLLER!\n");
+ return;
+}
+
+IPACM_LanToLan* IPACM_LanToLan::get_instance()
+{
+ if(p_instance == NULL)
+ {
+ p_instance = new IPACM_LanToLan();
+ IPACMDBG_H("Created LanToLan instance.\n");
+ }
+ return p_instance;
+}
+
+#ifdef FEATURE_L2TP
+bool IPACM_LanToLan::has_l2tp_iface()
+{
+ list<IPACM_LanToLan_Iface>::iterator it;
+ bool has_l2tp_iface = false;
+
+ for(it = m_iface.begin(); it != m_iface.end(); it++)
+ {
+ if(it->is_l2tp_iface() == true)
+ {
+ has_l2tp_iface = true;
+ break;
+ }
+ }
+ return has_l2tp_iface;
+}
+#endif
+
+void IPACM_LanToLan::event_callback(ipa_cm_event_id event, void* param)
+{
+ ipacm_event_eth_bridge *eth_bridge_data;
+ ipa_ioc_vlan_iface_info *vlan_iface_data;
+
+#ifdef FEATURE_L2TP
+ ipa_ioc_l2tp_vlan_mapping_info *l2tp_vlan_mapping_data;
+#endif
+ ipacm_event_data_all *vlan_data;
+
+ IPACMDBG_H("Get %s event.\n", IPACM_Iface::ipacmcfg->getEventName(event));
+
+ switch(event)
+ {
+ case IPA_ETH_BRIDGE_IFACE_UP:
+ {
+ eth_bridge_data = (ipacm_event_eth_bridge*)param;
+ handle_iface_up(eth_bridge_data);
+ break;
+ }
+
+ case IPA_ETH_BRIDGE_IFACE_DOWN:
+ {
+ eth_bridge_data = (ipacm_event_eth_bridge*)param;
+ handle_iface_down(eth_bridge_data);
+ break;
+ }
+
+ case IPA_ETH_BRIDGE_CLIENT_ADD:
+ {
+ eth_bridge_data = (ipacm_event_eth_bridge*)param;
+ handle_client_add(eth_bridge_data);
+ break;
+ }
+
+ case IPA_ETH_BRIDGE_CLIENT_DEL:
+ {
+ eth_bridge_data = (ipacm_event_eth_bridge*)param;
+ handle_client_del(eth_bridge_data);
+ break;
+ }
+
+ case IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH:
+ {
+ eth_bridge_data = (ipacm_event_eth_bridge*)param;
+ handle_wlan_scc_mcc_switch(eth_bridge_data);
+ break;
+ }
+
+#ifdef FEATURE_L2TP
+ case IPA_ADD_VLAN_IFACE:
+ {
+ vlan_iface_data = (ipa_ioc_vlan_iface_info*)param;
+ handle_add_vlan_iface(vlan_iface_data);
+ break;
+ }
+
+ case IPA_DEL_VLAN_IFACE:
+ {
+ vlan_iface_data = (ipa_ioc_vlan_iface_info*)param;
+ handle_del_vlan_iface(vlan_iface_data);
+ break;
+ }
+ case IPA_ADD_L2TP_VLAN_MAPPING:
+ {
+ l2tp_vlan_mapping_data = (ipa_ioc_l2tp_vlan_mapping_info*)param;
+ handle_add_l2tp_vlan_mapping(l2tp_vlan_mapping_data);
+ break;
+ }
+ case IPA_DEL_L2TP_VLAN_MAPPING:
+ {
+ l2tp_vlan_mapping_data = (ipa_ioc_l2tp_vlan_mapping_info*)param;
+ handle_del_l2tp_vlan_mapping(l2tp_vlan_mapping_data);
+ break;
+ }
+ case IPA_HANDLE_VLAN_CLIENT_INFO:
+ {
+ vlan_data = (ipacm_event_data_all*)param;
+ handle_vlan_client_info(vlan_data);
+ break;
+ }
+ case IPA_HANDLE_VLAN_IFACE_INFO:
+ {
+ vlan_data = (ipacm_event_data_all*)param;
+ handle_vlan_iface_info(vlan_data);
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+
+ print_data_structure_info();
+ return;
+}
+
+void IPACM_LanToLan::handle_iface_up(ipacm_event_eth_bridge *data)
+{
+ list<IPACM_LanToLan_Iface>::iterator it;
+ list<l2tp_vlan_mapping_info>::iterator it_mapping;
+ bool has_l2tp_iface = false;
+
+ IPACMDBG_H("Interface name: %s IP type: %d\n", data->p_iface->dev_name, data->iptype);
+ for(it = m_iface.begin(); it != m_iface.end(); it++)
+ {
+ if(it->get_iface_pointer() == data->p_iface)
+ {
+ IPACMDBG_H("Found the interface.\n");
+ if(it->get_m_is_ip_addr_assigned(data->iptype) == false)
+ {
+ IPACMDBG_H("IP type %d was not active before, activating it now.\n", data->iptype);
+ it->set_m_is_ip_addr_assigned(data->iptype, true);
+
+ /* install inter-interface rules */
+ if(it->get_m_support_inter_iface_offload())
+ it->add_all_inter_interface_client_flt_rule(data->iptype);
+
+ /* install intra-BSS rules */
+ if(it->get_m_support_intra_iface_offload())
+ it->add_all_intra_interface_client_flt_rule(data->iptype);
+ }
+ break;
+ }
+ }
+
+ if(it == m_iface.end()) //If the interface has not been created before
+ {
+ if(m_iface.size() == MAX_NUM_IFACE)
+ {
+ IPACMERR("The number of interfaces has reached maximum %d.\n", MAX_NUM_IFACE);
+ return;
+ }
+
+ if(!data->p_iface->tx_prop || !data->p_iface->rx_prop)
+ {
+ IPACMERR("The interface %s does not have tx_prop or rx_prop.\n", data->p_iface->dev_name);
+ return;
+ }
+
+ if(data->p_iface->tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_NONE || data->p_iface->tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_MAX)
+ {
+ IPACMERR("Invalid l2 header type %s!\n", ipa_l2_hdr_type[data->p_iface->tx_prop->tx[0].hdr_l2_type]);
+ return;
+ }
+
+ IPACMDBG_H("Does not find the interface, insert a new one.\n");
+ IPACM_LanToLan_Iface new_iface(data->p_iface);
+ new_iface.set_m_is_ip_addr_assigned(data->iptype, true);
+
+ m_iface.push_front(new_iface);
+ IPACMDBG_H("Now the total number of interfaces is %d.\n", m_iface.size());
+
+ IPACM_LanToLan_Iface &front_iface = m_iface.front();
+#ifdef FEATURE_L2TP
+ for(it_mapping = m_l2tp_vlan_mapping.begin(); it_mapping != m_l2tp_vlan_mapping.end(); it_mapping++)
+ {
+ if(front_iface.set_l2tp_iface(it_mapping->vlan_iface_name) == true)
+ {
+ has_l2tp_iface = true;
+ }
+ }
+
+ if(m_has_l2tp_iface == false && has_l2tp_iface == true)
+ {
+ IPACMDBG_H("There is l2tp iface, add rt rules for l2tp iface.\n");
+ m_has_l2tp_iface = true;
+ for(it = ++m_iface.begin(); it != m_iface.end(); it++)
+ {
+ if(it->is_l2tp_iface() == false)
+ {
+ it->handle_l2tp_enable();
+ }
+ }
+ }
+#endif
+ /* install inter-interface rules */
+ if(front_iface.get_m_support_inter_iface_offload())
+ {
+ for(it = ++m_iface.begin(); it != m_iface.end(); it++)
+ {
+ /* add peer info only when both interfaces support inter-interface communication */
+ if(it->get_m_support_inter_iface_offload())
+ {
+ /* populate hdr_proc_ctx and routing table handle */
+ handle_new_iface_up(&front_iface, &(*it));
+
+ /* add client specific routing rule on existing interface */
+ it->add_client_rt_rule_for_new_iface();
+ }
+ }
+
+ /* add client specific filtering rule on new interface */
+ front_iface.add_all_inter_interface_client_flt_rule(data->iptype);
+ }
+
+ /* populate the intra-interface information */
+ if(front_iface.get_m_support_intra_iface_offload())
+ {
+ front_iface.handle_intra_interface_info();
+ }
+
+ /* handle cached client add event */
+ handle_cached_client_add_event(front_iface.get_iface_pointer());
+ }
+ return;
+}
+
+void IPACM_LanToLan::handle_iface_down(ipacm_event_eth_bridge *data)
+{
+ list<IPACM_LanToLan_Iface>::iterator it_target_iface;
+ bool has_l2tp_iface = false;
+
+ IPACMDBG_H("Interface name: %s\n", data->p_iface->dev_name);
+
+ for(it_target_iface = m_iface.begin(); it_target_iface != m_iface.end(); it_target_iface++)
+ {
+ if(it_target_iface->get_iface_pointer() == data->p_iface)
+ {
+ IPACMDBG_H("Found the interface.\n");
+ break;
+ }
+ }
+
+ if(it_target_iface == m_iface.end())
+ {
+ IPACMDBG_H("The interface has not been found.\n");
+ /* clear cached client add event for the unfound interface*/
+ clear_cached_client_add_event(data->p_iface);
+ return;
+ }
+
+ it_target_iface->handle_down_event();
+ m_iface.erase(it_target_iface);
+#ifdef FEATURE_L2TP
+ for(it_target_iface = m_iface.begin(); it_target_iface != m_iface.end(); it_target_iface++)
+ {
+ if(it_target_iface->is_l2tp_iface() == true)
+ {
+ has_l2tp_iface = true;
+ break;
+ }
+ }
+ if(m_has_l2tp_iface == true && has_l2tp_iface == false)
+ {
+ IPACMDBG_H("There is no l2tp iface now, delete rt rules for l2tp iface.\n");
+ m_has_l2tp_iface = false;
+ for(it_target_iface = m_iface.begin(); it_target_iface != m_iface.end(); it_target_iface++)
+ {
+ if(it_target_iface->is_l2tp_iface() == false)
+ {
+ it_target_iface->handle_l2tp_disable();
+ }
+ }
+ }
+#endif
+ return;
+}
+
+void IPACM_LanToLan::handle_new_iface_up(IPACM_LanToLan_Iface *new_iface, IPACM_LanToLan_Iface *exist_iface)
+{
+ char rt_tbl_name_for_flt[IPA_IP_MAX][IPA_RESOURCE_NAME_MAX];
+ char rt_tbl_name_for_rt[IPA_IP_MAX][IPA_RESOURCE_NAME_MAX];
+
+ IPACMDBG_H("Populate peer info between: new_iface %s, existing iface %s\n", new_iface->get_iface_pointer()->dev_name,
+ exist_iface->get_iface_pointer()->dev_name);
+
+ /* populate the routing table information */
+ snprintf(rt_tbl_name_for_flt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX, "eth_v4_%s_to_%s",
+ ipa_l2_hdr_type[exist_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type],
+ ipa_l2_hdr_type[new_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type]);
+ IPACMDBG_H("IPv4 routing table for flt name: %s\n", rt_tbl_name_for_flt[IPA_IP_v4]);
+
+ snprintf(rt_tbl_name_for_flt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX, "eth_v6_%s_to_%s",
+ ipa_l2_hdr_type[exist_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type],
+ ipa_l2_hdr_type[new_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type]);
+ IPACMDBG_H("IPv6 routing table for flt name: %s\n", rt_tbl_name_for_flt[IPA_IP_v6]);
+
+ snprintf(rt_tbl_name_for_rt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX, "eth_v4_%s_to_%s",
+ ipa_l2_hdr_type[new_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type],
+ ipa_l2_hdr_type[exist_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type]);
+ IPACMDBG_H("IPv4 routing table for rt name: %s\n", rt_tbl_name_for_rt[IPA_IP_v4]);
+
+ snprintf(rt_tbl_name_for_rt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX, "eth_v6_%s_to_%s",
+ ipa_l2_hdr_type[new_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type],
+ ipa_l2_hdr_type[exist_iface->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type]);
+ IPACMDBG_H("IPv6 routing table for rt name: %s\n", rt_tbl_name_for_rt[IPA_IP_v6]);
+
+ /* add new peer info in both new iface and existing iface */
+ exist_iface->handle_new_iface_up(rt_tbl_name_for_flt, rt_tbl_name_for_rt, new_iface);
+
+ new_iface->handle_new_iface_up(rt_tbl_name_for_rt, rt_tbl_name_for_flt, exist_iface);
+
+ return;
+}
+
+void IPACM_LanToLan::handle_client_add(ipacm_event_eth_bridge *data)
+{
+ list<IPACM_LanToLan_Iface>::iterator it_iface;
+ list<l2tp_vlan_mapping_info>::iterator it_mapping;
+ l2tp_vlan_mapping_info *mapping_info = NULL;
+ bool is_l2tp_client = false;
+
+ IPACMDBG_H("Incoming client MAC: 0x%02x%02x%02x%02x%02x%02x, interface: %s\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], data->p_iface->dev_name);
+#ifdef FEATURE_L2TP
+ for(it_mapping = m_l2tp_vlan_mapping.begin(); it_mapping != m_l2tp_vlan_mapping.end(); it_mapping++)
+ {
+ if(strncmp(it_mapping->l2tp_iface_name, data->iface_name,
+ sizeof(it_mapping->l2tp_iface_name)) == 0)
+ {
+ IPACMDBG_H("Found l2tp iface %s with l2tp client MAC 0x%02x%02x%02x%02x%02x%02x\n",
+ it_mapping->l2tp_iface_name, it_mapping->l2tp_client_mac[0], it_mapping->l2tp_client_mac[1],
+ it_mapping->l2tp_client_mac[2], it_mapping->l2tp_client_mac[3], it_mapping->l2tp_client_mac[4],
+ it_mapping->l2tp_client_mac[5]);
+ memcpy(it_mapping->l2tp_client_mac, data->mac_addr, sizeof(it_mapping->l2tp_client_mac));
+ mapping_info = &(*it_mapping);
+ is_l2tp_client = true;
+ break;
+ }
+ }
+#endif
+ for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
+ {
+ if(it_iface->get_iface_pointer() == data->p_iface) //find the interface
+ {
+ IPACMDBG_H("Found the interface.\n");
+ it_iface->handle_client_add(data->mac_addr, is_l2tp_client, mapping_info);
+ break;
+ }
+ }
+
+ /* if the iface was not found, cache the client add event */
+ if(it_iface == m_iface.end())
+ {
+ IPACMDBG_H("The interface is not found.\n");
+ if(m_cached_client_add_event.size() < MAX_NUM_CACHED_CLIENT_ADD_EVENT)
+ {
+ IPACMDBG_H("Cached the client information.\n");
+ m_cached_client_add_event.push_front(*data);
+ }
+ else
+ {
+ IPACMDBG_H("Cached client add event has reached maximum number.\n");
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan::handle_client_del(ipacm_event_eth_bridge *data)
+{
+ list<IPACM_LanToLan_Iface>::iterator it_iface;
+
+ IPACMDBG_H("Incoming client MAC: 0x%02x%02x%02x%02x%02x%02x, interface: %s\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], data->p_iface->dev_name);
+
+ for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
+ {
+ if(it_iface->get_iface_pointer() == data->p_iface) //found the interface
+ {
+ IPACMDBG_H("Found the interface.\n");
+ it_iface->handle_client_del(data->mac_addr);
+ break;
+ }
+ }
+
+ if(it_iface == m_iface.end())
+ {
+ IPACMDBG_H("The interface is not found.\n");
+ }
+
+ return;
+}
+
+void IPACM_LanToLan::handle_wlan_scc_mcc_switch(ipacm_event_eth_bridge *data)
+{
+ list<IPACM_LanToLan_Iface>::iterator it_iface;
+
+ IPACMDBG_H("Incoming interface: %s\n", data->p_iface->dev_name);
+ for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
+ {
+ if(it_iface->get_iface_pointer() == data->p_iface)
+ {
+ it_iface->handle_wlan_scc_mcc_switch();
+ break;
+ }
+ }
+ return;
+}
+
+#ifdef FEATURE_L2TP
+void IPACM_LanToLan::handle_add_vlan_iface(ipa_ioc_vlan_iface_info *data)
+{
+ list<vlan_iface_info>::iterator it_vlan;
+ list<l2tp_vlan_mapping_info>::iterator it_mapping;
+ vlan_iface_info new_vlan_info;
+
+ IPACMDBG_H("Vlan iface: %s vlan id: %d\n", data->name, data->vlan_id);
+ for(it_vlan = m_vlan_iface.begin(); it_vlan != m_vlan_iface.end(); it_vlan++)
+ {
+ if(strncmp(it_vlan->vlan_iface_name, data->name, sizeof(it_vlan->vlan_iface_name)) == 0)
+ {
+ IPACMERR("The vlan iface was added before with id %d\n", it_vlan->vlan_id);
+ return;
+ }
+ }
+
+ for(it_mapping = m_l2tp_vlan_mapping.begin(); it_mapping != m_l2tp_vlan_mapping.end(); it_mapping++)
+ {
+ if(strncmp(data->name, it_mapping->vlan_iface_name, sizeof(data->name)) == 0)
+ {
+ IPACMDBG_H("Found a mapping: l2tp iface %s.\n", it_mapping->l2tp_iface_name);
+ it_mapping->vlan_id = data->vlan_id;
+ }
+ }
+
+ memset(&new_vlan_info, 0 , sizeof(new_vlan_info));
+ strlcpy(new_vlan_info.vlan_iface_name, data->name, sizeof(new_vlan_info.vlan_iface_name));
+ new_vlan_info.vlan_id = data->vlan_id;
+ m_vlan_iface.push_front(new_vlan_info);
+ return;
+}
+
+void IPACM_LanToLan::handle_del_vlan_iface(ipa_ioc_vlan_iface_info *data)
+{
+ list<vlan_iface_info>::iterator it_vlan;
+ list<l2tp_vlan_mapping_info>::iterator it_mapping;
+
+ IPACMDBG_H("Vlan iface: %s vlan id: %d\n", data->name, data->vlan_id);
+ for(it_vlan = m_vlan_iface.begin(); it_vlan != m_vlan_iface.end(); it_vlan++)
+ {
+ if(strncmp(it_vlan->vlan_iface_name, data->name, sizeof(it_vlan->vlan_iface_name)) == 0)
+ {
+ IPACMDBG_H("Found the vlan interface\n");
+ m_vlan_iface.erase(it_vlan);
+ break;
+ }
+ }
+
+ it_mapping = m_l2tp_vlan_mapping.begin();
+ while(it_mapping != m_l2tp_vlan_mapping.end())
+ {
+ if(strncmp(data->name, it_mapping->vlan_iface_name, sizeof(data->name)) == 0)
+ {
+ IPACMDBG_H("Delete mapping with l2tp iface %s\n", it_mapping->l2tp_iface_name);
+ it_mapping = m_l2tp_vlan_mapping.erase(it_mapping);
+ }
+ else
+ {
+ it_mapping++;
+ }
+ }
+ return;
+}
+void IPACM_LanToLan::handle_add_l2tp_vlan_mapping(ipa_ioc_l2tp_vlan_mapping_info *data)
+{
+ list<l2tp_vlan_mapping_info>::iterator it_mapping;
+ list<vlan_iface_info>::iterator it_vlan;
+ list<IPACM_LanToLan_Iface>::iterator it_iface;
+ l2tp_vlan_mapping_info new_mapping;
+ bool has_l2tp_iface = false;
+
+ IPACMDBG_H("L2tp iface: %s session id: %d vlan iface: %s \n",
+ data->l2tp_iface_name, data->l2tp_session_id, data->vlan_iface_name);
+ for(it_mapping = m_l2tp_vlan_mapping.begin(); it_mapping != m_l2tp_vlan_mapping.end(); it_mapping++)
+ {
+ if(strncmp(data->l2tp_iface_name, it_mapping->l2tp_iface_name,
+ sizeof(data->l2tp_iface_name)) == 0)
+ {
+ IPACMERR("L2tp mapping was added before mapped to vlan %s.\n", it_mapping->vlan_iface_name);
+ return;
+ }
+ }
+ memset(&new_mapping, 0, sizeof(new_mapping));
+ strlcpy(new_mapping.l2tp_iface_name, data->l2tp_iface_name,
+ sizeof(new_mapping.l2tp_iface_name));
+ strlcpy(new_mapping.vlan_iface_name, data->vlan_iface_name,
+ sizeof(new_mapping.vlan_iface_name));
+ new_mapping.l2tp_session_id = data->l2tp_session_id;
+
+ for(it_vlan = m_vlan_iface.begin(); it_vlan != m_vlan_iface.end(); it_vlan++)
+ {
+ if(strncmp(it_vlan->vlan_iface_name, data->vlan_iface_name, sizeof(it_vlan->vlan_iface_name)) == 0)
+ {
+ IPACMDBG_H("Found vlan iface with id %d\n", it_vlan->vlan_id);
+ new_mapping.vlan_id = it_vlan->vlan_id;
+ memcpy(new_mapping.vlan_iface_ipv6_addr, it_vlan->vlan_iface_ipv6_addr,
+ sizeof(new_mapping.vlan_iface_ipv6_addr));
+ memcpy(new_mapping.vlan_client_mac, it_vlan->vlan_client_mac,
+ sizeof(new_mapping.vlan_client_mac));
+ memcpy(new_mapping.vlan_client_ipv6_addr, it_vlan->vlan_client_ipv6_addr,
+ sizeof(new_mapping.vlan_client_ipv6_addr));
+ break;
+ }
+ }
+ m_l2tp_vlan_mapping.push_front(new_mapping);
+
+ for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
+ {
+ if(it_iface->set_l2tp_iface(data->vlan_iface_name) == true)
+ {
+ has_l2tp_iface = true;
+ }
+ }
+
+ if(m_has_l2tp_iface == false && has_l2tp_iface == true)
+ {
+ IPACMDBG_H("There is l2tp iface, add rt rules for l2tp iface.\n");
+ m_has_l2tp_iface = true;
+ for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
+ {
+ if(it_iface->is_l2tp_iface() == false)
+ {
+ it_iface->handle_l2tp_enable();
+ }
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan::handle_del_l2tp_vlan_mapping(ipa_ioc_l2tp_vlan_mapping_info *data)
+{
+ list<l2tp_vlan_mapping_info>::iterator it;
+ list<IPACM_LanToLan_Iface>::iterator it_iface;
+
+ IPACMDBG_H("L2tp iface: %s session id: %d vlan iface: %s \n",
+ data->l2tp_iface_name, data->l2tp_session_id, data->vlan_iface_name);
+ for(it = m_l2tp_vlan_mapping.begin(); it != m_l2tp_vlan_mapping.end(); it++)
+ {
+ if(strncmp(data->l2tp_iface_name, it->l2tp_iface_name,
+ sizeof(data->l2tp_iface_name)) == 0)
+ {
+ IPACMDBG_H("Found l2tp iface mapped to vlan %s.\n", it->vlan_iface_name);
+ if(strncmp(data->vlan_iface_name, it->vlan_iface_name,
+ sizeof(data->vlan_iface_name)) == 0)
+ {
+ m_l2tp_vlan_mapping.erase(it);
+ }
+ else
+ {
+ IPACMERR("Incoming mapping is incorrect.\n");
+ }
+ break;
+ }
+ }
+ return;
+}
+void IPACM_LanToLan::handle_vlan_client_info(ipacm_event_data_all *data)
+{
+ list<l2tp_vlan_mapping_info>::iterator it_mapping;
+ list<vlan_iface_info>::iterator it_vlan;
+
+ IPACMDBG_H("Incoming vlan client iface: %s IPv6 address: 0x%08x%08x%08x%08x\n", data->iface_name,
+ data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+ IPACMDBG_H("MAC address: 0x%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]);
+
+ for(it_vlan = m_vlan_iface.begin(); it_vlan != m_vlan_iface.end(); it_vlan++)
+ {
+ if(strncmp(it_vlan->vlan_iface_name, data->iface_name, sizeof(it_vlan->vlan_iface_name)) == 0)
+ {
+ IPACMDBG_H("Found vlan iface in vlan list: %s\n", it_vlan->vlan_iface_name);
+ if(it_vlan->vlan_client_ipv6_addr[0] > 0 || it_vlan->vlan_client_ipv6_addr[1] > 0 ||
+ it_vlan->vlan_client_ipv6_addr[2] > 0 || it_vlan->vlan_client_ipv6_addr[3] > 0)
+ {
+ IPACMDBG_H("Vlan client info has been populated before, return.\n");
+ return;
+ }
+ memcpy(it_vlan->vlan_client_mac, data->mac_addr, sizeof(it_vlan->vlan_client_mac));
+ memcpy(it_vlan->vlan_client_ipv6_addr, data->ipv6_addr, sizeof(it_vlan->vlan_client_ipv6_addr));
+ }
+ }
+
+ for(it_mapping = m_l2tp_vlan_mapping.begin(); it_mapping != m_l2tp_vlan_mapping.end(); it_mapping++)
+ {
+ if(strncmp(it_mapping->vlan_iface_name, data->iface_name, sizeof(it_mapping->vlan_iface_name)) == 0)
+ {
+ IPACMDBG_H("Found vlan iface in l2tp mapping list: %s, l2tp iface: %s\n", it_mapping->vlan_iface_name,
+ it_mapping->l2tp_iface_name);
+ memcpy(it_mapping->vlan_client_mac, data->mac_addr, sizeof(it_mapping->vlan_client_mac));
+ memcpy(it_mapping->vlan_client_ipv6_addr, data->ipv6_addr, sizeof(it_mapping->vlan_client_ipv6_addr));
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan::handle_vlan_iface_info(ipacm_event_data_all *data)
+{
+ list<vlan_iface_info>::iterator it_vlan;
+ list<l2tp_vlan_mapping_info>::iterator it_mapping;
+
+ IPACMDBG_H("Incoming vlan iface: %s IPv6 address: 0x%08x%08x%08x%08x\n", data->iface_name,
+ data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+
+ for(it_vlan = m_vlan_iface.begin(); it_vlan != m_vlan_iface.end(); it_vlan++)
+ {
+ if(strncmp(it_vlan->vlan_iface_name, data->iface_name,
+ sizeof(it_vlan->vlan_iface_name)) == 0)
+ {
+ IPACMDBG_H("Found vlan iface: %s\n", it_vlan->vlan_iface_name);
+ memcpy(it_vlan->vlan_iface_ipv6_addr, data->ipv6_addr,
+ sizeof(it_vlan->vlan_iface_ipv6_addr));
+
+ for(it_mapping = m_l2tp_vlan_mapping.begin(); it_mapping != m_l2tp_vlan_mapping.end(); it_mapping++)
+ {
+ if(strncmp(it_mapping->vlan_iface_name, it_vlan->vlan_iface_name,
+ sizeof(it_mapping->vlan_iface_name)) == 0)
+ {
+ IPACMDBG_H("Found the l2tp-vlan mapping: l2tp %s\n", it_mapping->l2tp_iface_name);
+ memcpy(it_mapping->vlan_iface_ipv6_addr, data->ipv6_addr,
+ sizeof(it_mapping->vlan_iface_ipv6_addr));
+ }
+ }
+ break;
+ }
+ }
+
+ if(it_vlan == m_vlan_iface.end())
+ {
+ IPACMDBG_H("Failed to find the vlan iface: %s\n", data->iface_name);
+ }
+ return;
+}
+#endif
+
+void IPACM_LanToLan::handle_cached_client_add_event(IPACM_Lan *p_iface)
+{
+ list<ipacm_event_eth_bridge>::iterator it;
+
+ it = m_cached_client_add_event.begin();
+ while(it != m_cached_client_add_event.end())
+ {
+ if(it->p_iface == p_iface)
+ {
+ IPACMDBG_H("Found client with MAC: 0x%02x%02x%02x%02x%02x%02x\n", it->mac_addr[0], it->mac_addr[1],
+ it->mac_addr[2], it->mac_addr[3], it->mac_addr[4], it->mac_addr[5]);
+ handle_client_add(&(*it));
+ it = m_cached_client_add_event.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan::clear_cached_client_add_event(IPACM_Lan *p_iface)
+{
+ list<ipacm_event_eth_bridge>::iterator it;
+
+ it = m_cached_client_add_event.begin();
+ while(it != m_cached_client_add_event.end())
+ {
+ if(it->p_iface == p_iface)
+ {
+ IPACMDBG_H("Found client with MAC: 0x%02x%02x%02x%02x%02x%02x\n", it->mac_addr[0], it->mac_addr[1],
+ it->mac_addr[2], it->mac_addr[3], it->mac_addr[4], it->mac_addr[5]);
+ it = m_cached_client_add_event.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan::print_data_structure_info()
+{
+ list<IPACM_LanToLan_Iface>::iterator it;
+ list<ipacm_event_eth_bridge>::iterator it_event;
+ list<vlan_iface_info>::iterator it_vlan;
+ list<l2tp_vlan_mapping_info>::iterator it_mapping;
+ int i;
+
+ IPACMDBG_H("Is there l2tp interface? %d\n", m_has_l2tp_iface);
+
+#ifdef FEATURE_L2TP
+ IPACMDBG_H("There are %d vlan interfaces.\n", m_vlan_iface.size());
+ for(it_vlan = m_vlan_iface.begin(); it_vlan != m_vlan_iface.end(); it_vlan++)
+ {
+ IPACMDBG_H("Vlan iface: %s, id: %d, ipv6 addr: 0x%08x%08x%08x%08x\n", it_vlan->vlan_iface_name,
+ it_vlan->vlan_id, it_vlan->vlan_iface_ipv6_addr[0], it_vlan->vlan_iface_ipv6_addr[1],
+ it_vlan->vlan_iface_ipv6_addr[2], it_vlan->vlan_iface_ipv6_addr[3]);
+ IPACMDBG_H("Vlan client mac: 0x%02x%02x%02x%02x%02x%02x, ipv6 addr: 0x%08x%08x%08x%08x\n",
+ it_vlan->vlan_client_mac[0], it_vlan->vlan_client_mac[1], it_vlan->vlan_client_mac[2],
+ it_vlan->vlan_client_mac[3], it_vlan->vlan_client_mac[4], it_vlan->vlan_client_mac[5],
+ it_vlan->vlan_client_ipv6_addr[0], it_vlan->vlan_client_ipv6_addr[1], it_vlan->vlan_client_ipv6_addr[2],
+ it_vlan->vlan_client_ipv6_addr[3]);
+ }
+
+ IPACMDBG_H("There are %d vlan-l2tp mapping.\n", m_l2tp_vlan_mapping.size());
+ for(it_mapping = m_l2tp_vlan_mapping.begin(); it_mapping != m_l2tp_vlan_mapping.end(); it_mapping++)
+ {
+ IPACMDBG_H("L2tp iface: %s, session id: %d\n", it_mapping->l2tp_iface_name, it_mapping->l2tp_session_id);
+ IPACMDBG_H("Vlan iface: %s, id: %d, ipv6 addr: 0x%08x%08x%08x%08x\n", it_mapping->vlan_iface_name,
+ it_mapping->vlan_id, it_mapping->vlan_iface_ipv6_addr[0], it_mapping->vlan_iface_ipv6_addr[1],
+ it_mapping->vlan_iface_ipv6_addr[2], it_mapping->vlan_iface_ipv6_addr[3]);
+ IPACMDBG_H("Vlan client mac: 0x%02x%02x%02x%02x%02x%02x, ipv6 addr: 0x%08x%08x%08x%08x\n",
+ it_mapping->vlan_client_mac[0], it_mapping->vlan_client_mac[1], it_mapping->vlan_client_mac[2],
+ it_mapping->vlan_client_mac[3], it_mapping->vlan_client_mac[4], it_mapping->vlan_client_mac[5],
+ it_mapping->vlan_client_ipv6_addr[0], it_mapping->vlan_client_ipv6_addr[1], it_mapping->vlan_client_ipv6_addr[2],
+ it_mapping->vlan_client_ipv6_addr[3]);
+ IPACMDBG_H("L2tp client mac: 0x%02x%02x%02x%02x%02x%02x\n", it_mapping->l2tp_client_mac[0], it_mapping->l2tp_client_mac[1],
+ it_mapping->l2tp_client_mac[2], it_mapping->l2tp_client_mac[3], it_mapping->l2tp_client_mac[4], it_mapping->l2tp_client_mac[5]);
+ }
+#endif
+ IPACMDBG_H("There are %d interfaces in total.\n", m_iface.size());
+ for(it = m_iface.begin(); it != m_iface.end(); it++)
+ {
+ it->print_data_structure_info();
+ }
+
+ IPACMDBG_H("There are %d cached client add events in total.\n", m_cached_client_add_event.size());
+
+ i = 1;
+ for(it_event = m_cached_client_add_event.begin(); it_event != m_cached_client_add_event.end(); it_event++)
+ {
+ IPACMDBG_H("Client %d MAC: 0x%02x%02x%02x%02x%02x%02x, interface: %s\n", i, it_event->mac_addr[0], it_event->mac_addr[1], it_event->mac_addr[2],
+ it_event->mac_addr[3], it_event->mac_addr[4], it_event->mac_addr[5], it_event->p_iface->dev_name);
+ i++;
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::add_client_rt_rule_for_new_iface()
+{
+ list<client_info>::iterator it;
+ ipa_hdr_l2_type peer_l2_type;
+ peer_iface_info &peer = m_peer_iface_info.front();
+
+ peer_l2_type = peer.peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+ if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 1)
+ {
+ for(it = m_client_info.begin(); it != m_client_info.end(); it++)
+ {
+#ifdef FEATURE_L2TP
+ if(it->is_l2tp_client == false)
+ {
+ add_client_rt_rule(&peer, &(*it));
+ }
+ /* add l2tp rt rules */
+ add_l2tp_client_rt_rule(&peer, &(*it));
+#else
+ add_client_rt_rule(&peer, &(*it));
+#endif
+ }
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::add_client_rt_rule(peer_iface_info *peer_info, client_info *client)
+{
+ int i, num_rt_rule;
+ uint32_t rt_rule_hdl[MAX_NUM_PROP];
+ ipa_hdr_l2_type peer_l2_hdr_type;
+
+ peer_l2_hdr_type = peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+
+ /* if the peer info is not for intra interface communication */
+ if(peer_info->peer != this)
+ {
+ IPACMDBG_H("This is for inter interface communication.\n");
+
+ m_p_iface->eth_bridge_add_rt_rule(client->mac_addr, peer_info->rt_tbl_name_for_rt[IPA_IP_v4], hdr_proc_ctx_for_inter_interface[peer_l2_hdr_type],
+ peer_l2_hdr_type, IPA_IP_v4, rt_rule_hdl, &num_rt_rule);
+
+ client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4] = num_rt_rule;
+ IPACMDBG_H("Number of IPv4 routing rule is %d.\n", num_rt_rule);
+ for(i=0; i<num_rt_rule; i++)
+ {
+ IPACMDBG_H("Routing rule %d handle %d\n", i, rt_rule_hdl[i]);
+ client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4][i] = rt_rule_hdl[i];
+ }
+
+ m_p_iface->eth_bridge_add_rt_rule(client->mac_addr, peer_info->rt_tbl_name_for_rt[IPA_IP_v6], hdr_proc_ctx_for_inter_interface[peer_l2_hdr_type],
+ peer_l2_hdr_type, IPA_IP_v6, rt_rule_hdl, &num_rt_rule);
+
+ client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6] = num_rt_rule;
+ IPACMDBG_H("Number of IPv6 routing rule is %d.\n", num_rt_rule);
+ for(i=0; i<num_rt_rule; i++)
+ {
+ IPACMDBG_H("Routing rule %d handle %d\n", i, rt_rule_hdl[i]);
+ client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6][i] = rt_rule_hdl[i];
+ }
+ }
+ else
+ {
+ IPACMDBG_H("This is for intra interface communication.\n");
+ m_p_iface->eth_bridge_add_rt_rule(client->mac_addr, peer_info->rt_tbl_name_for_rt[IPA_IP_v4], hdr_proc_ctx_for_intra_interface,
+ peer_l2_hdr_type, IPA_IP_v4, rt_rule_hdl, &num_rt_rule);
+
+ client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4] = num_rt_rule;
+ IPACMDBG_H("Number of IPv4 routing rule is %d.\n", num_rt_rule);
+ for(i=0; i<num_rt_rule; i++)
+ {
+ IPACMDBG_H("Routing rule %d handle %d\n", i, rt_rule_hdl[i]);
+ client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][i] = rt_rule_hdl[i];
+ }
+
+ m_p_iface->eth_bridge_add_rt_rule(client->mac_addr, peer_info->rt_tbl_name_for_rt[IPA_IP_v6], hdr_proc_ctx_for_intra_interface,
+ peer_l2_hdr_type, IPA_IP_v6, rt_rule_hdl, &num_rt_rule);
+
+ client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6] = num_rt_rule;
+ IPACMDBG_H("Number of IPv6 routing rule is %d.\n", num_rt_rule);
+ for(i=0; i<num_rt_rule; i++)
+ {
+ IPACMDBG_H("Routing rule %d handle %d\n", i, rt_rule_hdl[i]);
+ client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][i] = rt_rule_hdl[i];
+ }
+ }
+
+ return;
+}
+
+#ifdef FEATURE_L2TP
+void IPACM_LanToLan_Iface::add_l2tp_client_rt_rule(peer_iface_info *peer, client_info *client)
+{
+ ipa_hdr_l2_type peer_l2_hdr_type;
+ l2tp_vlan_mapping_info *mapping_info;
+
+ peer_l2_hdr_type = peer->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+ mapping_info = client->mapping_info;
+ if(client->is_l2tp_client)
+ {
+ m_p_iface->add_l2tp_rt_rule(IPA_IP_v4, client->mac_addr, peer_l2_hdr_type, mapping_info->l2tp_session_id,
+ mapping_info->vlan_id, mapping_info->vlan_client_mac, mapping_info->vlan_iface_ipv6_addr,
+ mapping_info->vlan_client_ipv6_addr, &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_hdr_hdl,
+ &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_hdr_proc_ctx_hdl[IPA_IP_v4], &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].second_pass_hdr_hdl,
+ &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].num_rt_hdl[IPA_IP_v4], client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_rt_rule_hdl[IPA_IP_v4],
+ client->l2tp_rt_rule_hdl[peer_l2_hdr_type].second_pass_rt_rule_hdl);
+
+ m_p_iface->add_l2tp_rt_rule(IPA_IP_v6, client->mac_addr, peer_l2_hdr_type, mapping_info->l2tp_session_id,
+ mapping_info->vlan_id, mapping_info->vlan_client_mac, mapping_info->vlan_iface_ipv6_addr,
+ mapping_info->vlan_client_ipv6_addr, &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_hdr_hdl,
+ &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_hdr_proc_ctx_hdl[IPA_IP_v6], &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].second_pass_hdr_hdl,
+ &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].num_rt_hdl[IPA_IP_v6], client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_rt_rule_hdl[IPA_IP_v6],
+ client->l2tp_rt_rule_hdl[peer_l2_hdr_type].second_pass_rt_rule_hdl);
+ }
+ else
+ {
+ if(IPACM_LanToLan::get_instance()->has_l2tp_iface() == true)
+ {
+ m_p_iface->add_l2tp_rt_rule(IPA_IP_v6, client->mac_addr, &hdr_proc_ctx_for_l2tp, &client->l2tp_rt_rule_hdl[peer_l2_hdr_type].num_rt_hdl[IPA_IP_v6],
+ client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_rt_rule_hdl[IPA_IP_v6]);
+ }
+ }
+ return;
+}
+#endif
+
+void IPACM_LanToLan_Iface::add_all_inter_interface_client_flt_rule(ipa_ip_type iptype)
+{
+ list<peer_iface_info>::iterator it_iface;
+ list<client_info>::iterator it_client;
+
+ for(it_iface = m_peer_iface_info.begin(); it_iface != m_peer_iface_info.end(); it_iface++)
+ {
+ IPACMDBG_H("Add flt rules for clients of interface %s.\n", it_iface->peer->get_iface_pointer()->dev_name);
+ for(it_client = it_iface->peer->m_client_info.begin(); it_client != it_iface->peer->m_client_info.end(); it_client++)
+ {
+ add_client_flt_rule(&(*it_iface), &(*it_client), iptype);
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan_Iface::add_all_intra_interface_client_flt_rule(ipa_ip_type iptype)
+{
+ list<client_info>::iterator it_client;
+
+ IPACMDBG_H("Add flt rules for own clients.\n");
+ for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+ {
+ add_client_flt_rule(&m_intra_interface_info, &(*it_client), iptype);
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::add_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client)
+{
+ list<peer_iface_info>::iterator it;
+
+ for(it = m_peer_iface_info.begin(); it != m_peer_iface_info.end(); it++)
+ {
+ if(it->peer == peer_iface)
+ {
+ IPACMDBG_H("Found the peer iface info.\n");
+ if(m_is_ip_addr_assigned[IPA_IP_v4])
+ {
+ add_client_flt_rule(&(*it), client, IPA_IP_v4);
+ }
+ if(m_is_ip_addr_assigned[IPA_IP_v6])
+ {
+ add_client_flt_rule(&(*it), client, IPA_IP_v6);
+ }
+
+ break;
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan_Iface::add_client_flt_rule(peer_iface_info *peer, client_info *client, ipa_ip_type iptype)
+{
+ list<flt_rule_info>::iterator it_flt;
+ uint32_t flt_rule_hdl;
+ uint32_t l2tp_first_pass_flt_rule_hdl = 0, l2tp_second_pass_flt_rule_hdl = 0;
+ flt_rule_info new_flt_info;
+ ipa_ioc_get_rt_tbl rt_tbl;
+
+ if(m_is_l2tp_iface && iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("No need to install IPv4 flt rule on l2tp interface.\n");
+ return;
+ }
+
+ for(it_flt = peer->flt_rule.begin(); it_flt != peer->flt_rule.end(); it_flt++)
+ {
+ if(it_flt->p_client == client) //the client is already in the flt info list
+ {
+ IPACMDBG_H("The client is found in flt info list.\n");
+ break;
+ }
+ }
+
+ if(it_flt != peer->flt_rule.end())
+ {
+ l2tp_first_pass_flt_rule_hdl = it_flt->l2tp_first_pass_flt_rule_hdl[iptype];
+ l2tp_second_pass_flt_rule_hdl = it_flt->l2tp_second_pass_flt_rule_hdl;
+ }
+
+#ifdef FEATURE_L2TP
+ if(m_is_l2tp_iface)
+ {
+ m_p_iface->add_l2tp_flt_rule(client->mac_addr, &l2tp_first_pass_flt_rule_hdl);
+ }
+ else
+#endif
+ {
+#ifdef FEATURE_L2TP
+ if(client->is_l2tp_client)
+ {
+ m_p_iface->add_l2tp_flt_rule(iptype, client->mac_addr, client->mapping_info->vlan_client_ipv6_addr,
+ &l2tp_first_pass_flt_rule_hdl, &l2tp_second_pass_flt_rule_hdl);
+ }
+ else
+#endif
+ {
+ rt_tbl.ip = iptype;
+ memcpy(rt_tbl.name, peer->rt_tbl_name_for_flt[iptype], sizeof(rt_tbl.name));
+ IPACMDBG_H("This flt rule points to rt tbl %s.\n", rt_tbl.name);
+
+ if(IPACM_Iface::m_routing.GetRoutingTable(&rt_tbl) == false)
+ {
+ IPACMERR("Failed to get routing table.\n");
+ return;
+ }
+
+ m_p_iface->eth_bridge_add_flt_rule(client->mac_addr, rt_tbl.hdl,
+ iptype, &flt_rule_hdl);
+ IPACMDBG_H("Installed flt rule for IP type %d: handle %d\n", iptype, flt_rule_hdl);
+ }
+ }
+
+ if(it_flt != peer->flt_rule.end())
+ {
+ it_flt->flt_rule_hdl[iptype] = flt_rule_hdl;
+ it_flt->l2tp_first_pass_flt_rule_hdl[iptype] = l2tp_first_pass_flt_rule_hdl;
+ it_flt->l2tp_second_pass_flt_rule_hdl = l2tp_second_pass_flt_rule_hdl;
+ }
+ else
+ {
+ IPACMDBG_H("The client is not found in flt info list, insert a new one.\n");
+ memset(&new_flt_info, 0, sizeof(new_flt_info));
+ new_flt_info.p_client = client;
+ new_flt_info.flt_rule_hdl[iptype] = flt_rule_hdl;
+ new_flt_info.l2tp_first_pass_flt_rule_hdl[iptype] = l2tp_first_pass_flt_rule_hdl;
+ new_flt_info.l2tp_second_pass_flt_rule_hdl = l2tp_second_pass_flt_rule_hdl;
+
+ peer->flt_rule.push_front(new_flt_info);
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::del_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client)
+{
+ list<peer_iface_info>::iterator it;
+
+ for(it = m_peer_iface_info.begin(); it != m_peer_iface_info.end(); it++)
+ {
+ if(it->peer == peer_iface)
+ {
+ IPACMDBG_H("Found the peer iface info.\n");
+ del_client_flt_rule(&(*it), client);
+ break;
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan_Iface::del_client_flt_rule(peer_iface_info *peer, client_info *client)
+{
+ list<flt_rule_info>::iterator it_flt;
+
+ for(it_flt = peer->flt_rule.begin(); it_flt != peer->flt_rule.end(); it_flt++)
+ {
+ if(it_flt->p_client == client) //found the client in flt info list
+ {
+ IPACMDBG_H("Found the client in flt info list.\n");
+ if(m_is_ip_addr_assigned[IPA_IP_v4])
+ {
+ if(m_is_l2tp_iface)
+ {
+ IPACMDBG_H("No IPv4 client flt rule on l2tp iface.\n");
+ }
+ else
+ {
+#ifdef FEATURE_L2TP
+ if(client->is_l2tp_client)
+ {
+ m_p_iface->del_l2tp_flt_rule(IPA_IP_v4, it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v4],
+ it_flt->l2tp_second_pass_flt_rule_hdl);
+ it_flt->l2tp_second_pass_flt_rule_hdl = 0;
+ IPACMDBG_H("Deleted IPv4 first pass flt rule %d and second pass flt rule %d.\n",
+ it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v4], it_flt->l2tp_second_pass_flt_rule_hdl);
+ }
+ else
+#endif
+ {
+ m_p_iface->eth_bridge_del_flt_rule(it_flt->flt_rule_hdl[IPA_IP_v4], IPA_IP_v4);
+ IPACMDBG_H("Deleted IPv4 flt rule %d.\n", it_flt->flt_rule_hdl[IPA_IP_v4]);
+ }
+ }
+ }
+ if(m_is_ip_addr_assigned[IPA_IP_v6])
+ {
+#ifdef FEATURE_L2TP
+ if(m_is_l2tp_iface)
+ {
+ m_p_iface->del_l2tp_flt_rule(it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6]);
+ IPACMDBG_H("Deleted IPv6 flt rule %d.\n", it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6]);
+ }
+ else
+#endif
+ {
+#ifdef FEATURE_L2TP
+ if(client->is_l2tp_client)
+ {
+ m_p_iface->del_l2tp_flt_rule(IPA_IP_v6, it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6],
+ it_flt->l2tp_second_pass_flt_rule_hdl);
+ IPACMDBG_H("Deleted IPv6 first pass flt rule %d and second pass flt rule %d.\n",
+ it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6], it_flt->l2tp_second_pass_flt_rule_hdl);
+ }
+ else
+#endif
+ {
+ m_p_iface->eth_bridge_del_flt_rule(it_flt->flt_rule_hdl[IPA_IP_v6], IPA_IP_v6);
+ IPACMDBG_H("Deleted IPv6 flt rule %d.\n", it_flt->flt_rule_hdl[IPA_IP_v6]);
+ }
+ }
+ }
+ peer->flt_rule.erase(it_flt);
+ break;
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan_Iface::del_client_rt_rule(peer_iface_info *peer, client_info *client)
+{
+ ipa_hdr_l2_type peer_l2_hdr_type;
+ int i, num_rules;
+
+ peer_l2_hdr_type = peer->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+ /* if the peer info is not for intra interface communication */
+ if(peer->peer != this)
+ {
+ IPACMDBG_H("Delete routing rules for inter interface communication.\n");
+
+ if(client->is_l2tp_client == false)
+ {
+ num_rules = client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4];
+ for(i = 0; i < num_rules; i++)
+ {
+ m_p_iface->eth_bridge_del_rt_rule(client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4][i], IPA_IP_v4);
+ IPACMDBG_H("IPv4 rt rule %d is deleted.\n", client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4][i]);
+ }
+ client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4] = 0;
+
+ num_rules = client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6];
+ for(i = 0; i < num_rules; i++)
+ {
+ m_p_iface->eth_bridge_del_rt_rule(client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6][i], IPA_IP_v6);
+ IPACMDBG_H("IPv6 rt rule %d is deleted.\n", client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6][i]);
+ }
+ client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6] = 0;
+#ifdef FEATURE_L2TP
+ if(IPACM_LanToLan::get_instance()->has_l2tp_iface() == true)
+ {
+ m_p_iface->del_l2tp_rt_rule(IPA_IP_v6, client->l2tp_rt_rule_hdl[peer_l2_hdr_type].num_rt_hdl[IPA_IP_v6],
+ client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_rt_rule_hdl[IPA_IP_v6]);
+ }
+#endif
+ }
+ else
+ {
+#ifdef FEATURE_L2TP
+ m_p_iface->del_l2tp_rt_rule(IPA_IP_v4, client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_hdr_hdl,
+ client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_hdr_proc_ctx_hdl[IPA_IP_v4], client->l2tp_rt_rule_hdl[peer_l2_hdr_type].second_pass_hdr_hdl,
+ client->l2tp_rt_rule_hdl[peer_l2_hdr_type].num_rt_hdl[IPA_IP_v4], client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_rt_rule_hdl[IPA_IP_v4],
+ client->l2tp_rt_rule_hdl[peer_l2_hdr_type].second_pass_rt_rule_hdl);
+
+ m_p_iface->del_l2tp_rt_rule(IPA_IP_v6, 0, client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_hdr_proc_ctx_hdl[IPA_IP_v6],
+ 0, client->l2tp_rt_rule_hdl[peer_l2_hdr_type].num_rt_hdl[IPA_IP_v6], client->l2tp_rt_rule_hdl[peer_l2_hdr_type].first_pass_rt_rule_hdl[IPA_IP_v6],
+ NULL);
+#endif
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Delete routing rules for intra interface communication.\n");
+ num_rules = client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4];
+ for(i = 0; i < num_rules; i++)
+ {
+ m_p_iface->eth_bridge_del_rt_rule(client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][i], IPA_IP_v4);
+ IPACMDBG_H("IPv4 rt rule %d is deleted.\n", client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][i]);
+ }
+ client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4] = 0;
+
+ num_rules = client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6];
+ for(i = 0; i < num_rules; i++)
+ {
+ m_p_iface->eth_bridge_del_rt_rule(client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][i], IPA_IP_v6);
+ IPACMDBG_H("IPv6 rt rule %d is deleted.\n", client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][i]);
+ }
+ client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6] = 0;
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::handle_down_event()
+{
+ list<IPACM_LanToLan_Iface>::iterator it_other_iface;
+ list<peer_iface_info>::iterator it_own_peer_info, it_other_iface_peer_info;
+ IPACM_LanToLan_Iface *other_iface;
+
+ /* clear inter-interface rules */
+ if(m_support_inter_iface_offload)
+ {
+ for(it_own_peer_info = m_peer_iface_info.begin(); it_own_peer_info != m_peer_iface_info.end();
+ it_own_peer_info++)
+ {
+ /* decrement reference count of peer l2 header type on both interfaces*/
+ decrement_ref_cnt_peer_l2_hdr_type(it_own_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type);
+ it_own_peer_info->peer->decrement_ref_cnt_peer_l2_hdr_type(m_p_iface->tx_prop->tx[0].hdr_l2_type);
+
+ /* first clear all flt rule on target interface */
+ IPACMDBG_H("Clear all flt rule on target interface.\n");
+ clear_all_flt_rule_for_one_peer_iface(&(*it_own_peer_info));
+
+ other_iface = it_own_peer_info->peer;
+ /* then clear all flt/rt rule and hdr proc ctx for target interface on peer interfaces */
+ IPACMDBG_H("Clear all flt/rt rules and hdr proc ctx for target interface on peer interfaces %s.\n",
+ it_own_peer_info->peer->get_iface_pointer()->dev_name);
+ for(it_other_iface_peer_info = other_iface->m_peer_iface_info.begin();
+ it_other_iface_peer_info != other_iface->m_peer_iface_info.end();
+ it_other_iface_peer_info++)
+ {
+ if(it_other_iface_peer_info->peer == this) //found myself in other iface's peer info list
+ {
+ IPACMDBG_H("Found the right peer info on other iface.\n");
+ other_iface->clear_all_flt_rule_for_one_peer_iface(&(*it_other_iface_peer_info));
+ other_iface->clear_all_rt_rule_for_one_peer_iface(&(*it_other_iface_peer_info));
+ /* remove the peer info from the list */
+ other_iface->m_peer_iface_info.erase(it_other_iface_peer_info);
+ other_iface->del_hdr_proc_ctx(m_p_iface->tx_prop->tx[0].hdr_l2_type);
+ break;
+ }
+ }
+
+ /* then clear rt rule and hdr proc ctx and release rt table on target interface */
+ IPACMDBG_H("Clear rt rules and hdr proc ctx and release rt table on target interface.\n");
+ clear_all_rt_rule_for_one_peer_iface(&(*it_own_peer_info));
+ del_hdr_proc_ctx(it_own_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type);
+ }
+ m_peer_iface_info.clear();
+ }
+
+ /* clear intra interface rules */
+ if(m_support_intra_iface_offload)
+ {
+ IPACMDBG_H("Clear intra interface flt/rt rules and hdr proc ctx, release rt tables.\n");
+ clear_all_flt_rule_for_one_peer_iface(&m_intra_interface_info);
+ clear_all_rt_rule_for_one_peer_iface(&m_intra_interface_info);
+ m_p_iface->eth_bridge_del_hdr_proc_ctx(hdr_proc_ctx_for_intra_interface);
+ IPACMDBG_H("Hdr proc ctx with hdl %d is deleted.\n", hdr_proc_ctx_for_intra_interface);
+ }
+
+ /* then clear the client info list */
+ m_client_info.clear();
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::clear_all_flt_rule_for_one_peer_iface(peer_iface_info *peer)
+{
+ list<flt_rule_info>::iterator it;
+
+ for(it = peer->flt_rule.begin(); it != peer->flt_rule.end(); it++)
+ {
+ if(m_is_ip_addr_assigned[IPA_IP_v4])
+ {
+ if(m_is_l2tp_iface)
+ {
+ IPACMDBG_H("No IPv4 client flt rule on l2tp iface.\n");
+ }
+ else
+ {
+#ifdef FEATURE_L2TP
+ if(it->p_client->is_l2tp_client)
+ {
+ m_p_iface->del_l2tp_flt_rule(IPA_IP_v4, it->l2tp_first_pass_flt_rule_hdl[IPA_IP_v4],
+ it->l2tp_second_pass_flt_rule_hdl);
+ it->l2tp_second_pass_flt_rule_hdl = 0;
+ IPACMDBG_H("Deleted IPv4 first pass flt rule %d and second pass flt rule %d.\n",
+ it->l2tp_first_pass_flt_rule_hdl[IPA_IP_v4], it->l2tp_second_pass_flt_rule_hdl);
+ }
+ else
+#endif
+ {
+ m_p_iface->eth_bridge_del_flt_rule(it->flt_rule_hdl[IPA_IP_v4], IPA_IP_v4);
+ IPACMDBG_H("Deleted IPv4 flt rule %d.\n", it->flt_rule_hdl[IPA_IP_v4]);
+ }
+ }
+ }
+ if(m_is_ip_addr_assigned[IPA_IP_v6])
+ {
+#ifdef FEATURE_L2TP
+ if(m_is_l2tp_iface)
+ {
+ m_p_iface->del_l2tp_flt_rule(it->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6]);
+ IPACMDBG_H("Deleted IPv6 flt rule %d.\n", it->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6]);
+ }
+ else
+#endif
+ {
+#ifdef FEATURE_L2TP
+ if(it->p_client->is_l2tp_client)
+ {
+ m_p_iface->del_l2tp_flt_rule(IPA_IP_v6, it->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6],
+ it->l2tp_second_pass_flt_rule_hdl);
+ IPACMDBG_H("Deleted IPv6 first pass flt rule %d and second pass flt rule %d.\n",
+ it->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6], it->l2tp_second_pass_flt_rule_hdl);
+ }
+ else
+#endif
+ {
+ m_p_iface->eth_bridge_del_flt_rule(it->flt_rule_hdl[IPA_IP_v6], IPA_IP_v6);
+ IPACMDBG_H("Deleted IPv6 flt rule %d.\n", it->flt_rule_hdl[IPA_IP_v6]);
+ }
+ }
+ }
+ }
+ peer->flt_rule.clear();
+ return;
+}
+
+void IPACM_LanToLan_Iface::clear_all_rt_rule_for_one_peer_iface(peer_iface_info *peer)
+{
+ list<client_info>::iterator it;
+ ipa_hdr_l2_type peer_l2_type;
+
+ peer_l2_type = peer->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+ if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 0)
+ {
+ for(it = m_client_info.begin(); it != m_client_info.end(); it++)
+ {
+ del_client_rt_rule(peer, &(*it));
+ }
+#ifdef FEATURE_L2TP
+ if(IPACM_LanToLan::get_instance()->has_l2tp_iface() == true)
+ {
+ m_p_iface->eth_bridge_del_hdr_proc_ctx(hdr_proc_ctx_for_l2tp);
+ hdr_proc_ctx_for_l2tp = 0;
+ }
+#endif
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::handle_wlan_scc_mcc_switch()
+{
+ list<peer_iface_info>::iterator it_peer_info;
+ list<client_info>::iterator it_client;
+ ipa_hdr_l2_type peer_l2_hdr_type;
+ bool flag[IPA_HDR_L2_MAX];
+ int i;
+
+ /* modify inter-interface routing rules */
+ if(m_support_inter_iface_offload)
+ {
+ IPACMDBG_H("Modify rt rules for peer interfaces.\n");
+ memset(flag, 0, sizeof(flag));
+ for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end(); it_peer_info++)
+ {
+ peer_l2_hdr_type = it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+ if(flag[peer_l2_hdr_type] == false)
+ {
+ flag[peer_l2_hdr_type] = true;
+ for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+ {
+ m_p_iface->eth_bridge_modify_rt_rule(it_client->mac_addr, hdr_proc_ctx_for_inter_interface[peer_l2_hdr_type],
+ peer_l2_hdr_type, IPA_IP_v4, it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4],
+ it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4]);
+ IPACMDBG_H("The following IPv4 routing rules are modified:\n");
+ for(i = 0; i < it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v4]; i++)
+ {
+ IPACMDBG_H("%d\n", it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v4][i]);
+ }
+
+ m_p_iface->eth_bridge_modify_rt_rule(it_client->mac_addr, hdr_proc_ctx_for_inter_interface[peer_l2_hdr_type],
+ peer_l2_hdr_type, IPA_IP_v6, it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6],
+ it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6]);
+ IPACMDBG_H("The following IPv6 routing rules are modified:\n");
+ for(i = 0; i < it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].num_hdl[IPA_IP_v6]; i++)
+ {
+ IPACMDBG_H("%d\n", it_client->inter_iface_rt_rule_hdl[peer_l2_hdr_type].rule_hdl[IPA_IP_v6][i]);
+ }
+ }
+ }
+ }
+ }
+
+ /* modify routing rules for intra-interface communication */
+ IPACMDBG_H("Modify rt rules for intra-interface communication.\n");
+ if(m_support_intra_iface_offload)
+ {
+ for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+ {
+ m_p_iface->eth_bridge_modify_rt_rule(it_client->mac_addr, hdr_proc_ctx_for_intra_interface,
+ m_p_iface->tx_prop->tx[0].hdr_l2_type, IPA_IP_v4, it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4],
+ it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4]);
+ IPACMDBG_H("The following IPv4 routing rules are modified:\n");
+ for(i = 0; i < it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4]; i++)
+ {
+ IPACMDBG_H("%d\n", it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][i]);
+ }
+
+ m_p_iface->eth_bridge_modify_rt_rule(it_client->mac_addr, hdr_proc_ctx_for_intra_interface,
+ m_p_iface->tx_prop->tx[0].hdr_l2_type, IPA_IP_v6, it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6],
+ it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6]);
+ IPACMDBG_H("The following IPv6 routing rules are modified:\n");
+ for(i = 0; i < it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6]; i++)
+ {
+ IPACMDBG_H("%d\n", it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][i]);
+ }
+ }
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::handle_intra_interface_info()
+{
+ uint32_t hdr_proc_ctx_hdl;
+
+ if(m_p_iface->tx_prop == NULL)
+ {
+ IPACMERR("No tx prop.\n");
+ return;
+ }
+
+ m_intra_interface_info.peer = this;
+
+ snprintf(m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX,
+ "eth_v4_intra_interface");
+ IPACMDBG_H("IPv4 routing table for flt name: %s\n", m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4]);
+ snprintf(m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX,
+ "eth_v6_intra_interface");
+ IPACMDBG_H("IPv6 routing table for flt name: %s\n", m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6]);
+
+ memcpy(m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v4], m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4],
+ IPA_RESOURCE_NAME_MAX);
+ IPACMDBG_H("IPv4 routing table for rt name: %s\n", m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v4]);
+ memcpy(m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v6], m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6],
+ IPA_RESOURCE_NAME_MAX);
+ IPACMDBG_H("IPv6 routing table for rt name: %s\n", m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v6]);
+
+ m_p_iface->eth_bridge_add_hdr_proc_ctx(m_p_iface->tx_prop->tx[0].hdr_l2_type,
+ &hdr_proc_ctx_hdl);
+ hdr_proc_ctx_for_intra_interface = hdr_proc_ctx_hdl;
+ IPACMDBG_H("Hdr proc ctx for intra-interface communication: hdl %d\n", hdr_proc_ctx_hdl);
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::handle_new_iface_up(char rt_tbl_name_for_flt[][IPA_RESOURCE_NAME_MAX], char rt_tbl_name_for_rt[][IPA_RESOURCE_NAME_MAX],
+ IPACM_LanToLan_Iface *peer_iface)
+{
+ peer_iface_info new_peer;
+ ipa_hdr_l2_type peer_l2_hdr_type;
+
+ new_peer.peer = peer_iface;
+ memcpy(new_peer.rt_tbl_name_for_rt[IPA_IP_v4], rt_tbl_name_for_rt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX);
+ memcpy(new_peer.rt_tbl_name_for_rt[IPA_IP_v6], rt_tbl_name_for_rt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX);
+ memcpy(new_peer.rt_tbl_name_for_flt[IPA_IP_v4], rt_tbl_name_for_flt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX);
+ memcpy(new_peer.rt_tbl_name_for_flt[IPA_IP_v6], rt_tbl_name_for_flt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX);
+
+ peer_l2_hdr_type = peer_iface->m_p_iface->tx_prop->tx[0].hdr_l2_type;
+ increment_ref_cnt_peer_l2_hdr_type(peer_l2_hdr_type);
+ add_hdr_proc_ctx(peer_l2_hdr_type);
+
+ /* push the new peer_iface_info into the list */
+ m_peer_iface_info.push_front(new_peer);
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::handle_client_add(uint8_t *mac, bool is_l2tp_client, l2tp_vlan_mapping_info *mapping_info)
+{
+ list<client_info>::iterator it_client;
+ list<peer_iface_info>::iterator it_peer_info;
+ client_info new_client;
+ bool flag[IPA_HDR_L2_MAX];
+
+ for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+ {
+ if(memcmp(it_client->mac_addr, mac, sizeof(it_client->mac_addr)) == 0)
+ {
+ IPACMDBG_H("This client has been added before.\n");
+ return;
+ }
+ }
+
+ if(m_client_info.size() == MAX_NUM_CLIENT)
+ {
+ IPACMDBG_H("The number of clients has reached maximum %d.\n", MAX_NUM_CLIENT);
+ return;
+ }
+
+ IPACMDBG_H("is_l2tp_client: %d, mapping_info: %p\n", is_l2tp_client, mapping_info);
+ memset(&new_client, 0, sizeof(new_client));
+ memcpy(new_client.mac_addr, mac, sizeof(new_client.mac_addr));
+ new_client.is_l2tp_client = is_l2tp_client;
+ new_client.mapping_info = mapping_info;
+ m_client_info.push_front(new_client);
+
+ client_info &front_client = m_client_info.front();
+
+ /* install inter-interface rules */
+ if(m_support_inter_iface_offload)
+ {
+ memset(flag, 0, sizeof(flag));
+ for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end(); it_peer_info++)
+ {
+ /* make sure add routing rule only once for each peer l2 header type */
+ if(flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] == false)
+ {
+ /* add client routing rule for each peer interface */
+ if(front_client.is_l2tp_client == false)
+ {
+ add_client_rt_rule(&(*it_peer_info), &front_client);
+ }
+#ifdef FEATURE_L2TP
+ /* add l2tp rt rules */
+ add_l2tp_client_rt_rule(&(*it_peer_info), &front_client);
+#endif
+ flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] = true;
+ }
+
+ /* add client filtering rule on peer interfaces */
+ it_peer_info->peer->add_one_client_flt_rule(this, &front_client);
+ }
+ }
+
+ /* install intra-interface rules */
+ if(m_support_intra_iface_offload)
+ {
+ /* add routing rule first */
+ add_client_rt_rule(&m_intra_interface_info, &front_client);
+
+ /* add filtering rule */
+ if(m_is_ip_addr_assigned[IPA_IP_v4])
+ {
+ add_client_flt_rule(&m_intra_interface_info, &front_client, IPA_IP_v4);
+ }
+ if(m_is_ip_addr_assigned[IPA_IP_v6])
+ {
+ add_client_flt_rule(&m_intra_interface_info, &front_client, IPA_IP_v6);
+ }
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::handle_client_del(uint8_t *mac)
+{
+ list<client_info>::iterator it_client;
+ list<peer_iface_info>::iterator it_peer_info;
+ bool flag[IPA_HDR_L2_MAX];
+
+ for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+ {
+ if(memcmp(it_client->mac_addr, mac, sizeof(it_client->mac_addr)) == 0) //found the client
+ {
+ IPACMDBG_H("Found the client.\n");
+ break;
+ }
+ }
+
+ if(it_client != m_client_info.end()) //if we found the client
+ {
+ /* uninstall inter-interface rules */
+ if(m_support_inter_iface_offload)
+ {
+ memset(flag, 0, sizeof(flag));
+ for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end();
+ it_peer_info++)
+ {
+ IPACMDBG_H("Delete client filtering rule on peer interface.\n");
+ it_peer_info->peer->del_one_client_flt_rule(this, &(*it_client));
+
+ /* make sure to delete routing rule only once for each peer l2 header type */
+ if(flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] == false)
+ {
+ IPACMDBG_H("Delete client routing rule for peer interface.\n");
+ del_client_rt_rule(&(*it_peer_info), &(*it_client));
+#ifdef FEATURE_L2TP
+ if(it_client->is_l2tp_client == false && IPACM_LanToLan::get_instance()->has_l2tp_iface() == true
+ && m_client_info.size() == 1)
+ {
+ m_p_iface->eth_bridge_del_hdr_proc_ctx(hdr_proc_ctx_for_l2tp);
+ hdr_proc_ctx_for_l2tp = 0;
+ }
+#endif
+ flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] = true;
+ }
+ }
+ }
+
+ /* uninstall intra-interface rules */
+ if(m_support_intra_iface_offload)
+ {
+ /* delete filtering rule first */
+ IPACMDBG_H("Delete client filtering rule for intra-interface communication.\n");
+ del_client_flt_rule(&m_intra_interface_info, &(*it_client));
+
+ /* delete routing rule */
+ IPACMDBG_H("Delete client routing rule for intra-interface communication.\n");
+ del_client_rt_rule(&m_intra_interface_info, &(*it_client));
+ }
+
+ /* erase the client from client info list */
+ m_client_info.erase(it_client);
+ }
+ else
+ {
+ IPACMDBG_H("The client is not found.\n");
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type)
+{
+ uint32_t hdr_proc_ctx_hdl;
+
+ if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 1)
+ {
+ m_p_iface->eth_bridge_add_hdr_proc_ctx(peer_l2_type, &hdr_proc_ctx_hdl);
+ hdr_proc_ctx_for_inter_interface[peer_l2_type] = hdr_proc_ctx_hdl;
+ IPACMDBG_H("Installed inter-interface hdr proc ctx on iface %s: handle %d\n", m_p_iface->dev_name, hdr_proc_ctx_hdl);
+ }
+ return;
+}
+
+void IPACM_LanToLan_Iface::del_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type)
+{
+ if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 0)
+ {
+ m_p_iface->eth_bridge_del_hdr_proc_ctx(hdr_proc_ctx_for_inter_interface[peer_l2_type]);
+ IPACMDBG_H("Hdr proc ctx with hdl %d is deleted.\n", hdr_proc_ctx_for_inter_interface[peer_l2_type]);
+ }
+ return;
+}
+
+void IPACM_LanToLan_Iface::print_data_structure_info()
+{
+ list<peer_iface_info>::iterator it_peer;
+ list<client_info>::iterator it_client;
+ int i, j, k;
+
+ IPACMDBG_H("\n");
+ IPACMDBG_H("Interface %s:\n", m_p_iface->dev_name);
+ IPACMDBG_H("Is IPv4 addr assigned? %d\n", m_is_ip_addr_assigned[IPA_IP_v4]);
+ IPACMDBG_H("Is IPv6 addr assigned? %d\n", m_is_ip_addr_assigned[IPA_IP_v6]);
+ IPACMDBG_H("Support inter interface offload? %d\n", m_support_inter_iface_offload);
+ IPACMDBG_H("Support intra interface offload? %d\n", m_support_intra_iface_offload);
+ IPACMDBG_H("Is l2tp interface? %d\n", m_is_l2tp_iface);
+
+ if(m_support_inter_iface_offload)
+ {
+ for(i = 0; i < IPA_HDR_L2_MAX; i++)
+ {
+ IPACMDBG_H("Ref_cnt of peer l2 type %s is %d.\n", ipa_l2_hdr_type[i], ref_cnt_peer_l2_hdr_type[i]);
+ if(ref_cnt_peer_l2_hdr_type[i] > 0)
+ {
+ IPACMDBG_H("Hdr proc ctx for peer l2 type %s: %d\n", ipa_l2_hdr_type[i], hdr_proc_ctx_for_inter_interface[i]);
+ }
+ }
+ }
+
+ if(m_support_intra_iface_offload)
+ {
+ IPACMDBG_H("Hdr proc ctx for intra-interface: %d\n", hdr_proc_ctx_for_intra_interface);
+ }
+
+ IPACMDBG_H("Hdr proc ctx for l2tp: %d\n", hdr_proc_ctx_for_l2tp);
+
+ i = 1;
+ IPACMDBG_H("There are %d clients in total.\n", m_client_info.size());
+ for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+ {
+ IPACMDBG_H("Client %d MAC: 0x%02x%02x%02x%02x%02x%02x Pointer: 0x%08x\n", i, it_client->mac_addr[0], it_client->mac_addr[1],
+ it_client->mac_addr[2], it_client->mac_addr[3], it_client->mac_addr[4], it_client->mac_addr[5], &(*it_client));
+ IPACMDBG_H("Is l2tp client? %d\n", it_client->is_l2tp_client);
+ if(it_client->is_l2tp_client && it_client->mapping_info)
+ {
+ IPACMDBG_H("Vlan iface associated with this client: %s\n", it_client->mapping_info->vlan_iface_name);
+ }
+
+ if(m_support_inter_iface_offload)
+ {
+ for(j = 0; j < IPA_HDR_L2_MAX; j++)
+ {
+ if(ref_cnt_peer_l2_hdr_type[j] > 0)
+ {
+ IPACMDBG_H("Printing routing rule info for inter-interface communication for peer l2 type %s.\n",
+ ipa_l2_hdr_type[j]);
+ IPACMDBG_H("Number of IPv4 routing rules is %d, handles:\n", it_client->inter_iface_rt_rule_hdl[j].num_hdl[IPA_IP_v4]);
+ for(k = 0; k < it_client->inter_iface_rt_rule_hdl[j].num_hdl[IPA_IP_v4]; k++)
+ {
+ IPACMDBG_H("%d\n", it_client->inter_iface_rt_rule_hdl[j].rule_hdl[IPA_IP_v4][k]);
+ }
+
+ IPACMDBG_H("Number of IPv6 routing rules is %d, handles:\n", it_client->inter_iface_rt_rule_hdl[j].num_hdl[IPA_IP_v6]);
+ for(k = 0; k < it_client->inter_iface_rt_rule_hdl[j].num_hdl[IPA_IP_v6]; k++)
+ {
+ IPACMDBG_H("%d\n", it_client->inter_iface_rt_rule_hdl[j].rule_hdl[IPA_IP_v6][k]);
+ }
+
+#ifdef FEATURE_L2TP
+ if(it_client->is_l2tp_client)
+ {
+ IPACMDBG_H("Printing l2tp hdr info for l2tp client.\n");
+ IPACMDBG_H("First pass hdr hdl: %d, IPv4 hdr proc ctx hdl: IPv6 hdr proc ctx hdl: %d\n",
+ it_client->l2tp_rt_rule_hdl[j].first_pass_hdr_hdl, it_client->l2tp_rt_rule_hdl[j].first_pass_hdr_proc_ctx_hdl[IPA_IP_v4],
+ it_client->l2tp_rt_rule_hdl[j].first_pass_hdr_proc_ctx_hdl[IPA_IP_v6]);
+ IPACMDBG_H("Second pass hdr hdl: %d\n", it_client->l2tp_rt_rule_hdl[j].second_pass_hdr_hdl);
+
+ IPACMDBG_H("Printing l2tp routing rule info for l2tp client.\n");
+ IPACMDBG_H("Number of IPv4 routing rules is %d, first pass handles:\n", it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v4]);
+ for(k = 0; k < it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v4]; k++)
+ {
+ IPACMDBG_H("%d\n", it_client->l2tp_rt_rule_hdl[j].first_pass_rt_rule_hdl[IPA_IP_v4][k]);
+ }
+ IPACMDBG_H("Number of IPv6 routing rules is %d, first pass handles:\n", it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v6]);
+ for(k = 0; k < it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v6]; k++)
+ {
+ IPACMDBG_H("%d\n", it_client->l2tp_rt_rule_hdl[j].first_pass_rt_rule_hdl[IPA_IP_v6][k]);
+ }
+ IPACMDBG_H("Second pass handles:\n");
+ for(k = 0; k < it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v6]; k++)
+ {
+ IPACMDBG_H("%d\n", it_client->l2tp_rt_rule_hdl[j].second_pass_rt_rule_hdl[k]);
+ }
+ }
+ else
+ {
+ if(IPACM_LanToLan::get_instance()->has_l2tp_iface())
+ {
+ IPACMDBG_H("Printing l2tp hdr info for non l2tp client.\n");
+ IPACMDBG_H("Hdr hdl: %d, IPv4 hdr proc ctx hdl: IPv6 hdr proc ctx hdl: %d\n",
+ it_client->l2tp_rt_rule_hdl[j].first_pass_hdr_hdl, it_client->l2tp_rt_rule_hdl[j].first_pass_hdr_proc_ctx_hdl[IPA_IP_v4],
+ it_client->l2tp_rt_rule_hdl[j].first_pass_hdr_proc_ctx_hdl[IPA_IP_v6]);
+
+ IPACMDBG_H("Printing l2tp routing rule info for non l2tp client.\n");
+ IPACMDBG_H("Number of IPv4 routing rules is %d, handles:\n", it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v4]);
+ for(k = 0; k < it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v4]; k++)
+ {
+ IPACMDBG_H("%d\n", it_client->l2tp_rt_rule_hdl[j].first_pass_rt_rule_hdl[IPA_IP_v4][k]);
+ }
+ IPACMDBG_H("Number of IPv6 routing rules is %d, handles:\n", it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v6]);
+ for(k = 0; k < it_client->l2tp_rt_rule_hdl[j].num_rt_hdl[IPA_IP_v6]; k++)
+ {
+ IPACMDBG_H("%d\n", it_client->l2tp_rt_rule_hdl[j].first_pass_rt_rule_hdl[IPA_IP_v6][k]);
+ }
+ }
+ }
+#endif
+ }
+ }
+ }
+
+ if(m_support_intra_iface_offload)
+ {
+ IPACMDBG_H("Printing routing rule info for intra-interface communication.\n");
+ IPACMDBG_H("Number of IPv4 routing rules is %d, handles:\n", it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4]);
+ for(j = 0; j < it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v4]; j++)
+ {
+ IPACMDBG_H("%d\n", it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v4][j]);
+ }
+
+ IPACMDBG_H("Number of IPv6 routing rules is %d, handles:\n", it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6]);
+ for(j = 0; j < it_client->intra_iface_rt_rule_hdl.num_hdl[IPA_IP_v6]; j++)
+ {
+ IPACMDBG_H("%d\n", it_client->intra_iface_rt_rule_hdl.rule_hdl[IPA_IP_v6][j]);
+ }
+ }
+ i++;
+ }
+
+ IPACMDBG_H("There are %d peer interfaces in total.\n", m_peer_iface_info.size());
+ for(it_peer = m_peer_iface_info.begin(); it_peer != m_peer_iface_info.end(); it_peer++)
+ {
+ print_peer_info(&(*it_peer));
+ }
+
+ if(m_support_intra_iface_offload)
+ {
+ IPACMDBG_H("This interface supports intra-interface communication, printing info:\n");
+ print_peer_info(&m_intra_interface_info);
+ }
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::print_peer_info(peer_iface_info *peer_info)
+{
+ list<flt_rule_info>::iterator it_flt;
+ list<rt_rule_info>::iterator it_rt;
+
+ IPACMDBG_H("Printing peer info for iface %s:\n", peer_info->peer->m_p_iface->dev_name);
+
+ IPACMDBG_H("There are %d flt info in total.\n", peer_info->flt_rule.size());
+ for(it_flt = peer_info->flt_rule.begin(); it_flt != peer_info->flt_rule.end(); it_flt++)
+ {
+ IPACMDBG_H("Flt rule handle for client 0x%08x:\n", it_flt->p_client);
+ if(m_is_ip_addr_assigned[IPA_IP_v4])
+ {
+ IPACMDBG_H("IPv4 %d\n", it_flt->flt_rule_hdl[IPA_IP_v4]);
+ IPACMDBG_H("IPv4 l2tp first pass flt rule: %d\n", it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v4]);
+ }
+ if(m_is_ip_addr_assigned[IPA_IP_v6])
+ {
+ IPACMDBG_H("IPv6 %d\n", it_flt->flt_rule_hdl[IPA_IP_v6]);
+ IPACMDBG_H("IPv6 l2tp first pass flt rule: %d\n", it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6]);
+ }
+ IPACMDBG_H("L2tp second pass flt rule: %d\n", it_flt->l2tp_second_pass_flt_rule_hdl);
+ }
+
+ return;
+}
+
+IPACM_Lan* IPACM_LanToLan_Iface::get_iface_pointer()
+{
+ return m_p_iface;
+}
+
+bool IPACM_LanToLan_Iface::get_m_is_ip_addr_assigned(ipa_ip_type iptype)
+{
+ IPACMDBG_H("Has IP address been assigned to interface %s for IP type %d? %d\n",
+ m_p_iface->dev_name, iptype, m_is_ip_addr_assigned[iptype]);
+ return m_is_ip_addr_assigned[iptype];
+}
+
+void IPACM_LanToLan_Iface::set_m_is_ip_addr_assigned(ipa_ip_type iptype, bool value)
+{
+ IPACMDBG_H("Is IP address of IP type %d assigned to interface %s? %d\n", iptype,
+ m_p_iface->dev_name, value);
+ m_is_ip_addr_assigned[iptype] = value;
+}
+
+bool IPACM_LanToLan_Iface::get_m_support_inter_iface_offload()
+{
+ IPACMDBG_H("Support inter interface offload on %s? %d\n", m_p_iface->dev_name,
+ m_support_inter_iface_offload);
+ return m_support_inter_iface_offload;
+}
+
+bool IPACM_LanToLan_Iface::get_m_support_intra_iface_offload()
+{
+ IPACMDBG_H("Support intra interface offload on %s? %d\n", m_p_iface->dev_name,
+ m_support_intra_iface_offload);
+ return m_support_intra_iface_offload;
+}
+
+void IPACM_LanToLan_Iface::increment_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type)
+{
+ ref_cnt_peer_l2_hdr_type[peer_l2_type]++;
+ IPACMDBG_H("Now the ref_cnt of peer l2 hdr type %s is %d.\n", ipa_l2_hdr_type[peer_l2_type],
+ ref_cnt_peer_l2_hdr_type[peer_l2_type]);
+
+ return;
+}
+
+void IPACM_LanToLan_Iface::decrement_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type)
+{
+ ref_cnt_peer_l2_hdr_type[peer_l2_type]--;
+ IPACMDBG_H("Now the ref_cnt of peer l2 hdr type %s is %d.\n", ipa_l2_hdr_type[peer_l2_type],
+ ref_cnt_peer_l2_hdr_type[peer_l2_type]);
+
+ return;
+}
+
+#ifdef FEATURE_L2TP
+bool IPACM_LanToLan_Iface::set_l2tp_iface(char *vlan_iface_name)
+{
+ IPACMDBG_H("Self iface %s, vlan iface %s\n", m_p_iface->dev_name,
+ vlan_iface_name);
+
+ if(m_is_l2tp_iface == false)
+ {
+ if(strncmp(m_p_iface->dev_name, vlan_iface_name, strlen(m_p_iface->dev_name)) == 0)
+ {
+ IPACMDBG_H("This interface is l2tp interface.\n");
+ m_is_l2tp_iface = true;
+ switch_to_l2tp_iface();
+ }
+ }
+ return m_is_l2tp_iface;
+}
+
+bool IPACM_LanToLan_Iface::is_l2tp_iface()
+{
+ return m_is_l2tp_iface;
+}
+
+void IPACM_LanToLan_Iface::switch_to_l2tp_iface()
+{
+ list<peer_iface_info>::iterator it_peer;
+ list<flt_rule_info>::iterator it_flt;
+
+ for(it_peer = m_peer_iface_info.begin(); it_peer != m_peer_iface_info.end(); it_peer++)
+ {
+ for(it_flt = it_peer->flt_rule.begin(); it_flt != it_peer->flt_rule.end(); it_flt++)
+ {
+ if(m_is_ip_addr_assigned[IPA_IP_v4])
+ {
+ m_p_iface->eth_bridge_del_flt_rule(it_flt->flt_rule_hdl[IPA_IP_v4], IPA_IP_v4);
+ IPACMDBG_H("Deleted IPv4 flt rule %d.\n", it_flt->flt_rule_hdl[IPA_IP_v4]);
+ }
+ if(m_is_ip_addr_assigned[IPA_IP_v6])
+ {
+ m_p_iface->eth_bridge_del_flt_rule(it_flt->flt_rule_hdl[IPA_IP_v6], IPA_IP_v6);
+ m_p_iface->add_l2tp_flt_rule(it_flt->p_client->mac_addr, &it_flt->l2tp_first_pass_flt_rule_hdl[IPA_IP_v6]);
+ IPACMDBG_H("Deleted IPv6 flt rule %d.\n", it_flt->flt_rule_hdl[IPA_IP_v6]);
+ }
+ }
+ }
+ return;
+}
+void IPACM_LanToLan_Iface::handle_l2tp_enable()
+{
+ int i;
+ ipa_hdr_l2_type peer_l2_hdr_type;
+ list<peer_iface_info>::iterator it_peer_info;
+ list<client_info>::iterator it_client;
+ bool flag[IPA_HDR_L2_MAX];
+
+ if(m_support_inter_iface_offload)
+ {
+ memset(flag, 0, sizeof(flag));
+ for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end(); it_peer_info++)
+ {
+ if(it_peer_info->peer->is_l2tp_iface())
+ {
+ peer_l2_hdr_type = it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+ flag[peer_l2_hdr_type] = true;
+ }
+ }
+
+ for(i = 0; i < IPA_HDR_L2_MAX; i++)
+ {
+ if(flag[i] == true)
+ {
+ IPACMDBG_H("Add rt rule for peer l2 type %s\n", ipa_l2_hdr_type[i]);
+ for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+ {
+ m_p_iface->add_l2tp_rt_rule(IPA_IP_v6, it_client->mac_addr, &hdr_proc_ctx_for_l2tp,
+ &it_client->l2tp_rt_rule_hdl[i].num_rt_hdl[IPA_IP_v6],
+ it_client->l2tp_rt_rule_hdl[i].first_pass_rt_rule_hdl[IPA_IP_v6]);
+ }
+ }
+ }
+ }
+ return;
+}
+
+void IPACM_LanToLan_Iface::handle_l2tp_disable()
+{
+ int i;
+ ipa_hdr_l2_type peer_l2_hdr_type;
+ list<peer_iface_info>::iterator it_peer_info;
+ list<client_info>::iterator it_client;
+ bool flag[IPA_HDR_L2_MAX];
+
+ if(m_support_inter_iface_offload)
+ {
+ memset(flag, 0, sizeof(flag));
+ for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end(); it_peer_info++)
+ {
+ peer_l2_hdr_type = it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type;
+ flag[peer_l2_hdr_type] = true;
+ }
+
+ for(i = 0; i < IPA_HDR_L2_MAX; i++)
+ {
+ if(flag[i] == true)
+ {
+ IPACMDBG_H("Delete rt rule for peer l2 type %s\n", ipa_l2_hdr_type[i]);
+ for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
+ {
+ m_p_iface->del_l2tp_rt_rule(IPA_IP_v6, it_client->l2tp_rt_rule_hdl[i].num_rt_hdl[IPA_IP_v6],
+ it_client->l2tp_rt_rule_hdl[i].first_pass_rt_rule_hdl[IPA_IP_v6]);
+ }
+ }
+ }
+ }
+ return;
+}
+#endif
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Log.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Log.cpp
new file mode 100644
index 0000000..3e2e668
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Log.cpp
@@ -0,0 +1,102 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_log.cpp
+
+ @brief
+ This file implements the IPAM log functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include "IPACM_Log.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <asm/types.h>
+#include <linux/if.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <IPACM_Defs.h>
+
+/* start IPACMDIAG socket*/
+int create_socket(int *sockfd)
+{
+
+ if ((*sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) == IPACM_FAILURE)
+ {
+ perror("Error creating ipacm_log socket\n");
+ return IPACM_FAILURE;
+ }
+
+ if(fcntl(*sockfd, F_SETFD, FD_CLOEXEC) < 0)
+ {
+ perror("Couldn't set ipacm_log Close on Exec\n");
+ }
+
+ return IPACM_SUCCESS;
+}
+
+void ipacm_log_send( void * user_data)
+{
+ ipacm_log_buffer_t ipacm_log_buffer;
+ int numBytes=0, len;
+ struct sockaddr_un ipacmlog_socket;
+ static int ipacm_log_sockfd = 0;
+
+ if(ipacm_log_sockfd == 0)
+ {
+ /* start ipacm_log socket */
+ if(create_socket(&ipacm_log_sockfd) < 0)
+ {
+ printf("unable to create ipacm_log socket\n");
+ return;
+ }
+ printf("create ipacm_log socket successfully\n");
+ }
+ ipacmlog_socket.sun_family = AF_UNIX;
+ strlcpy(ipacmlog_socket.sun_path, IPACMLOG_FILE,sizeof(ipacmlog_socket.sun_path));
+ len = strlen(ipacmlog_socket.sun_path) + sizeof(ipacmlog_socket.sun_family);
+
+ memcpy(ipacm_log_buffer.user_data, user_data, MAX_BUF_LEN);
+
+ //printf("send : %s\n", ipacm_log_buffer.user_data);
+ if ((numBytes = sendto(ipacm_log_sockfd, (void *)&ipacm_log_buffer, sizeof(ipacm_log_buffer.user_data), 0,
+ (struct sockaddr *)&ipacmlog_socket, len)) == -1)
+ {
+ printf("Send Failed(%d) %s \n",errno,strerror(errno));
+ return;
+ }
+ return;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Main.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Main.cpp
new file mode 100644
index 0000000..d93cef6
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Main.cpp
@@ -0,0 +1,1050 @@
+/*
+Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Main.cpp
+
+ @brief
+ This file implements the IPAM functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+/******************************************************************************
+
+ IPCM_MAIN.C
+
+******************************************************************************/
+
+#include <sys/socket.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "linux/ipa_qmi_service_v01.h"
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Neighbor.h"
+#include "IPACM_IfaceManager.h"
+#include "IPACM_Log.h"
+
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_Netlink.h"
+
+#ifdef FEATURE_IPACM_HAL
+#include "IPACM_OffloadManager.h"
+#include <HAL.h>
+#endif
+
+/* not defined(FEATURE_IPA_ANDROID)*/
+#ifndef FEATURE_IPA_ANDROID
+#include "IPACM_LanToLan.h"
+#endif
+
+#define IPA_DRIVER "/dev/ipa"
+
+#define IPACM_FIREWALL_FILE_NAME "mobileap_firewall.xml"
+#define IPACM_CFG_FILE_NAME "IPACM_cfg.xml"
+#ifdef FEATURE_IPA_ANDROID
+#define IPACM_PID_FILE "/data/vendor/ipa/ipacm.pid"
+#define IPACM_DIR_NAME "/data"
+#else/* defined(FEATURE_IPA_ANDROID) */
+#define IPACM_PID_FILE "/etc/ipacm.pid"
+#define IPACM_DIR_NAME "/etc"
+#endif /* defined(NOT FEATURE_IPA_ANDROID)*/
+#define IPACM_NAME "ipacm"
+
+#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
+#define INOTIFY_BUF_LEN (INOTIFY_EVENT_SIZE + 2*sizeof(IPACM_FIREWALL_FILE_NAME))
+
+#define IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS 3
+#define IPA_DRIVER_WLAN_EVENT_SIZE (sizeof(struct ipa_wlan_msg_ex)+ IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS*sizeof(ipa_wlan_hdr_attrib_val))
+#define IPA_DRIVER_PIPE_STATS_EVENT_SIZE (sizeof(struct ipa_get_data_stats_resp_msg_v01))
+#define IPA_DRIVER_WLAN_META_MSG (sizeof(struct ipa_msg_meta))
+#define IPA_DRIVER_WLAN_BUF_LEN (IPA_DRIVER_PIPE_STATS_EVENT_SIZE + IPA_DRIVER_WLAN_META_MSG)
+
+uint32_t ipacm_event_stats[IPACM_EVENT_MAX];
+bool ipacm_logging = true;
+
+void ipa_is_ipacm_running(void);
+int ipa_get_if_index(char *if_name, int *if_index);
+
+IPACM_Neighbor *neigh;
+IPACM_IfaceManager *ifacemgr;
+
+#ifdef FEATURE_IPACM_HAL
+ IPACM_OffloadManager* OffloadMng;
+ HAL *hal;
+#endif
+
+/* start netlink socket monitor*/
+void* netlink_start(void *param)
+{
+ param = NULL;
+ ipa_nl_sk_fd_set_info_t sk_fdset;
+ int ret_val = 0;
+ memset(&sk_fdset, 0, sizeof(ipa_nl_sk_fd_set_info_t));
+ IPACMDBG_H("netlink starter memset sk_fdset succeeds\n");
+ ret_val = ipa_nl_listener_init(NETLINK_ROUTE, (RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK |
+ RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH |
+ RTNLGRP_IPV6_PREFIX),
+ &sk_fdset, ipa_nl_recv_msg);
+
+ if (ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Failed to initialize IPA netlink event listener\n");
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/* start firewall-rule monitor*/
+void* firewall_monitor(void *param)
+{
+ int length;
+ int wd;
+ char buffer[INOTIFY_BUF_LEN];
+ int inotify_fd;
+ ipacm_cmd_q_data evt_data;
+ uint32_t mask = IN_MODIFY | IN_MOVE;
+
+ param = NULL;
+ inotify_fd = inotify_init();
+ if (inotify_fd < 0)
+ {
+ PERROR("inotify_init");
+ }
+
+ IPACMDBG_H("Waiting for nofications in dir %s with mask: 0x%x\n", IPACM_DIR_NAME, mask);
+
+ wd = inotify_add_watch(inotify_fd,
+ IPACM_DIR_NAME,
+ mask);
+
+ while (1)
+ {
+ length = read(inotify_fd, buffer, INOTIFY_BUF_LEN);
+ if (length < 0)
+ {
+ IPACMERR("inotify read() error return length: %d and mask: 0x%x\n", length, mask);
+ continue;
+ }
+
+ struct inotify_event* event;
+ event = (struct inotify_event*)malloc(length);
+ if(event == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return NULL;
+ }
+ memset(event, 0, length);
+ memcpy(event, buffer, length);
+
+ if (event->len > 0)
+ {
+ if ( (event->mask & IN_MODIFY) || (event->mask & IN_MOVE))
+ {
+ if (event->mask & IN_ISDIR)
+ {
+ IPACMDBG_H("The directory %s was 0x%x\n", event->name, event->mask);
+ }
+ else if (!strncmp(event->name, IPACM_FIREWALL_FILE_NAME, event->len)) // firewall_rule change
+ {
+ IPACMDBG_H("File \"%s\" was 0x%x\n", event->name, event->mask);
+ IPACMDBG_H("The interested file %s .\n", IPACM_FIREWALL_FILE_NAME);
+
+ evt_data.event = IPA_FIREWALL_CHANGE_EVENT;
+ evt_data.evt_data = NULL;
+
+ /* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ else if (!strncmp(event->name, IPACM_CFG_FILE_NAME, event->len)) // IPACM_configuration change
+ {
+ IPACMDBG_H("File \"%s\" was 0x%x\n", event->name, event->mask);
+ IPACMDBG_H("The interested file %s .\n", IPACM_CFG_FILE_NAME);
+
+ evt_data.event = IPA_CFG_CHANGE_EVENT;
+ evt_data.evt_data = NULL;
+
+ /* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ }
+ IPACMDBG_H("Received monitoring event %s.\n", event->name);
+ }
+ free(event);
+ }
+
+ (void)inotify_rm_watch(inotify_fd, wd);
+ (void)close(inotify_fd);
+ return NULL;
+}
+
+
+/* start IPACM wan-driver notifier */
+void* ipa_driver_msg_notifier(void *param)
+{
+ int length, fd, cnt;
+ char buffer[IPA_DRIVER_WLAN_BUF_LEN];
+ struct ipa_msg_meta event_hdr;
+ struct ipa_ecm_msg event_ecm;
+ struct ipa_wan_msg event_wan;
+ struct ipa_wlan_msg_ex event_ex_o;
+ struct ipa_wlan_msg *event_wlan=NULL;
+ struct ipa_wlan_msg_ex *event_ex= NULL;
+ struct ipa_get_data_stats_resp_msg_v01 event_data_stats;
+ struct ipa_get_apn_data_stats_resp_msg_v01 event_network_stats;
+ IPACM_OffloadManager* OffloadMng;
+
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_mac *data = NULL;
+ ipacm_event_data_fid *data_fid = NULL;
+ ipacm_event_data_iptype *data_iptype = NULL;
+ ipacm_event_data_wlan_ex *data_ex;
+ ipa_get_data_stats_resp_msg_v01 *data_tethering_stats = NULL;
+ ipa_get_apn_data_stats_resp_msg_v01 *data_network_stats = NULL;
+#ifdef FEATURE_L2TP
+ ipa_ioc_vlan_iface_info *vlan_info = NULL;
+ ipa_ioc_l2tp_vlan_mapping_info *mapping = NULL;
+#endif
+ ipacm_cmd_q_data new_neigh_evt;
+ ipacm_event_data_all* new_neigh_data;
+
+ param = NULL;
+ fd = open(IPA_DRIVER, O_RDWR);
+ if (fd < 0)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DRIVER);
+ return NULL;
+ }
+
+ while (1)
+ {
+ IPACMDBG_H("Waiting for nofications from IPA driver \n");
+ memset(buffer, 0, sizeof(buffer));
+ memset(&evt_data, 0, sizeof(evt_data));
+ memset(&new_neigh_evt, 0, sizeof(ipacm_cmd_q_data));
+ new_neigh_data = NULL;
+ data = NULL;
+ data_fid = NULL;
+ data_tethering_stats = NULL;
+ data_network_stats = NULL;
+
+ length = read(fd, buffer, IPA_DRIVER_WLAN_BUF_LEN);
+ if (length < 0)
+ {
+ PERROR("didn't read IPA_driver correctly");
+ continue;
+ }
+
+ memcpy(&event_hdr, buffer,sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Message type: %d\n", event_hdr.msg_type);
+ IPACMDBG_H("Event header length received: %d\n",event_hdr.msg_len);
+
+ /* Insert WLAN_DRIVER_EVENT to command queue */
+ switch (event_hdr.msg_type)
+ {
+
+ case SW_ROUTING_ENABLE:
+ IPACMDBG_H("Received SW_ROUTING_ENABLE\n");
+ evt_data.event = IPA_SW_ROUTING_ENABLE;
+ IPACMDBG_H("Not supported anymore\n");
+ continue;
+
+ case SW_ROUTING_DISABLE:
+ IPACMDBG_H("Received SW_ROUTING_DISABLE\n");
+ evt_data.event = IPA_SW_ROUTING_DISABLE;
+ IPACMDBG_H("Not supported anymore\n");
+ continue;
+
+ case WLAN_AP_CONNECT:
+ event_wlan = (struct ipa_wlan_msg *) (buffer + sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Received WLAN_AP_CONNECT name: %s\n",event_wlan->name);
+ IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+ event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_wlan data_fid\n");
+ return NULL;
+ }
+ ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
+ evt_data.event = IPA_WLAN_AP_LINK_UP_EVENT;
+ evt_data.evt_data = data_fid;
+ break;
+
+ case WLAN_AP_DISCONNECT:
+ event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Received WLAN_AP_DISCONNECT name: %s\n",event_wlan->name);
+ IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+ event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_wlan data_fid\n");
+ return NULL;
+ }
+ ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
+ evt_data.event = IPA_WLAN_LINK_DOWN_EVENT;
+ evt_data.evt_data = data_fid;
+ break;
+ case WLAN_STA_CONNECT:
+ event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Received WLAN_STA_CONNECT name: %s\n",event_wlan->name);
+ IPACMDBG_H("STA Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+ event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+ data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+ if(data == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_wlan data_fid\n");
+ return NULL;
+ }
+ memcpy(data->mac_addr,
+ event_wlan->mac_addr,
+ sizeof(event_wlan->mac_addr));
+ ipa_get_if_index(event_wlan->name, &(data->if_index));
+ evt_data.event = IPA_WLAN_STA_LINK_UP_EVENT;
+ evt_data.evt_data = data;
+ break;
+
+ case WLAN_STA_DISCONNECT:
+ event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Received WLAN_STA_DISCONNECT name: %s\n",event_wlan->name);
+ IPACMDBG_H("STA Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+ event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_wlan data_fid\n");
+ return NULL;
+ }
+ ipa_get_if_index(event_wlan->name, &(data_fid->if_index));
+ evt_data.event = IPA_WLAN_LINK_DOWN_EVENT;
+ evt_data.evt_data = data_fid;
+ break;
+
+ case WLAN_CLIENT_CONNECT:
+ event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Received WLAN_CLIENT_CONNECT\n");
+ IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+ event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+ data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+ if (data == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_wlan data\n");
+ return NULL;
+ }
+ memcpy(data->mac_addr,
+ event_wlan->mac_addr,
+ sizeof(event_wlan->mac_addr));
+ ipa_get_if_index(event_wlan->name, &(data->if_index));
+ evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT;
+ evt_data.evt_data = data;
+ break;
+
+ case WLAN_CLIENT_CONNECT_EX:
+ IPACMDBG_H("Received WLAN_CLIENT_CONNECT_EX\n");
+
+ memcpy(&event_ex_o, buffer + sizeof(struct ipa_msg_meta),sizeof(struct ipa_wlan_msg_ex));
+ if(event_ex_o.num_of_attribs > IPA_DRIVER_WLAN_EVENT_MAX_OF_ATTRIBS)
+ {
+ IPACMERR("buffer size overflow\n");
+ return NULL;
+ }
+ length = sizeof(ipa_wlan_msg_ex)+ event_ex_o.num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val);
+ IPACMDBG_H("num_of_attribs %d, length %d\n", event_ex_o.num_of_attribs, length);
+ event_ex = (ipa_wlan_msg_ex *)malloc(length);
+ if(event_ex == NULL )
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return NULL;
+ }
+ memcpy(event_ex, buffer + sizeof(struct ipa_msg_meta), length);
+ data_ex = (ipacm_event_data_wlan_ex *)malloc(sizeof(ipacm_event_data_wlan_ex) + event_ex_o.num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val));
+ if (data_ex == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data\n");
+ return NULL;
+ }
+ data_ex->num_of_attribs = event_ex->num_of_attribs;
+
+ memcpy(data_ex->attribs,
+ event_ex->attribs,
+ event_ex->num_of_attribs * sizeof(ipa_wlan_hdr_attrib_val));
+
+ ipa_get_if_index(event_ex->name, &(data_ex->if_index));
+ evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT_EX;
+ evt_data.evt_data = data_ex;
+
+ /* Construct new_neighbor msg with netdev device internally */
+ new_neigh_data = (ipacm_event_data_all*)malloc(sizeof(ipacm_event_data_all));
+ if(new_neigh_data == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return NULL;
+ }
+ memset(new_neigh_data, 0, sizeof(ipacm_event_data_all));
+ new_neigh_data->iptype = IPA_IP_v6;
+ for(cnt = 0; cnt < event_ex->num_of_attribs; cnt++)
+ {
+ if(event_ex->attribs[cnt].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+ {
+ memcpy(new_neigh_data->mac_addr, event_ex->attribs[cnt].u.mac_addr, sizeof(new_neigh_data->mac_addr));
+ IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_ex->attribs[cnt].u.mac_addr[0], event_ex->attribs[cnt].u.mac_addr[1], event_ex->attribs[cnt].u.mac_addr[2],
+ event_ex->attribs[cnt].u.mac_addr[3], event_ex->attribs[cnt].u.mac_addr[4], event_ex->attribs[cnt].u.mac_addr[5]);
+ }
+ else if(event_ex->attribs[cnt].attrib_type == WLAN_HDR_ATTRIB_STA_ID)
+ {
+ IPACMDBG_H("Wlan client id %d\n",event_ex->attribs[cnt].u.sta_id);
+ }
+ else
+ {
+ IPACMDBG_H("Wlan message has unexpected type!\n");
+ }
+ }
+ new_neigh_data->if_index = data_ex->if_index;
+ new_neigh_evt.evt_data = (void*)new_neigh_data;
+ new_neigh_evt.event = IPA_NEW_NEIGH_EVENT;
+ free(event_ex);
+ break;
+
+ case WLAN_CLIENT_DISCONNECT:
+ IPACMDBG_H("Received WLAN_CLIENT_DISCONNECT\n");
+ event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+ event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+ data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+ if (data == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_wlan data\n");
+ return NULL;
+ }
+ memcpy(data->mac_addr,
+ event_wlan->mac_addr,
+ sizeof(event_wlan->mac_addr));
+ ipa_get_if_index(event_wlan->name, &(data->if_index));
+ evt_data.event = IPA_WLAN_CLIENT_DEL_EVENT;
+ evt_data.evt_data = data;
+ break;
+
+ case WLAN_CLIENT_POWER_SAVE_MODE:
+ IPACMDBG_H("Received WLAN_CLIENT_POWER_SAVE_MODE\n");
+ event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+ event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+ data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+ if (data == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_wlan data\n");
+ return NULL;
+ }
+ memcpy(data->mac_addr,
+ event_wlan->mac_addr,
+ sizeof(event_wlan->mac_addr));
+ ipa_get_if_index(event_wlan->name, &(data->if_index));
+ evt_data.event = IPA_WLAN_CLIENT_POWER_SAVE_EVENT;
+ evt_data.evt_data = data;
+ break;
+
+ case WLAN_CLIENT_NORMAL_MODE:
+ IPACMDBG_H("Received WLAN_CLIENT_NORMAL_MODE\n");
+ event_wlan = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ IPACMDBG_H("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event_wlan->mac_addr[0], event_wlan->mac_addr[1], event_wlan->mac_addr[2],
+ event_wlan->mac_addr[3], event_wlan->mac_addr[4], event_wlan->mac_addr[5]);
+ data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+ if (data == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_wlan data\n");
+ return NULL;
+ }
+ memcpy(data->mac_addr,
+ event_wlan->mac_addr,
+ sizeof(event_wlan->mac_addr));
+ ipa_get_if_index(event_wlan->name, &(data->if_index));
+ evt_data.evt_data = data;
+ evt_data.event = IPA_WLAN_CLIENT_RECOVER_EVENT;
+ break;
+
+ case ECM_CONNECT:
+ memcpy(&event_ecm, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_ecm_msg));
+ IPACMDBG_H("Received ECM_CONNECT name: %s\n",event_ecm.name);
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_ecm data_fid\n");
+ return NULL;
+ }
+ data_fid->if_index = event_ecm.ifindex;
+ evt_data.event = IPA_USB_LINK_UP_EVENT;
+ evt_data.evt_data = data_fid;
+ break;
+
+ case ECM_DISCONNECT:
+ memcpy(&event_ecm, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_ecm_msg));
+ IPACMDBG_H("Received ECM_DISCONNECT name: %s\n",event_ecm.name);
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_ecm data_fid\n");
+ return NULL;
+ }
+ data_fid->if_index = event_ecm.ifindex;
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ evt_data.evt_data = data_fid;
+ break;
+ /* Add for 8994 Android case */
+ case WAN_UPSTREAM_ROUTE_ADD:
+ memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
+ IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD name: %s, tethered name: %s\n", event_wan.upstream_ifname, event_wan.tethered_ifname);
+ data_iptype = (ipacm_event_data_iptype *)malloc(sizeof(ipacm_event_data_iptype));
+ if(data_iptype == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_ecm data_iptype\n");
+ return NULL;
+ }
+ ipa_get_if_index(event_wan.upstream_ifname, &(data_iptype->if_index));
+ ipa_get_if_index(event_wan.tethered_ifname, &(data_iptype->if_index_tether));
+ data_iptype->iptype = event_wan.ip;
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+ data_iptype->ipv4_addr_gw = event_wan.ipv4_addr_gw;
+ data_iptype->ipv6_addr_gw[0] = event_wan.ipv6_addr_gw[0];
+ data_iptype->ipv6_addr_gw[1] = event_wan.ipv6_addr_gw[1];
+ data_iptype->ipv6_addr_gw[2] = event_wan.ipv6_addr_gw[2];
+ data_iptype->ipv6_addr_gw[3] = event_wan.ipv6_addr_gw[3];
+ IPACMDBG_H("default gw ipv4 (%x)\n", data_iptype->ipv4_addr_gw);
+ IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
+ data_iptype->ipv6_addr_gw[0], data_iptype->ipv6_addr_gw[1], data_iptype->ipv6_addr_gw[2], data_iptype->ipv6_addr_gw[3]);
+#endif
+ IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", data_iptype->if_index,
+ data_iptype->if_index_tether, data_iptype->iptype);
+ evt_data.event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT;
+ evt_data.evt_data = data_iptype;
+ break;
+ case WAN_UPSTREAM_ROUTE_DEL:
+ memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
+ IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL name: %s, tethered name: %s\n", event_wan.upstream_ifname, event_wan.tethered_ifname);
+ data_iptype = (ipacm_event_data_iptype *)malloc(sizeof(ipacm_event_data_iptype));
+ if(data_iptype == NULL)
+ {
+ IPACMERR("unable to allocate memory for event_ecm data_iptype\n");
+ return NULL;
+ }
+ ipa_get_if_index(event_wan.upstream_ifname, &(data_iptype->if_index));
+ ipa_get_if_index(event_wan.tethered_ifname, &(data_iptype->if_index_tether));
+ data_iptype->iptype = event_wan.ip;
+ IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_DEL: fid(%d) ip-type(%d)\n", data_iptype->if_index, data_iptype->iptype);
+ evt_data.event = IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT;
+ evt_data.evt_data = data_iptype;
+ break;
+ /* End of adding for 8994 Android case */
+
+ /* Add for embms case */
+ case WAN_EMBMS_CONNECT:
+ memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_wan_msg));
+ IPACMDBG("Received WAN_EMBMS_CONNECT name: %s\n",event_wan.upstream_ifname);
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return NULL;
+ }
+ ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
+ evt_data.event = IPA_WAN_EMBMS_LINK_UP_EVENT;
+ evt_data.evt_data = data_fid;
+ break;
+
+ case WLAN_SWITCH_TO_SCC:
+ IPACMDBG_H("Received WLAN_SWITCH_TO_SCC\n");
+ case WLAN_WDI_ENABLE:
+ IPACMDBG_H("Received WLAN_WDI_ENABLE\n");
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+ {
+ IPACM_Iface::ipacmcfg->isMCC_Mode = false;
+ evt_data.event = IPA_WLAN_SWITCH_TO_SCC;
+ break;
+ }
+ continue;
+ case WLAN_SWITCH_TO_MCC:
+ IPACMDBG_H("Received WLAN_SWITCH_TO_MCC\n");
+ case WLAN_WDI_DISABLE:
+ IPACMDBG_H("Received WLAN_WDI_DISABLE\n");
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == false)
+ {
+ IPACM_Iface::ipacmcfg->isMCC_Mode = true;
+ evt_data.event = IPA_WLAN_SWITCH_TO_MCC;
+ break;
+ }
+ continue;
+
+ case WAN_XLAT_CONNECT:
+ memcpy(&event_wan, buffer + sizeof(struct ipa_msg_meta),
+ sizeof(struct ipa_wan_msg));
+ IPACMDBG_H("Received WAN_XLAT_CONNECT name: %s\n",
+ event_wan.upstream_ifname);
+
+ /* post IPA_LINK_UP_EVENT event
+ * may be WAN interface is not up
+ */
+ data_fid = (ipacm_event_data_fid *)calloc(1, sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for xlat event\n");
+ return NULL;
+ }
+ ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
+ evt_data.event = IPA_LINK_UP_EVENT;
+ evt_data.evt_data = data_fid;
+ IPACMDBG_H("Posting IPA_LINK_UP_EVENT event:%d\n", evt_data.event);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+ /* post IPA_WAN_XLAT_CONNECT_EVENT event */
+ memset(&evt_data, 0, sizeof(evt_data));
+ data_fid = (ipacm_event_data_fid *)calloc(1, sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for xlat event\n");
+ return NULL;
+ }
+ ipa_get_if_index(event_wan.upstream_ifname, &(data_fid->if_index));
+ evt_data.event = IPA_WAN_XLAT_CONNECT_EVENT;
+ evt_data.evt_data = data_fid;
+ IPACMDBG_H("Posting IPA_WAN_XLAT_CONNECT_EVENT event:%d\n", evt_data.event);
+ break;
+
+ case IPA_TETHERING_STATS_UPDATE_STATS:
+ memcpy(&event_data_stats, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_get_data_stats_resp_msg_v01));
+ data_tethering_stats = (ipa_get_data_stats_resp_msg_v01 *)malloc(sizeof(struct ipa_get_data_stats_resp_msg_v01));
+ if(data_tethering_stats == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_tethering_stats\n");
+ return NULL;
+ }
+ memcpy(data_tethering_stats,
+ &event_data_stats,
+ sizeof(struct ipa_get_data_stats_resp_msg_v01));
+ IPACMDBG("Received IPA_TETHERING_STATS_UPDATE_STATS ipa_stats_type: %d\n",data_tethering_stats->ipa_stats_type);
+ IPACMDBG("Received %d UL, %d DL pipe stats\n",data_tethering_stats->ul_src_pipe_stats_list_len, data_tethering_stats->dl_dst_pipe_stats_list_len);
+ evt_data.event = IPA_TETHERING_STATS_UPDATE_EVENT;
+ evt_data.evt_data = data_tethering_stats;
+ break;
+
+ case IPA_TETHERING_STATS_UPDATE_NETWORK_STATS:
+ memcpy(&event_network_stats, buffer + sizeof(struct ipa_msg_meta), sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
+ data_network_stats = (ipa_get_apn_data_stats_resp_msg_v01 *)malloc(sizeof(ipa_get_apn_data_stats_resp_msg_v01));
+ if(data_network_stats == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_network_stats\n");
+ return NULL;
+ }
+ memcpy(data_network_stats,
+ &event_network_stats,
+ sizeof(struct ipa_get_apn_data_stats_resp_msg_v01));
+ IPACMDBG("Received %d apn network stats \n", data_network_stats->apn_data_stats_list_len);
+ evt_data.event = IPA_NETWORK_STATS_UPDATE_EVENT;
+ evt_data.evt_data = data_network_stats;
+ break;
+
+#ifdef FEATURE_IPACM_HAL
+ case IPA_QUOTA_REACH:
+ IPACMDBG_H("Received IPA_QUOTA_REACH\n");
+ OffloadMng = IPACM_OffloadManager::GetInstance();
+ if (OffloadMng->elrInstance == NULL) {
+ IPACMERR("OffloadMng->elrInstance is NULL, can't forward to framework!\n");
+ } else {
+ IPACMERR("calling OffloadMng->elrInstance->onLimitReached \n");
+ OffloadMng->elrInstance->onLimitReached();
+ }
+ continue;
+ case IPA_SSR_BEFORE_SHUTDOWN:
+ IPACMDBG_H("Received IPA_SSR_BEFORE_SHUTDOWN\n");
+ OffloadMng = IPACM_OffloadManager::GetInstance();
+ if (OffloadMng->elrInstance == NULL) {
+ IPACMERR("OffloadMng->elrInstance is NULL, can't forward to framework!\n");
+ } else {
+ IPACMERR("calling OffloadMng->elrInstance->onOffloadStopped \n");
+ OffloadMng->elrInstance->onOffloadStopped(IpaEventRelay::ERROR);
+ }
+ /* WA to clean up wlan instances during SSR */
+ evt_data.event = IPA_SSR_NOTICE;
+ evt_data.evt_data = NULL;
+ break;
+ case IPA_SSR_AFTER_POWERUP:
+ IPACMDBG_H("Received IPA_SSR_AFTER_POWERUP\n");
+ OffloadMng = IPACM_OffloadManager::GetInstance();
+ if (OffloadMng->elrInstance == NULL) {
+ IPACMERR("OffloadMng->elrInstance is NULL, can't forward to framework!\n");
+ } else {
+ IPACMERR("calling OffloadMng->elrInstance->onOffloadSupportAvailable \n");
+ OffloadMng->elrInstance->onOffloadSupportAvailable();
+ }
+ continue;
+#endif
+#ifdef FEATURE_L2TP
+ case ADD_VLAN_IFACE:
+ vlan_info = (ipa_ioc_vlan_iface_info *)malloc(sizeof(*vlan_info));
+ if(vlan_info == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return NULL;
+ }
+ memcpy(vlan_info, buffer + sizeof(struct ipa_msg_meta), sizeof(*vlan_info));
+ evt_data.event = IPA_ADD_VLAN_IFACE;
+ evt_data.evt_data = vlan_info;
+ break;
+
+ case DEL_VLAN_IFACE:
+ vlan_info = (ipa_ioc_vlan_iface_info *)malloc(sizeof(*vlan_info));
+ if(vlan_info == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return NULL;
+ }
+ memcpy(vlan_info, buffer + sizeof(struct ipa_msg_meta), sizeof(*vlan_info));
+ evt_data.event = IPA_DEL_VLAN_IFACE;
+ evt_data.evt_data = vlan_info;
+ break;
+
+ case ADD_L2TP_VLAN_MAPPING:
+ mapping = (ipa_ioc_l2tp_vlan_mapping_info *)malloc(sizeof(*mapping));
+ if(mapping == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return NULL;
+ }
+ memcpy(mapping, buffer + sizeof(struct ipa_msg_meta), sizeof(*mapping));
+ evt_data.event = IPA_ADD_L2TP_VLAN_MAPPING;
+ evt_data.evt_data = mapping;
+ break;
+
+ case DEL_L2TP_VLAN_MAPPING:
+ mapping = (ipa_ioc_l2tp_vlan_mapping_info *)malloc(sizeof(*mapping));
+ if(mapping == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return NULL;
+ }
+ memcpy(mapping, buffer + sizeof(struct ipa_msg_meta), sizeof(*mapping));
+ evt_data.event = IPA_DEL_L2TP_VLAN_MAPPING;
+ evt_data.evt_data = mapping;
+ break;
+#endif
+ default:
+ IPACMDBG_H("Unhandled message type: %d\n", event_hdr.msg_type);
+ continue;
+
+ }
+ /* finish command queue */
+ IPACMDBG_H("Posting event:%d\n", evt_data.event);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* push new_neighbor with netdev device internally */
+ if(new_neigh_data != NULL)
+ {
+ IPACMDBG_H("Internally post event IPA_NEW_NEIGH_EVENT\n");
+ IPACM_EvtDispatcher::PostEvt(&new_neigh_evt);
+ }
+ }
+
+ (void)close(fd);
+ return NULL;
+}
+
+void IPACM_Sig_Handler(int sig)
+{
+ ipacm_cmd_q_data evt_data;
+
+ printf("Received Signal: %d\n", sig);
+ memset(&evt_data, 0, sizeof(evt_data));
+
+ switch(sig)
+ {
+ case SIGUSR1:
+ IPACMDBG_H("Received SW_ROUTING_ENABLE request \n");
+ evt_data.event = IPA_SW_ROUTING_ENABLE;
+ IPACM_Iface::ipacmcfg->ipa_sw_rt_enable = true;
+ break;
+
+ case SIGUSR2:
+ IPACMDBG_H("Received SW_ROUTING_DISABLE request \n");
+ evt_data.event = IPA_SW_ROUTING_DISABLE;
+ IPACM_Iface::ipacmcfg->ipa_sw_rt_enable = false;
+ break;
+ }
+ /* finish command queue */
+ IPACMDBG_H("Posting event:%d\n", evt_data.event);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ return;
+}
+
+void RegisterForSignals(void)
+{
+
+ signal(SIGUSR1, IPACM_Sig_Handler);
+ signal(SIGUSR2, IPACM_Sig_Handler);
+}
+
+
+int main(int argc, char **argv)
+{
+ int ret;
+ pthread_t netlink_thread = 0, monitor_thread = 0, ipa_driver_thread = 0;
+ pthread_t cmd_queue_thread = 0;
+
+ /* check if ipacm is already running or not */
+ ipa_is_ipacm_running();
+
+ IPACMDBG_H("In main()\n");
+ (void)argc;
+ (void)argv;
+
+ neigh = new IPACM_Neighbor();
+ ifacemgr = new IPACM_IfaceManager();
+
+#ifdef FEATURE_IPACM_HAL
+ OffloadMng = IPACM_OffloadManager::GetInstance();
+ hal = HAL::makeIPAHAL(1, OffloadMng);
+ IPACMDBG_H(" START IPACM_OffloadManager and link to android framework\n");
+#endif
+
+#ifdef FEATURE_ETH_BRIDGE_LE
+ IPACM_LanToLan* lan2lan = IPACM_LanToLan::get_instance();
+#endif
+
+ CtList = new IPACM_ConntrackListener();
+
+ IPACMDBG_H("Staring IPA main\n");
+ IPACMDBG_H("ipa_cmdq_successful\n");
+
+
+ RegisterForSignals();
+
+ if (IPACM_SUCCESS == cmd_queue_thread)
+ {
+ ret = pthread_create(&cmd_queue_thread, NULL, MessageQueue::Process, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to command queue thread\n");
+ return ret;
+ }
+ IPACMDBG_H("created command queue thread\n");
+ if(pthread_setname_np(cmd_queue_thread, "cmd queue process") != 0)
+ {
+ IPACMERR("unable to set thread name\n");
+ }
+ }
+
+ if (IPACM_SUCCESS == netlink_thread)
+ {
+ ret = pthread_create(&netlink_thread, NULL, netlink_start, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to create netlink thread\n");
+ return ret;
+ }
+ IPACMDBG_H("created netlink thread\n");
+ if(pthread_setname_np(netlink_thread, "netlink socket") != 0)
+ {
+ IPACMERR("unable to set thread name\n");
+ }
+ }
+
+ /* Enable Firewall support only on MDM targets */
+#ifndef FEATURE_IPA_ANDROID
+ if (IPACM_SUCCESS == monitor_thread)
+ {
+ ret = pthread_create(&monitor_thread, NULL, firewall_monitor, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to create monitor thread\n");
+ return ret;
+ }
+ IPACMDBG_H("created firewall monitor thread\n");
+ if(pthread_setname_np(monitor_thread, "firewall cfg process") != 0)
+ {
+ IPACMERR("unable to set thread name\n");
+ }
+ }
+#endif
+
+ if (IPACM_SUCCESS == ipa_driver_thread)
+ {
+ ret = pthread_create(&ipa_driver_thread, NULL, ipa_driver_msg_notifier, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to create ipa_driver_wlan thread\n");
+ return ret;
+ }
+ IPACMDBG_H("created ipa_driver_wlan thread\n");
+ if(pthread_setname_np(ipa_driver_thread, "ipa driver ntfy") != 0)
+ {
+ IPACMERR("unable to set thread name\n");
+ }
+ }
+
+ pthread_join(cmd_queue_thread, NULL);
+ pthread_join(netlink_thread, NULL);
+ pthread_join(monitor_thread, NULL);
+ pthread_join(ipa_driver_thread, NULL);
+ return IPACM_SUCCESS;
+}
+
+/*===========================================================================
+ FUNCTION ipa_is_ipacm_running
+===========================================================================*/
+/*!
+@brief
+ Determine whether there's already an IPACM process running, if so, terminate
+ the current one
+
+@return
+ None
+
+@note
+
+- Dependencies
+ - None
+
+- Side Effects
+ - None
+*/
+/*=========================================================================*/
+
+void ipa_is_ipacm_running(void) {
+
+ int fd;
+ struct flock lock;
+ int retval;
+
+ fd = open(IPACM_PID_FILE, O_RDWR | O_CREAT, 0600);
+ if ( fd <= 0 )
+ {
+ IPACMERR("Failed to open %s, error is %d - %s\n",
+ IPACM_PID_FILE, errno, strerror(errno));
+ exit(0);
+ }
+
+ /*
+ * Getting an exclusive Write lock on the file, if it fails,
+ * it means that another instance of IPACM is running and it
+ * got the lock before us.
+ */
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_WRLCK;
+ retval = fcntl(fd, F_SETLK, &lock);
+
+ if (retval != 0)
+ {
+ retval = fcntl(fd, F_GETLK, &lock);
+ if (retval == 0)
+ {
+ IPACMERR("Unable to get lock on file %s (my PID %d), PID %d already has it\n",
+ IPACM_PID_FILE, getpid(), lock.l_pid);
+ close(fd);
+ exit(0);
+ }
+ }
+ else
+ {
+ IPACMERR("PID %d is IPACM main process\n", getpid());
+ }
+
+ return;
+}
+
+/*===========================================================================
+ FUNCTION ipa_get_if_index
+===========================================================================*/
+/*!
+@brief
+ get ipa interface index by given the interface name
+
+@return
+ IPACM_SUCCESS or IPA_FALUIRE
+
+@note
+
+- Dependencies
+ - None
+
+- Side Effects
+ - None
+*/
+/*=========================================================================*/
+int ipa_get_if_index
+(
+ char *if_name,
+ int *if_index
+ )
+{
+ int fd;
+ struct ifreq ifr;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ PERROR("get interface index socket create failed");
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ (void)strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
+ {
+ IPACMERR("call_ioctl_on_dev: ioctl failed: can't find device %s",if_name);
+ *if_index = -1;
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ *if_index = ifr.ifr_ifindex;
+ close(fd);
+ return IPACM_SUCCESS;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Neighbor.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Neighbor.cpp
new file mode 100644
index 0000000..5ed5453
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Neighbor.cpp
@@ -0,0 +1,580 @@
+/*
+Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Neighbor.cpp
+
+ @brief
+ This file implements the functionality of handling IPACM Neighbor events.
+
+ @Author
+ Skylar Chang
+
+*/
+
+#include <sys/ioctl.h>
+#include <IPACM_Neighbor.h>
+#include <IPACM_EvtDispatcher.h>
+#include "IPACM_Defs.h"
+#include "IPACM_Log.h"
+
+
+IPACM_Neighbor::IPACM_Neighbor()
+{
+ num_neighbor_client = 0;
+ circular_index = 0;
+ memset(neighbor_client, 0, IPA_MAX_NUM_NEIGHBOR_CLIENTS * sizeof(ipa_neighbor_client));
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT_EX, this);
+ IPACM_EvtDispatcher::registr(IPA_NEW_NEIGH_EVENT, this);
+ IPACM_EvtDispatcher::registr(IPA_DEL_NEIGH_EVENT, this);
+ return;
+}
+
+void IPACM_Neighbor::event_callback(ipa_cm_event_id event, void *param)
+{
+ ipacm_event_data_all *data_all = NULL;
+ int i, ipa_interface_index;
+ ipacm_cmd_q_data evt_data;
+ int num_neighbor_client_temp = num_neighbor_client;
+
+ IPACMDBG("Recieved event %d\n", event);
+
+ switch (event)
+ {
+ case IPA_WLAN_CLIENT_ADD_EVENT_EX:
+ {
+ ipacm_event_data_wlan_ex *data = (ipacm_event_data_wlan_ex *)param;
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("IPA_WLAN_CLIENT_ADD_EVENT_EX: not supported iface id: %d\n", data->if_index);
+ break;
+ }
+ uint8_t client_mac_addr[6] = {0};
+
+ IPACMDBG_H("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
+ for(i = 0; i < data->num_of_attribs; i++)
+ {
+ if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+ {
+ memcpy(client_mac_addr,
+ data->attribs[i].u.mac_addr,
+ sizeof(client_mac_addr));
+ IPACMDBG_H("AP Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ client_mac_addr[0], client_mac_addr[1], client_mac_addr[2],
+ client_mac_addr[3], client_mac_addr[4], client_mac_addr[5]);
+ }
+ else
+ {
+ IPACMDBG_H("The attribute type is not expected!\n");
+ }
+ }
+
+ for (i = 0; i < num_neighbor_client_temp; i++)
+ {
+ /* find the client */
+ if (memcmp(neighbor_client[i].mac_addr, client_mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+ {
+ /* check if iface is not bridge interface*/
+ if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
+ {
+ /* use previous ipv4 first */
+ if(data->if_index != neighbor_client[i].iface_index)
+ {
+ IPACMERR("update new kernel iface index \n");
+ neighbor_client[i].iface_index = data->if_index;
+ }
+
+ /* check if client associated with previous network interface */
+ if(ipa_interface_index != neighbor_client[i].ipa_if_num)
+ {
+ IPACMERR("client associate to different AP \n");
+ return;
+ }
+
+ if (neighbor_client[i].v4_addr != 0) /* not 0.0.0.0 */
+ {
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if (data_all == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+ memset(data_all,0,sizeof(ipacm_event_data_all));
+ data_all->iptype = IPA_IP_v4;
+ data_all->if_index = neighbor_client[i].iface_index;
+ data_all->ipv4_addr = neighbor_client[i].v4_addr; //use previous ipv4 address
+ memcpy(data_all->mac_addr,
+ neighbor_client[i].mac_addr,
+ sizeof(data_all->mac_addr));
+ memcpy(data_all->iface_name, neighbor_client[i].iface_name,
+ sizeof(data_all->iface_name));
+ evt_data.evt_data = (void *)data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* ask for replaced iface name*/
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("not supported iface id: %d\n", data_all->if_index);
+ } else {
+ IPACMDBG_H("Posted event %d, with %s for ipv4 client re-connect\n",
+ evt_data.event,
+ data_all->iface_name);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ if (event == IPA_NEW_NEIGH_EVENT)
+ {
+ IPACMDBG_H("Received IPA_NEW_NEIGH_EVENT\n");
+ }
+ else
+ {
+ IPACMDBG_H("Received IPA_DEL_NEIGH_EVENT\n");
+ }
+
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+#ifndef FEATURE_L2TP
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("not supported iface id: %d\n", data->if_index);
+ break;
+ }
+#endif
+ if (data->iptype == IPA_IP_v4)
+ {
+ if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+ {
+ IPACMDBG("Got Neighbor event with ipv4 address: 0x%x \n", data->ipv4_addr);
+ /* check if ipv4 address is link local(169.254.xxx.xxx) */
+ if ((data->ipv4_addr & IPV4_ADDR_LINKLOCAL_MASK) == IPV4_ADDR_LINKLOCAL)
+ {
+ IPACMDBG_H("This is link local ipv4 address: 0x%x : ignore this NEIGH_EVENT\n", data->ipv4_addr);
+ return;
+ }
+ /* check if iface is bridge interface*/
+ if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, data->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;
+ strlcpy(data->iface_name, neighbor_client[i].iface_name, sizeof(data->iface_name));
+ neighbor_client[i].v4_addr = data->ipv4_addr; // cache client's previous ipv4 address
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+ if (event == IPA_NEW_NEIGH_EVENT)
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ else
+ /* not to clean-up the client mac cache on bridge0 delneigh */
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if (data_all == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+ memcpy(data_all, data, sizeof(ipacm_event_data_all));
+ evt_data.evt_data = (void *)data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+ /* ask for replaced iface name*/
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("not supported iface id: %d\n", data_all->if_index);
+ } else {
+ IPACMDBG_H("Posted event %d,\
+ with %s for ipv4\n",
+ evt_data.event,
+ data->iface_name);
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+ if (event == IPA_NEW_NEIGH_EVENT)
+ {
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ /* Also save to cache for ipv4 */
+ /*searh if seen this client or not*/
+ for (i = 0; i < num_neighbor_client_temp; i++)
+ {
+ /* find the client */
+ if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+ {
+ /* update the network interface client associated */
+ neighbor_client[i].iface_index = data->if_index;
+ neighbor_client[i].ipa_if_num = ipa_interface_index;
+ neighbor_client[i].v4_addr = data->ipv4_addr; // cache client's previous ipv4 address
+ strlcpy(neighbor_client[i].iface_name, data->iface_name, sizeof(neighbor_client[i].iface_name));
+ IPACMDBG_H("update cache %d-entry, with %s iface, ipv4 address: 0x%x\n",
+ i, data->iface_name, data->ipv4_addr);
+ break;
+ }
+ }
+ /* not find client */
+ if (i == num_neighbor_client_temp)
+ {
+ if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
+ {
+ memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
+ data->mac_addr,
+ sizeof(data->mac_addr));
+ neighbor_client[num_neighbor_client_temp].iface_index = data->if_index;
+ /* cache the network interface client associated */
+ neighbor_client[num_neighbor_client_temp].ipa_if_num = ipa_interface_index;
+ neighbor_client[num_neighbor_client_temp].v4_addr = data->ipv4_addr;
+ strlcpy(neighbor_client[num_neighbor_client_temp].iface_name,
+ data->iface_name, sizeof(neighbor_client[num_neighbor_client_temp].iface_name));
+ num_neighbor_client++;
+ IPACMDBG_H("Cache client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+ neighbor_client[num_neighbor_client_temp].mac_addr[0],
+ neighbor_client[num_neighbor_client_temp].mac_addr[1],
+ neighbor_client[num_neighbor_client_temp].mac_addr[2],
+ neighbor_client[num_neighbor_client_temp].mac_addr[3],
+ neighbor_client[num_neighbor_client_temp].mac_addr[4],
+ neighbor_client[num_neighbor_client_temp].mac_addr[5],
+ num_neighbor_client);
+ }
+ else
+ {
+
+ IPACMERR("error: neighbor client oversize! recycle %d-st entry ! \n", circular_index);
+ memcpy(neighbor_client[circular_index].mac_addr,
+ data->mac_addr,
+ sizeof(data->mac_addr));
+ neighbor_client[circular_index].iface_index = data->if_index;
+ /* cache the network interface client associated */
+ neighbor_client[circular_index].ipa_if_num = ipa_interface_index;
+ neighbor_client[circular_index].v4_addr = 0;
+ strlcpy(neighbor_client[circular_index].iface_name,
+ data->iface_name, sizeof(neighbor_client[circular_index].iface_name));
+ IPACMDBG_H("Copy wlan-iface client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d, circular %d\n",
+ neighbor_client[circular_index].mac_addr[0],
+ neighbor_client[circular_index].mac_addr[1],
+ neighbor_client[circular_index].mac_addr[2],
+ neighbor_client[circular_index].mac_addr[3],
+ neighbor_client[circular_index].mac_addr[4],
+ neighbor_client[circular_index].mac_addr[5],
+ num_neighbor_client,
+ circular_index);
+ circular_index = (circular_index + 1) % IPA_MAX_NUM_NEIGHBOR_CLIENTS;
+ }
+ }
+ }
+ else
+ {
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+ /*searh if seen this client or not*/
+ for (i = 0; i < num_neighbor_client_temp; i++)
+ {
+ /* find the client */
+ if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+ {
+ IPACMDBG_H("Clean %d-st Cached client-MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+ i,
+ neighbor_client[i].mac_addr[0],
+ neighbor_client[i].mac_addr[1],
+ neighbor_client[i].mac_addr[2],
+ neighbor_client[i].mac_addr[3],
+ neighbor_client[i].mac_addr[4],
+ neighbor_client[i].mac_addr[5],
+ num_neighbor_client);
+
+ memset(neighbor_client[i].mac_addr, 0, sizeof(neighbor_client[i].mac_addr));
+ neighbor_client[i].iface_index = 0;
+ neighbor_client[i].v4_addr = 0;
+ neighbor_client[i].ipa_if_num = 0;
+ memset(neighbor_client[i].iface_name, 0, sizeof(neighbor_client[i].iface_name));
+ for (; i < num_neighbor_client_temp - 1; i++)
+ {
+ memcpy(neighbor_client[i].mac_addr,
+ neighbor_client[i+1].mac_addr,
+ sizeof(neighbor_client[i].mac_addr));
+ neighbor_client[i].iface_index = neighbor_client[i+1].iface_index;
+ neighbor_client[i].v4_addr = neighbor_client[i+1].v4_addr;
+ neighbor_client[i].ipa_if_num = neighbor_client[i+1].ipa_if_num;
+ strlcpy(neighbor_client[i].iface_name, neighbor_client[i+1].iface_name,
+ sizeof(neighbor_client[i].iface_name));
+ }
+ num_neighbor_client--;
+ IPACMDBG_H(" total number of left cased clients: %d\n", num_neighbor_client);
+ break;
+ }
+ }
+ /* not find client, no need clean-up */
+ }
+
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if (data_all == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+ memcpy(data_all, data, sizeof(ipacm_event_data_all));
+ evt_data.evt_data = (void *)data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG_H("Posted event %d with %s for ipv4\n",
+ evt_data.event, data->iface_name);
+ }
+ }
+ }
+ else
+ { //ipv6 starts
+
+ if ((data->ipv6_addr[0]) || (data->ipv6_addr[1]) || (data->ipv6_addr[2]) || (data->ipv6_addr[3]))
+ {
+ IPACMDBG("Got New_Neighbor event with ipv6 address \n");
+ /* check if iface is bridge interface*/
+ if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, data->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;
+ strlcpy(data->iface_name, neighbor_client[i].iface_name, sizeof(data->iface_name));
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+ if (event == IPA_NEW_NEIGH_EVENT) evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ else evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if (data_all == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+ memcpy(data_all, data, sizeof(ipacm_event_data_all));
+ evt_data.evt_data = (void *)data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* ask for replaced iface name*/
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
+ /* check for failure return */
+ if (IPACM_FAILURE == ipa_interface_index) {
+ IPACMERR("not supported iface id: %d\n", data_all->if_index);
+ } else {
+ IPACMDBG_H("Posted event %d,\
+ with %s for ipv6\n",
+ evt_data.event,
+ data->iface_name);
+ }
+ break;
+ };
+ }
+ }
+ else
+ {
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+ if (event == IPA_NEW_NEIGH_EVENT)
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ else
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if (data_all == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+ memcpy(data_all, data, sizeof(ipacm_event_data_all));
+ evt_data.evt_data = (void *)data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG_H("Posted event %d with %s for ipv6\n",
+ evt_data.event, data->iface_name);
+ }
+ }
+ else
+ {
+ IPACMDBG(" Got Neighbor event with no ipv6/ipv4 address \n");
+ /*no ipv6 in data searh if seen this client or not*/
+ for (i = 0; i < num_neighbor_client_temp; i++)
+ {
+ /* find the client */
+ if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+ {
+ IPACMDBG_H(" find %d-st client, MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+ i,
+ neighbor_client[i].mac_addr[0],
+ neighbor_client[i].mac_addr[1],
+ neighbor_client[i].mac_addr[2],
+ neighbor_client[i].mac_addr[3],
+ neighbor_client[i].mac_addr[4],
+ neighbor_client[i].mac_addr[5],
+ num_neighbor_client);
+ /* check if iface is not bridge interface*/
+ if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, data->iface_name) != 0)
+ {
+ /* use previous ipv4 first */
+ if(data->if_index != neighbor_client[i].iface_index)
+ {
+ IPACMDBG_H("update new kernel iface index \n");
+ neighbor_client[i].iface_index = data->if_index;
+ strlcpy(neighbor_client[i].iface_name, data->iface_name, sizeof(neighbor_client[i].iface_name));
+ }
+
+ /* check if client associated with previous network interface */
+ if(ipa_interface_index != neighbor_client[i].ipa_if_num)
+ {
+ IPACMDBG_H("client associate to different AP \n");
+ }
+
+ if (neighbor_client[i].v4_addr != 0) /* not 0.0.0.0 */
+ {
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+ if (event == IPA_NEW_NEIGH_EVENT)
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ else
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if (data_all == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+ data_all->iptype = IPA_IP_v4;
+ data_all->if_index = neighbor_client[i].iface_index;
+ data_all->ipv4_addr = neighbor_client[i].v4_addr; //use previous ipv4 address
+ memcpy(data_all->mac_addr, neighbor_client[i].mac_addr,
+ sizeof(data_all->mac_addr));
+ strlcpy(data_all->iface_name, neighbor_client[i].iface_name, sizeof(data_all->iface_name));
+ evt_data.evt_data = (void *)data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG_H("Posted event %d with %s for ipv4\n",
+ evt_data.event, data_all->iface_name);
+ }
+ }
+ /* delete cache neighbor entry */
+ if (event == IPA_DEL_NEIGH_EVENT)
+ {
+ IPACMDBG_H("Clean %d-st Cached client-MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+ i,
+ neighbor_client[i].mac_addr[0],
+ neighbor_client[i].mac_addr[1],
+ neighbor_client[i].mac_addr[2],
+ neighbor_client[i].mac_addr[3],
+ neighbor_client[i].mac_addr[4],
+ neighbor_client[i].mac_addr[5],
+ num_neighbor_client);
+
+ memset(neighbor_client[i].mac_addr, 0, sizeof(neighbor_client[i].mac_addr));
+ neighbor_client[i].iface_index = 0;
+ neighbor_client[i].v4_addr = 0;
+ neighbor_client[i].ipa_if_num = 0;
+ memset(neighbor_client[i].iface_name, 0, sizeof(neighbor_client[i].iface_name));
+ for (; i < num_neighbor_client_temp - 1; i++)
+ {
+ memcpy(neighbor_client[i].mac_addr,
+ neighbor_client[i+1].mac_addr,
+ sizeof(neighbor_client[i].mac_addr));
+ neighbor_client[i].iface_index = neighbor_client[i+1].iface_index;
+ neighbor_client[i].v4_addr = neighbor_client[i+1].v4_addr;
+ neighbor_client[i].ipa_if_num = neighbor_client[i+1].ipa_if_num;
+ strlcpy(neighbor_client[i].iface_name, neighbor_client[i+1].iface_name,
+ sizeof(neighbor_client[i].iface_name));
+ }
+ num_neighbor_client--;
+ IPACMDBG_H(" total number of left cased clients: %d\n", num_neighbor_client);
+ }
+ break;
+ }
+ }
+ /* not find client */
+ if ((i == num_neighbor_client_temp) && (event == IPA_NEW_NEIGH_EVENT))
+ {
+ /* check if iface is not bridge interface*/
+ if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, data->iface_name) != 0)
+ {
+ if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
+ {
+ memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
+ data->mac_addr,
+ sizeof(data->mac_addr));
+ neighbor_client[num_neighbor_client_temp].iface_index = data->if_index;
+ /* cache the network interface client associated */
+ neighbor_client[num_neighbor_client_temp].ipa_if_num = ipa_interface_index;
+ neighbor_client[num_neighbor_client_temp].v4_addr = 0;
+ strlcpy(neighbor_client[num_neighbor_client_temp].iface_name, data->iface_name,
+ sizeof(neighbor_client[num_neighbor_client_temp].iface_name));
+ num_neighbor_client++;
+ IPACMDBG_H("Copy client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+ neighbor_client[num_neighbor_client_temp].mac_addr[0],
+ neighbor_client[num_neighbor_client_temp].mac_addr[1],
+ neighbor_client[num_neighbor_client_temp].mac_addr[2],
+ neighbor_client[num_neighbor_client_temp].mac_addr[3],
+ neighbor_client[num_neighbor_client_temp].mac_addr[4],
+ neighbor_client[num_neighbor_client_temp].mac_addr[5],
+ num_neighbor_client);
+ return;
+ }
+ else
+ {
+ IPACMERR("error: neighbor client oversize! recycle %d-st entry ! \n", circular_index);
+ memcpy(neighbor_client[circular_index].mac_addr,
+ data->mac_addr,
+ sizeof(data->mac_addr));
+ neighbor_client[circular_index].iface_index = data->if_index;
+ /* cache the network interface client associated */
+ neighbor_client[circular_index].ipa_if_num = ipa_interface_index;
+ neighbor_client[circular_index].v4_addr = 0;
+ strlcpy(neighbor_client[circular_index].iface_name, data->iface_name,
+ sizeof(neighbor_client[circular_index].iface_name));
+ IPACMDBG_H("Copy wlan-iface client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d, circular %d\n",
+ neighbor_client[circular_index].mac_addr[0],
+ neighbor_client[circular_index].mac_addr[1],
+ neighbor_client[circular_index].mac_addr[2],
+ neighbor_client[circular_index].mac_addr[3],
+ neighbor_client[circular_index].mac_addr[4],
+ neighbor_client[circular_index].mac_addr[5],
+ num_neighbor_client,
+ circular_index);
+ circular_index = (circular_index + 1) % IPA_MAX_NUM_NEIGHBOR_CLIENTS;
+ return;
+ }
+ }
+ }
+ }
+ } //ipv6 ends
+ }
+ break;
+ }
+ return;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp
new file mode 100644
index 0000000..e2ecd50
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp
@@ -0,0 +1,1775 @@
+/*
+Copyright (c) 2013-2017, 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"
+
+int ipa_get_if_name(char *if_name, int if_index);
+int find_mask(int ip_v4_last, int *mask_value);
+
+#ifdef FEATURE_IPA_ANDROID
+
+#define IPACM_NL_COPY_ADDR( event_info, element ) \
+ memcpy( &event_info->attr_info.element.__data, \
+ RTA_DATA(rtah), \
+ sizeof(event_info->attr_info.element.__data) );
+
+#define IPACM_EVENT_COPY_ADDR_v6( event_data, element) \
+ memcpy( event_data, element.__data, sizeof(event_data));
+
+#define IPACM_EVENT_COPY_ADDR_v4( event_data, element) \
+ memcpy( &event_data, element.__data, sizeof(event_data));
+
+#define IPACM_NL_REPORT_ADDR( prefix, addr ) \
+ if( AF_INET6 == (addr).ss_family ) { \
+ IPACM_LOG_IPV6_ADDR( prefix, addr.__data); \
+ } else { \
+ IPACM_LOG_IPV4_ADDR( prefix, (*(unsigned int*)&(addr).__data) ); \
+ }
+
+#else/* defined(FEATURE_IPA_ANDROID) */
+
+#define IPACM_NL_COPY_ADDR( event_info, element ) \
+ memcpy( &event_info->attr_info.element.__ss_padding, \
+ RTA_DATA(rtah), \
+ sizeof(event_info->attr_info.element.__ss_padding) );
+
+#define IPACM_EVENT_COPY_ADDR_v6( event_data, element) \
+ memcpy( event_data, element.__ss_padding, sizeof(event_data));
+
+#define IPACM_EVENT_COPY_ADDR_v4( event_data, element) \
+ memcpy( &event_data, element.__ss_padding, sizeof(event_data));
+
+#define IPACM_NL_REPORT_ADDR( prefix, addr ) \
+ if( AF_INET6 == (addr).ss_family ) { \
+ IPACM_LOG_IPV6_ADDR( prefix, addr.__ss_padding); \
+ } else { \
+ IPACM_LOG_IPV4_ADDR( prefix, (*(unsigned int*)&(addr).__ss_padding) ); \
+ }
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#define IPACM_LOG_IPV6_ADDR(prefix, ip_addr) \
+ IPACMDBG_H(prefix); \
+ IPACMDBG_H(" IPV6 Address %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", \
+ (int)ip_addr[0], (int)ip_addr[1], \
+ (int)ip_addr[2], (int)ip_addr[3], \
+ (int)ip_addr[4], (int)ip_addr[5], \
+ (int)ip_addr[6], (int)ip_addr[7], \
+ (int)ip_addr[8], (int)ip_addr[9], \
+ (int)ip_addr[10], (int)ip_addr[11], \
+ (int)ip_addr[12], (int)ip_addr[13], \
+ (int)ip_addr[14], (int)ip_addr[15]);
+
+#define IPACM_LOG_IPV4_ADDR(prefix, ip_addr) \
+ IPACMDBG_H(prefix); \
+ IPACMDBG_H(" IPV4 Address %d.%d.%d.%d\n", \
+ (unsigned char)(ip_addr), \
+ (unsigned char)(ip_addr >> 8), \
+ (unsigned char)(ip_addr >> 16) , \
+ (unsigned char)(ip_addr >> 24));
+
+/* 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;
+ int buf_size = 6669999, sendbuff=0, res;
+ struct sockaddr_nl *p_sk_addr_loc;
+ socklen_t optlen;
+
+ 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;
+ }
+
+ optlen = sizeof(sendbuff);
+ res = getsockopt(*p_sk_fd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);
+
+ if(res == -1) {
+ IPACMDBG("Error getsockopt one");
+ } else {
+ IPACMDBG("orignal send buffer size = %d\n", sendbuff);
+ }
+ IPACMDBG("sets the send buffer to %d\n", buf_size);
+ if (setsockopt(*p_sk_fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(int)) == -1) {
+ IPACMERR("Error setting socket opts\n");
+ }
+
+ /* 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)
+ {
+ IPACMERR("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 *info,
+ int fd,
+ ipa_sock_thrd_fd_read_f read_f
+ )
+{
+ if(info->num_fd < MAX_NUM_OF_FD)
+ {
+ FD_SET(fd, &info->fdset);
+
+ /* Add fd to fdmap array and store read handler function ptr */
+ info->sk_fds[info->num_fd].sk_fd = fd;
+ info->sk_fds[info->num_fd].read_func = read_f;
+
+ /* Increment number of fds stored in fdmap */
+ info->num_fd++;
+ if(info->max_fd < fd)
+ info->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)
+ {
+ for(i = 0; i < sk_fd_set->num_fd; i++ )
+ {
+ FD_SET(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset));
+ }
+
+ 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);
+ }
+ FD_CLR(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset));
+ }
+ else
+ {
+ IPACMERR("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");
+ return NULL;
+ }
+
+ nladdr = (struct sockaddr_nl *)malloc(sizeof(struct sockaddr_nl));
+ if(nladdr == NULL)
+ {
+ IPACMERR("Failed malloc for sockaddr\n");
+ free(msgh);
+ return NULL;
+ }
+
+ iov = (struct iovec *)malloc(sizeof(struct iovec));
+ if(iov == NULL)
+ {
+ PERROR("Failed malloc for iovec");
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ buf = (unsigned char *)malloc(msglen);
+ if(buf == NULL)
+ {
+ IPACMERR("Failed malloc for mglen\n");
+ 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;
+ }
+
+ if(buf)
+ {
+ free(buf);
+ }
+ if(iov)
+ {
+ free(iov);
+ }
+ if(nladdr)
+ {
+ free(nladdr);
+ }
+ if(msgh)
+ {
+ 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;
+ /* 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);
+
+ 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;
+ IPACM_NL_COPY_ADDR( addr_info, prefix_addr );
+ 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;
+ IPACM_NL_COPY_ADDR( neigh_info, local_addr );
+ 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:
+ route_info->attr_info.dst_addr.ss_family = route_info->metainfo.rtm_family;
+ IPACM_NL_COPY_ADDR( route_info, dst_addr );
+ 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;
+ IPACM_NL_COPY_ADDR( route_info, src_addr );
+ 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;
+ IPACM_NL_COPY_ADDR( route_info, gateway_addr );
+ 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]={0};
+ int ret_val, mask_index, mask_value_v6;
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+ uint32_t if_ipv4_addr =0, if_ipipv4_addr_mask =0, temp =0, if_ipv4_addr_gw =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))
+ {
+ memset(dev_name,0,IF_NAME_LEN);
+ 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);
+ /* RTM_NEWLINK event with AF_BRIDGE family should be ignored in Android
+ but this should be processed in case of MDM for Ehernet interface.
+ */
+#ifdef FEATURE_IPA_ANDROID
+ if (msg_ptr->nl_link_info.metainfo.ifi_family == AF_BRIDGE)
+ {
+ IPACMERR(" ignore this RTM_NEWLINK msg \n");
+ return IPACM_SUCCESS;
+ }
+#endif
+ if(IFF_UP & msg_ptr->nl_link_info.metainfo.ifi_change)
+ {
+ IPACMDBG("GOT useful newlink event\n");
+ 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");
+ return IPACM_FAILURE;
+ }
+
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ if(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_UP)
+ {
+ IPACMDBG_H("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_H("Posting IPA_LINK_UP_EVENT with if index: %d\n",
+ msg_ptr->nl_link_info.metainfo.ifi_index);
+ }
+ else
+ {
+ IPACMDBG_H("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_H("Posting IPA_LINK_DOWN_EVENT with if index: %d\n",
+ data_fid->if_index);
+ }
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ /* Add IPACM support for ECM plug-in/plug_out */
+ /*--------------------------------------------------------------------------
+ Check if the interface is running.If its a RTM_NEWLINK and the interface
+ is running then it means that its a link up event
+ ---------------------------------------------------------------------------*/
+ if((msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_RUNNING) &&
+ (msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_LOWER_UP))
+ {
+
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ 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");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Got a usb link_up event (Interface %s, %d) \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+
+ /*--------------------------------------------------------------------------
+ Post LAN iface (ECM) link up event
+ ---------------------------------------------------------------------------*/
+ evt_data.event = IPA_USB_LINK_UP_EVENT;
+ evt_data.evt_data = data_fid;
+ IPACMDBG_H("Posting usb IPA_LINK_UP_EVENT with if index: %d\n",
+ data_fid->if_index);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ else if (!(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_LOWER_UP))
+ {
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ 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");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("Got a usb link_down event (Interface %s) \n", dev_name);
+
+ /*--------------------------------------------------------------------------
+ Post LAN iface (ECM) link down event
+ ---------------------------------------------------------------------------*/
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ evt_data.evt_data = data_fid;
+ IPACMDBG_H("Posting usb IPA_LINK_DOWN_EVENT with if index: %d\n",
+ data_fid->if_index);
+ 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
+ {
+ IPACMDBG("Got RTM_DELLINK with below values\n");
+ IPACMDBG("RTM_DELLINK, ifi_change:%d\n", msg_ptr->nl_link_info.metainfo.ifi_change);
+ IPACMDBG("RTM_DELLINK, ifi_flags:%d\n", msg_ptr->nl_link_info.metainfo.ifi_flags);
+ IPACMDBG("RTM_DELLINK, ifi_index:%d\n", msg_ptr->nl_link_info.metainfo.ifi_index);
+ IPACMDBG("RTM_DELLINK, family:%d\n", msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* RTM_NEWLINK event with AF_BRIDGE family should be ignored in Android
+ but this should be processed in case of MDM for Ehernet interface.
+ */
+#ifdef FEATURE_IPA_ANDROID
+ if (msg_ptr->nl_link_info.metainfo.ifi_family == AF_BRIDGE)
+ {
+ IPACMERR(" ignore this RTM_DELLINK msg \n");
+ return IPACM_SUCCESS;
+ }
+#endif
+ 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");
+ return IPACM_FAILURE;
+ }
+ 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)
+ {
+ IPACMERR("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_H("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)
+ {
+ IPACMERR("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;
+ IPACM_NL_REPORT_ADDR( "IFA_ADDRESS:", msg_ptr->nl_addr_info.attr_info.prefix_addr );
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_addr_info.attr_info.prefix_addr);
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+ }
+ else
+ {
+ data_addr->iptype = IPA_IP_v4;
+ IPACM_NL_REPORT_ADDR( "IFA_ADDRESS:", msg_ptr->nl_addr_info.attr_info.prefix_addr );
+ IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr, msg_ptr->nl_addr_info.attr_info.prefix_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;
+ strlcpy(data_addr->iface_name, dev_name, sizeof(data_addr->iface_name));
+ if(AF_INET6 == msg_ptr->nl_addr_info.attr_info.prefix_addr.ss_family)
+ {
+ IPACMDBG("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv6 addr:0x%x:%x:%x:%x\n",
+ data_addr->if_index,
+ data_addr->ipv6_addr[0],
+ data_addr->ipv6_addr[1],
+ data_addr->ipv6_addr[2],
+ data_addr->ipv6_addr[3]);
+ }
+ else
+ {
+ 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("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);
+
+ /* 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_protocol == RTPROT_RA)) &&
+ (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");
+ return IPACM_FAILURE;
+ }
+
+ IPACM_NL_REPORT_ADDR( "route add -host", msg_ptr->nl_route_info.attr_info.dst_addr );
+ IPACM_NL_REPORT_ADDR( "gw", msg_ptr->nl_route_info.attr_info.gateway_addr );
+ IPACMDBG("dev %s\n",dev_name );
+ /* insert to command queue */
+ IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_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)
+ {
+ IPACMERR("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");
+ return IPACM_FAILURE;
+ }
+
+ 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_H("ip -6 route add default dev %s metric %d\n",
+ dev_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG_H("ip -6 route add default dev %s\n", dev_name);
+ }
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+ data_addr->ipv6_addr_gw[0] = ntohl(data_addr->ipv6_addr_gw[0]);
+ data_addr->ipv6_addr_gw[1] = ntohl(data_addr->ipv6_addr_gw[1]);
+ data_addr->ipv6_addr_gw[2] = ntohl(data_addr->ipv6_addr_gw[2]);
+ data_addr->ipv6_addr_gw[3] = ntohl(data_addr->ipv6_addr_gw[3]);
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+
+ 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
+ {
+ IPACM_NL_REPORT_ADDR( "route add default gw \n", msg_ptr->nl_route_info.attr_info.gateway_addr );
+ IPACMDBG_H("dev %s \n", dev_name);
+ IPACM_NL_REPORT_ADDR( "dstIP:", msg_ptr->nl_route_info.attr_info.dst_addr );
+
+ /* 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;
+ }
+
+ IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ IPACM_EVENT_COPY_ADDR_v4( if_ipipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+ IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+
+ 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_gw = ntohl(if_ipv4_addr_gw);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG_H("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 addr:0x%x, mask: 0x%x and gw: 0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask,
+ data_addr->ipv4_addr_gw);
+ 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)
+ {
+ IPACM_NL_REPORT_ADDR( "Route ADD DST:", msg_ptr->nl_route_info.attr_info.dst_addr );
+ IPACMDBG("%d, metric %d, dev %s\n",
+ 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;
+ }
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+ 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]);
+
+ data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3] = ntohl(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)
+ {
+ IPACM_NL_REPORT_ADDR( "Route ADD ::/0 Next Hop:", msg_ptr->nl_route_info.attr_info.gateway_addr );
+ IPACMDBG(" metric %d, dev %s\n",
+ 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;
+ }
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+ data_addr->ipv6_addr[0]=ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1]=ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2]=ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3]=ntohl(data_addr->ipv6_addr[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+ data_addr->ipv6_addr_mask[0]=ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1]=ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2]=ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3]=ntohl(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 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)))
+ {
+ IPACMERR("Failed to decode rtm route message\n");
+ return IPACM_FAILURE;
+ }
+ /* 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_protocol == RTPROT_RA)) &&
+ (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");
+ return IPACM_FAILURE;
+ }
+ IPACM_NL_REPORT_ADDR( "route del -host ", msg_ptr->nl_route_info.attr_info.dst_addr);
+ IPACM_NL_REPORT_ADDR( " gw ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+ IPACMDBG("dev %s\n", 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;
+ }
+ IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_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_H("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");
+ return IPACM_FAILURE;
+ }
+
+ /* 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);
+ }
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+ data_addr->ipv6_addr_gw[0] = ntohl(data_addr->ipv6_addr_gw[0]);
+ data_addr->ipv6_addr_gw[1] = ntohl(data_addr->ipv6_addr_gw[1]);
+ data_addr->ipv6_addr_gw[2] = ntohl(data_addr->ipv6_addr_gw[2]);
+ data_addr->ipv6_addr_gw[3] = ntohl(data_addr->ipv6_addr_gw[3]);
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+ data_addr->iptype = IPA_IP_v6;
+ }
+ else
+ {
+ IPACM_NL_REPORT_ADDR( "route del default gw", msg_ptr->nl_route_info.attr_info.gateway_addr);
+ IPACMDBG("dev %s\n", dev_name);
+
+ IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+ IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+ 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_H("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");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACM_NL_REPORT_ADDR( "DEL", msg_ptr->nl_route_info.attr_info.dst_addr);
+ IPACMDBG("/%d, metric %d, dev %s\n",
+ 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;
+ }
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+ 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]);
+
+ data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3] = ntohl(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_H("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 */
+ }
+ }
+ 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;
+ }
+
+ 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");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("\n GOT RTM_NEWNEIGH event (%s) ip %d\n",dev_name,msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+ }
+
+ /* 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;
+ }
+
+ memset(data_all, 0, sizeof(ipacm_event_data_all));
+ if(msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET6)
+ {
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+ IPACM_EVENT_COPY_ADDR_v6( data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+
+ data_all->ipv6_addr[0]=ntohl(data_all->ipv6_addr[0]);
+ data_all->ipv6_addr[1]=ntohl(data_all->ipv6_addr[1]);
+ data_all->ipv6_addr[2]=ntohl(data_all->ipv6_addr[2]);
+ data_all->ipv6_addr[3]=ntohl(data_all->ipv6_addr[3]);
+ data_all->iptype = IPA_IP_v6;
+ }
+ else if (msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET)
+ {
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+ IPACM_EVENT_COPY_ADDR_v4( data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+ data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+ data_all->iptype = IPA_IP_v4;
+ }
+ else
+ {
+ data_all->iptype = IPA_IP_v6;
+ }
+
+ 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]);
+
+
+ memcpy(data_all->mac_addr,
+ msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+ sizeof(data_all->mac_addr));
+ data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+ strlcpy(data_all->iface_name, dev_name, sizeof(data_all->iface_name));
+ /* Add support to replace src-mac as bridge0 mac */
+ if((msg_ptr->nl_neigh_info.metainfo.ndm_family == AF_BRIDGE) &&
+ (msg_ptr->nl_neigh_info.metainfo.ndm_state == NUD_PERMANENT))
+ {
+ /* Posting IPA_BRIDGE_LINK_UP_EVENT event */
+ evt_data.event = IPA_BRIDGE_LINK_UP_EVENT;
+ IPACMDBG_H("posting IPA_BRIDGE_LINK_UP_EVENT (%s):index:%d \n",
+ dev_name,
+ data_all->if_index);
+ }
+ else
+ {
+ /* Posting new_neigh events for all LAN/WAN clients */
+ evt_data.event = IPA_NEW_NEIGH_EVENT;
+ IPACMDBG_H("posting IPA_NEW_NEIGH_EVENT (%s):index:%d ip-family: %d\n",
+ dev_name,
+ data_all->if_index,
+ msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+ }
+ evt_data.evt_data = data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ 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;
+ }
+
+ 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");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("\n GOT RTM_DELNEIGH event (%s) ip %d\n",dev_name,msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+ }
+
+ /* 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;
+ }
+
+ memset(data_all, 0, sizeof(ipacm_event_data_all));
+ if(msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET6)
+ {
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+ IPACM_EVENT_COPY_ADDR_v6( data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+
+ data_all->ipv6_addr[0] = ntohl(data_all->ipv6_addr[0]);
+ data_all->ipv6_addr[1] = ntohl(data_all->ipv6_addr[1]);
+ data_all->ipv6_addr[2] = ntohl(data_all->ipv6_addr[2]);
+ data_all->ipv6_addr[3] = ntohl(data_all->ipv6_addr[3]);
+ data_all->iptype = IPA_IP_v6;
+ }
+ else if (msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET)
+ {
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+ IPACM_EVENT_COPY_ADDR_v4( data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+ data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+ data_all->iptype = IPA_IP_v4;
+ }
+ else
+ {
+ data_all->iptype = IPA_IP_v6;
+ }
+
+ 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]);
+
+ 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_H("posting IPA_DEL_NEIGH_EVENT (%s):index:%d ip-family: %d\n",
+ dev_name,
+ data_all->if_index,
+ msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+ evt_data.evt_data = data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ 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 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;
+ }
+
+ if(msghdr== NULL)
+ {
+ IPACMERR(" failed to get msghdr\n");
+ goto error;
+ }
+
+ 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;
+ }
+ /* Release NetLink message buffer */
+ if(msghdr)
+ {
+ ipa_nl_release_msg(msghdr);
+ }
+ if(nlmsg)
+ {
+ 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)strlcpy(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;
+ int ret_val;
+
+ memset(&sk_info, 0, sizeof(ipa_nl_sk_info_t));
+ IPACMDBG_H("Entering IPA NL listener init\n");
+
+ if(ipa_nl_open_socket(&sk_info, nl_type, nl_groups) == IPACM_SUCCESS)
+ {
+ IPACMDBG_H("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");
+ close(sk_info.sk_fd);
+ 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/data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp
new file mode 100644
index 0000000..977b9b1
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp
@@ -0,0 +1,764 @@
+/*
+Copyright (c) 2017, 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_OffloadManager.cpp
+
+ @brief
+ This file implements the basis Iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <IPACM_OffloadManager.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <string.h>
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_Iface.h"
+#include "IPACM_Config.h"
+#include <unistd.h>
+
+const char *IPACM_OffloadManager::DEVICE_NAME = "/dev/wwan_ioctl";
+
+/* NatApp class Implementation */
+IPACM_OffloadManager *IPACM_OffloadManager::pInstance = NULL;
+
+IPACM_OffloadManager::IPACM_OffloadManager()
+{
+ default_gw_index = INVALID_IFACE;
+ upstream_v4_up = false;
+ upstream_v6_up = false;
+ memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache));
+ latest_cache_index = 0;
+ elrInstance = NULL;
+ touInstance = NULL;
+ return ;
+}
+
+RET IPACM_OffloadManager::registerEventListener(IpaEventListener* eventlistener)
+{
+ RET result = SUCCESS;
+ if (elrInstance == NULL) {
+ IPACMDBG_H("get registerEventListener \n");
+ elrInstance = eventlistener;
+ } else {
+ IPACMDBG_H("already have EventListener previously, override \n");
+ elrInstance = eventlistener;
+ result = FAIL_INPUT_CHECK;
+ }
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::unregisterEventListener(IpaEventListener* )
+{
+ RET result = SUCCESS;
+ if (elrInstance)
+ elrInstance = NULL;
+ else {
+ IPACMDBG_H("already unregisterEventListener previously \n");
+ result = SUCCESS_DUPLICATE_CONFIG;
+ }
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::registerCtTimeoutUpdater(ConntrackTimeoutUpdater* timeoutupdater)
+{
+ RET result = SUCCESS;
+ if (touInstance == NULL)
+ {
+ IPACMDBG_H("get ConntrackTimeoutUpdater \n");
+ touInstance = timeoutupdater;
+ } else {
+ IPACMDBG_H("already have ConntrackTimeoutUpdater previously, override \n");
+ touInstance = timeoutupdater;
+ result = FAIL_INPUT_CHECK;
+ }
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater* )
+{
+ RET result = SUCCESS;
+ if (touInstance)
+ touInstance = NULL;
+ else {
+ IPACMDBG_H("already unregisterCtTimeoutUpdater previously \n");
+ result = SUCCESS_DUPLICATE_CONFIG;
+ }
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::provideFd(int fd, unsigned int groups)
+{
+ IPACM_ConntrackClient *cc;
+ int on = 1, rel;
+ struct sockaddr_nl local;
+ unsigned int addr_len;
+
+ cc = IPACM_ConntrackClient::GetInstance();
+
+ if(!cc)
+ {
+ IPACMERR("Init failed: cc %p\n", cc);
+ return FAIL_HARDWARE;
+ }
+
+ /* check socket name */
+ memset(&local, 0, sizeof(struct sockaddr_nl));
+ addr_len = sizeof(local);
+ getsockname(fd, (struct sockaddr *)&local, (socklen_t *)&addr_len);
+ IPACMDBG_H(" FD %d, nl_pad %d nl_pid %u\n", fd, local.nl_pad, local.nl_pid);
+
+ /* add the check if getting FDs already or not */
+ if(cc->fd_tcp > -1 && cc->fd_udp > -1) {
+ IPACMDBG_H("has valid FDs fd_tcp %d, fd_udp %d, ignore fd %d.\n", cc->fd_tcp, cc->fd_udp, fd);
+ return SUCCESS;
+ }
+
+ if (groups == cc->subscrips_tcp) {
+ cc->fd_tcp = dup(fd);
+ IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups);
+ /* set netlink buf */
+ rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
+ if (rel == -1)
+ {
+ IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) );
+ }
+ } else if (groups == cc->subscrips_udp) {
+ cc->fd_udp = dup(fd);
+ IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups);
+ /* set netlink buf */
+ rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) );
+ if (rel == -1)
+ {
+ IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) );
+ }
+ } else {
+ IPACMERR("Received unexpected fd with groups %d.\n", groups);
+ }
+ if(cc->fd_tcp >0 && cc->fd_udp >0) {
+ IPACMDBG_H(" Got both fds from framework, start conntrack listener thread.\n");
+ CtList->CreateConnTrackThreads();
+ }
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::clearAllFds()
+{
+
+ /* IPACM needs to kee old FDs, can't clear */
+ IPACMDBG_H("Still use old Fds, can't clear \n");
+ return SUCCESS;
+}
+
+bool IPACM_OffloadManager::isStaApSupported()
+{
+ return true;
+}
+
+
+RET IPACM_OffloadManager::setLocalPrefixes(std::vector<Prefix> &/* prefixes */)
+{
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::addDownstream(const char * downstream_name, const Prefix &prefix)
+{
+ int index;
+ ipacm_cmd_q_data evt;
+ ipacm_event_ipahal_stream *evt_data;
+
+ IPACMDBG_H("addDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
+
+ if (prefix.fam == V4) {
+ IPACMDBG_H("subnet info v4Addr (%x) v4Mask (%x)\n", prefix.v4Addr, prefix.v4Mask);
+ } else {
+ IPACMDBG_H("subnet info v6Addr: %08x:%08x:%08x:%08x \n",
+ prefix.v6Addr[0], prefix.v6Addr[1], prefix.v6Addr[2], prefix.v6Addr[3]);
+ IPACMDBG_H("subnet info v6Mask: %08x:%08x:%08x:%08x \n",
+ prefix.v6Mask[0], prefix.v6Mask[1], prefix.v6Mask[2], prefix.v6Mask[3]);
+ }
+
+ /* check if netdev valid on device */
+ if(ipa_get_if_index(downstream_name, &index))
+ {
+ IPACMERR("fail to get iface index.\n");
+ return FAIL_INPUT_CHECK;
+ }
+ /* Iface is valid, add to list if not present */
+ if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end())
+ {
+ /* Iface is new, add it to the list */
+ valid_ifaces.push_back(downstream_name);
+ IPACMDBG_H("add iface(%s) to list\n", downstream_name);
+ }
+
+ /* check if downstream netdev driver finished its configuration on IPA-HW */
+ if (IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name))
+ {
+ IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", downstream_name);
+ /* copy to the cache */
+ for(int i = 0; i < MAX_EVENT_CACHE ;i++)
+ {
+ if(event_cache[latest_cache_index].valid == false)
+ {
+ //do the copy
+ event_cache[latest_cache_index].valid = true;
+ event_cache[latest_cache_index].event = IPA_DOWNSTREAM_ADD;
+ memcpy(event_cache[latest_cache_index].dev_name, downstream_name, sizeof(event_cache[latest_cache_index].dev_name));
+ memcpy(&event_cache[latest_cache_index].prefix_cache, &prefix, sizeof(event_cache[latest_cache_index].prefix_cache));
+ if (prefix.fam == V4) {
+ IPACMDBG_H("cache event(%d) subnet info v4Addr (%x) v4Mask (%x) dev(%s) on entry (%d)\n",
+ event_cache[latest_cache_index].event,
+ event_cache[latest_cache_index].prefix_cache.v4Addr,
+ event_cache[latest_cache_index].prefix_cache.v4Mask,
+ event_cache[latest_cache_index].dev_name,
+ latest_cache_index);
+ } else {
+ IPACMDBG_H("cache event (%d) v6Addr: %08x:%08x:%08x:%08x \n",
+ event_cache[latest_cache_index].event,
+ event_cache[latest_cache_index].prefix_cache.v6Addr[0],
+ event_cache[latest_cache_index].prefix_cache.v6Addr[1],
+ event_cache[latest_cache_index].prefix_cache.v6Addr[2],
+ event_cache[latest_cache_index].prefix_cache.v6Addr[3]);
+ IPACMDBG_H("subnet v6Mask: %08x:%08x:%08x:%08x dev(%s) on entry(%d), \n",
+ event_cache[latest_cache_index].prefix_cache.v6Mask[0],
+ event_cache[latest_cache_index].prefix_cache.v6Mask[1],
+ event_cache[latest_cache_index].prefix_cache.v6Mask[2],
+ event_cache[latest_cache_index].prefix_cache.v6Mask[3],
+ event_cache[latest_cache_index].dev_name,
+ latest_cache_index);
+ }
+ latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
+ break;
+ }
+ latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
+ if(i == MAX_EVENT_CACHE - 1)
+ {
+ IPACMDBG_H(" run out of event cache (%d)\n", i);
+ return FAIL_HARDWARE;
+ }
+ }
+
+ return SUCCESS;
+ }
+
+ evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
+ if(evt_data == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return FAIL_HARDWARE;
+ }
+ memset(evt_data, 0, sizeof(*evt_data));
+
+ evt_data->if_index = index;
+ memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix));
+
+ memset(&evt, 0, sizeof(ipacm_cmd_q_data));
+ evt.evt_data = (void*)evt_data;
+ evt.event = IPA_DOWNSTREAM_ADD;
+
+ IPACMDBG_H("Posting event IPA_DOWNSTREAM_ADD\n");
+ IPACM_EvtDispatcher::PostEvt(&evt);
+
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::removeDownstream(const char * downstream_name, const Prefix &prefix)
+{
+ int index;
+ ipacm_cmd_q_data evt;
+ ipacm_event_ipahal_stream *evt_data;
+
+ IPACMDBG_H("removeDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam);
+ if(strnlen(downstream_name, sizeof(downstream_name)) == 0)
+ {
+ IPACMERR("iface length is 0.\n");
+ return FAIL_HARDWARE;
+ }
+ if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end())
+ {
+ IPACMERR("iface is not present in list.\n");
+ return FAIL_HARDWARE;
+ }
+
+ if(ipa_get_if_index(downstream_name, &index))
+ {
+ IPACMERR("netdev(%s) already removed, ignored\n", downstream_name);
+ return SUCCESS;
+ }
+
+ evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream));
+ if(evt_data == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return FAIL_HARDWARE;
+ }
+ memset(evt_data, 0, sizeof(*evt_data));
+
+ evt_data->if_index = index;
+ memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix));
+
+ memset(&evt, 0, sizeof(ipacm_cmd_q_data));
+ evt.evt_data = (void*)evt_data;
+ evt.event = IPA_DOWNSTREAM_DEL;
+
+ IPACMDBG_H("Posting event IPA_DOWNSTREAM_DEL\n");
+ IPACM_EvtDispatcher::PostEvt(&evt);
+
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::setUpstream(const char *upstream_name, const Prefix& gw_addr_v4 , const Prefix& gw_addr_v6)
+{
+ int index;
+ RET result = SUCCESS;
+
+ /* if interface name is NULL, default route is removed */
+ if(upstream_name != NULL)
+ {
+ IPACMDBG_H("setUpstream upstream_name(%s), ipv4-fam(%d) ipv6-fam(%d)\n", upstream_name, gw_addr_v4.fam, gw_addr_v6.fam);
+ }
+ else
+ {
+ IPACMDBG_H("setUpstream clean upstream_name for ipv4-fam(%d) ipv6-fam(%d)\n", gw_addr_v4.fam, gw_addr_v6.fam);
+ }
+ if(upstream_name == NULL)
+ {
+ if (default_gw_index == INVALID_IFACE) {
+ IPACMERR("no previous upstream set before\n");
+ return FAIL_INPUT_CHECK;
+ }
+ if (gw_addr_v4.fam == V4 && upstream_v4_up == true) {
+ IPACMDBG_H("clean upstream for ipv4-fam(%d) upstream_v4_up(%d)\n", gw_addr_v4.fam, upstream_v4_up);
+ post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
+ upstream_v4_up = false;
+ }
+ if (gw_addr_v6.fam == V6 && upstream_v6_up == true) {
+ IPACMDBG_H("clean upstream for ipv6-fam(%d) upstream_v6_up(%d)\n", gw_addr_v6.fam, upstream_v6_up);
+ post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
+ upstream_v6_up = false;
+ }
+ default_gw_index = INVALID_IFACE;
+ }
+ else
+ {
+ /* check if netdev valid on device */
+ if(ipa_get_if_index(upstream_name, &index))
+ {
+ IPACMERR("fail to get iface index.\n");
+ return FAIL_INPUT_CHECK;
+ }
+
+ /* check if downstream netdev driver finished its configuration on IPA-HW */
+ if (IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name))
+ {
+ IPACMDBG_H("setUpstream name(%s) currently not support in ipa \n", upstream_name);
+ /* copy to the cache */
+ for(int i = 0; i < MAX_EVENT_CACHE ;i++)
+ {
+ if(event_cache[latest_cache_index].valid == false)
+ {
+ //do the copy
+ event_cache[latest_cache_index].valid = true;
+ event_cache[latest_cache_index].event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT;
+ memcpy(event_cache[latest_cache_index].dev_name, upstream_name, sizeof(event_cache[latest_cache_index].dev_name));
+ memcpy(&event_cache[latest_cache_index].prefix_cache, &gw_addr_v4, sizeof(event_cache[latest_cache_index].prefix_cache));
+ memcpy(&event_cache[latest_cache_index].prefix_cache_v6, &gw_addr_v6, sizeof(event_cache[latest_cache_index].prefix_cache_v6));
+ if (gw_addr_v4.fam == V4) {
+ IPACMDBG_H("cache event(%d) ipv4 fateway: (%x) dev(%s) on entry (%d)\n",
+ event_cache[latest_cache_index].event,
+ event_cache[latest_cache_index].prefix_cache.v4Addr,
+ event_cache[latest_cache_index].dev_name,
+ latest_cache_index);
+ }
+
+ if (gw_addr_v6.fam == V6)
+ {
+ IPACMDBG_H("cache event (%d) ipv6 gateway: %08x:%08x:%08x:%08x dev(%s) on entry(%d)\n",
+ event_cache[latest_cache_index].event,
+ event_cache[latest_cache_index].prefix_cache_v6.v6Addr[0],
+ event_cache[latest_cache_index].prefix_cache_v6.v6Addr[1],
+ event_cache[latest_cache_index].prefix_cache_v6.v6Addr[2],
+ event_cache[latest_cache_index].prefix_cache_v6.v6Addr[3],
+ event_cache[latest_cache_index].dev_name,
+ latest_cache_index);
+ }
+ latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
+ break;
+ }
+ latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE;
+ if(i == MAX_EVENT_CACHE - 1)
+ {
+ IPACMDBG_H(" run out of event cache (%d) \n", i);
+ return FAIL_HARDWARE;
+ }
+ }
+ return SUCCESS;
+ }
+
+ /* reset the stats when switch from LTE->STA */
+ if (index != default_gw_index) {
+ IPACMDBG_H(" interface switched to %s\n", upstream_name);
+ if (upstream_v4_up == true) {
+ IPACMDBG_H("clean upstream for ipv4-fam(%d) upstream_v4_up(%d)\n", gw_addr_v4.fam, upstream_v4_up);
+ post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
+ upstream_v4_up = false;
+ }
+ if (upstream_v6_up == true) {
+ IPACMDBG_H("clean upstream for ipv6-fam(%d) upstream_v6_up(%d)\n", gw_addr_v6.fam, upstream_v6_up);
+ post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
+ upstream_v6_up = false;
+ }
+ default_gw_index = INVALID_IFACE;
+ if(memcmp(upstream_name, "wlan0", sizeof("wlan0")) == 0)
+ {
+ IPACMDBG_H("switch to STA mode, need reset wlan-fw stats\n");
+ resetTetherStats(upstream_name);
+ }
+ }
+
+ if (gw_addr_v4.fam == V4 && gw_addr_v6.fam == V6) {
+
+ if (upstream_v4_up == false) {
+ IPACMDBG_H("IPV4 gateway: 0x%x \n", gw_addr_v4.v4Addr);
+ /* posting route add event for both IPv4 and IPv6 */
+ post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4);
+ upstream_v4_up = true;
+ } else {
+ IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name);
+ }
+
+ if (upstream_v6_up == false) {
+ IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
+ gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]);
+ /* check v6-address valid or not */
+ if((gw_addr_v6.v6Addr[0] == 0) && (gw_addr_v6.v6Addr[1] ==0) && (gw_addr_v6.v6Addr[2] == 0) && (gw_addr_v6.v6Addr[3] == 0))
+ {
+ IPACMDBG_H("Invliad ipv6-address, ignored v6-setupstream\n");
+ } else {
+ post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6);
+ upstream_v6_up = true;
+ }
+ } else {
+ IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name);
+ }
+ } else if (gw_addr_v4.fam == V4 ) {
+ IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index);
+ if (upstream_v6_up == true && default_gw_index != INVALID_IFACE ) {
+ /* clean up previous V6 upstream event */
+ IPACMDBG_H(" Post clean-up v6 default gw on iface %d\n", default_gw_index);
+ post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6);
+ upstream_v6_up = false;
+ }
+
+ if (upstream_v4_up == false) {
+ IPACMDBG_H("IPV4 gateway: %x \n", gw_addr_v4.v4Addr);
+ /* posting route add event for both IPv4 and IPv6 */
+ post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4);
+ upstream_v4_up = true;
+ } else {
+ IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name);
+ result = SUCCESS_DUPLICATE_CONFIG;
+ }
+ } else if (gw_addr_v6.fam == V6) {
+ IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index);
+ if (upstream_v4_up == true && default_gw_index != INVALID_IFACE ) {
+ /* clean up previous V4 upstream event */
+ IPACMDBG_H(" Post clean-up v4 default gw on iface %d\n", default_gw_index);
+ post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4);
+ upstream_v4_up = false;
+ }
+
+ if (upstream_v6_up == false) {
+ IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
+ gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]);
+ /* check v6-address valid or not */
+ if((gw_addr_v6.v6Addr[0] == 0) && (gw_addr_v6.v6Addr[1] ==0) && (gw_addr_v6.v6Addr[2] == 0) && (gw_addr_v6.v6Addr[3] == 0))
+ {
+ IPACMDBG_H("Invliad ipv6-address, ignored v6-setupstream\n");
+ } else {
+ post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6);
+ upstream_v6_up = true;
+ }
+ } else {
+ IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name);
+ result = SUCCESS_DUPLICATE_CONFIG;
+ }
+ }
+ default_gw_index = index;
+ IPACMDBG_H("Change degault_gw netdev to (%s)\n", upstream_name);
+ }
+ return result;
+}
+
+RET IPACM_OffloadManager::stopAllOffload()
+{
+ Prefix v4gw, v6gw;
+ RET result = SUCCESS;
+
+ memset(&v4gw, 0, sizeof(v4gw));
+ memset(&v6gw, 0, sizeof(v6gw));
+ v4gw.fam = V4;
+ v6gw.fam = V6;
+ IPACMDBG_H("posting setUpstream(NULL), ipv4-fam(%d) ipv6-fam(%d)\n", v4gw.fam, v6gw.fam);
+ result = setUpstream(NULL, v4gw, v6gw);
+
+ /* reset the event cache */
+ default_gw_index = INVALID_IFACE;
+ upstream_v4_up = false;
+ upstream_v6_up = false;
+ memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache));
+ latest_cache_index = 0;
+ valid_ifaces.clear();
+ return result;
+}
+
+RET IPACM_OffloadManager::setQuota(const char * upstream_name /* upstream */, uint64_t mb/* limit */)
+{
+ wan_ioctl_set_data_quota quota;
+ int fd = -1,rc = 0;
+
+ if ((fd = open(DEVICE_NAME, O_RDWR)) < 0)
+ {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ return FAIL_HARDWARE;
+ }
+
+ quota.quota_mbytes = mb;
+ quota.set_quota = true;
+
+ memset(quota.interface_name, 0, IFNAMSIZ);
+ if (strlcpy(quota.interface_name, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
+ IPACMERR("String truncation occurred on upstream");
+ close(fd);
+ return FAIL_INPUT_CHECK;
+ }
+
+ IPACMDBG_H("SET_DATA_QUOTA %s %llu", quota.interface_name, (long long)mb);
+
+ rc = ioctl(fd, WAN_IOC_SET_DATA_QUOTA, &quota);
+
+ if(rc != 0)
+ {
+ close(fd);
+ IPACMERR("IOCTL WAN_IOCTL_SET_DATA_QUOTA call failed: %s rc: %d\n", strerror(errno),rc);
+ if (errno == ENODEV) {
+ IPACMDBG_H("Invalid argument.\n");
+ return FAIL_UNSUPPORTED;
+ }
+ else {
+ return FAIL_TRY_AGAIN;
+ }
+ }
+ close(fd);
+ return SUCCESS;
+}
+
+RET IPACM_OffloadManager::getStats(const char * upstream_name /* upstream */,
+ bool reset /* reset */, OffloadStatistics& offload_stats/* ret */)
+{
+ int fd = -1;
+ wan_ioctl_query_tether_stats_all stats;
+
+ if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ return FAIL_HARDWARE;
+ }
+
+ memset(&stats, 0, sizeof(stats));
+ if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
+ IPACMERR("String truncation occurred on upstream\n");
+ close(fd);
+ return FAIL_INPUT_CHECK;
+ }
+ stats.reset_stats = reset;
+ stats.ipa_client = IPACM_CLIENT_MAX;
+
+ if (ioctl(fd, WAN_IOC_QUERY_TETHER_STATS_ALL, &stats) < 0) {
+ IPACMERR("IOCTL WAN_IOC_QUERY_TETHER_STATS_ALL call failed: %s \n", strerror(errno));
+ close(fd);
+ return FAIL_TRY_AGAIN;
+ }
+ /* feedback to IPAHAL*/
+ offload_stats.tx = stats.tx_bytes;
+ offload_stats.rx = stats.rx_bytes;
+
+ IPACMDBG_H("send getStats tx:%llu rx:%llu \n", (long long)offload_stats.tx, (long long)offload_stats.rx);
+ close(fd);
+ return SUCCESS;
+}
+
+int IPACM_OffloadManager::post_route_evt(enum ipa_ip_type iptype, int index, ipa_cm_event_id event, const Prefix &gw_addr)
+{
+ ipacm_cmd_q_data evt;
+ ipacm_event_data_iptype *evt_data_route;
+
+ evt_data_route = (ipacm_event_data_iptype*)malloc(sizeof(ipacm_event_data_iptype));
+ if(evt_data_route == NULL)
+ {
+ IPACMERR("Failed to allocate memory.\n");
+ return -EFAULT;
+ }
+ memset(evt_data_route, 0, sizeof(*evt_data_route));
+
+ evt_data_route->if_index = index;
+ evt_data_route->if_index_tether = 0;
+ evt_data_route->iptype = iptype;
+
+ IPACMDBG_H("gw_addr.v4Addr: %d, gw_addr.v6Addr: %08x:%08x:%08x:%08x \n",
+ gw_addr.v4Addr,gw_addr.v6Addr[0],gw_addr.v6Addr[1],gw_addr.v6Addr[2],gw_addr.v6Addr[3]);
+
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+ evt_data_route->ipv4_addr_gw = gw_addr.v4Addr;
+ evt_data_route->ipv6_addr_gw[0] = gw_addr.v6Addr[0];
+ evt_data_route->ipv6_addr_gw[1] = gw_addr.v6Addr[1];
+ evt_data_route->ipv6_addr_gw[2] = gw_addr.v6Addr[2];
+ evt_data_route->ipv6_addr_gw[3] = gw_addr.v6Addr[3];
+ IPACMDBG_H("default gw ipv4 (%x)\n", evt_data_route->ipv4_addr_gw);
+ IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n",
+ evt_data_route->ipv6_addr_gw[0], evt_data_route->ipv6_addr_gw[1], evt_data_route->ipv6_addr_gw[2], evt_data_route->ipv6_addr_gw[3]);
+#endif
+ IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", evt_data_route->if_index,
+ evt_data_route->if_index_tether, evt_data_route->iptype);
+
+ memset(&evt, 0, sizeof(evt));
+ evt.evt_data = (void*)evt_data_route;
+ evt.event = event;
+
+ IPACM_EvtDispatcher::PostEvt(&evt);
+
+ return 0;
+}
+
+int IPACM_OffloadManager::ipa_get_if_index(const char * if_name, int * if_index)
+{
+ int fd;
+ struct ifreq ifr;
+
+ if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ IPACMERR("get interface index socket create failed \n");
+ return IPACM_FAILURE;
+ }
+
+ if(strnlen(if_name, sizeof(if_name)) >= sizeof(ifr.ifr_name)) {
+ IPACMERR("interface name overflows: len %zu\n", strnlen(if_name, sizeof(if_name)));
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+ IPACMDBG_H("interface name (%s)\n", if_name);
+
+ if(ioctl(fd,SIOCGIFINDEX , &ifr) < 0)
+ {
+ IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name);
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ *if_index = ifr.ifr_ifindex;
+ IPACMDBG_H("Interface netdev index %d\n", *if_index);
+ close(fd);
+ return IPACM_SUCCESS;
+}
+
+int IPACM_OffloadManager::resetTetherStats(const char * upstream_name /* upstream */)
+{
+ int fd = -1;
+ wan_ioctl_reset_tether_stats stats;
+
+ if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ return FAIL_HARDWARE;
+ }
+
+ memset(stats.upstreamIface, 0, IFNAMSIZ);
+ if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) {
+ IPACMERR("String truncation occurred on upstream\n");
+ close(fd);
+ return FAIL_INPUT_CHECK;
+ }
+ stats.reset_stats = true;
+
+ if (ioctl(fd, WAN_IOC_RESET_TETHER_STATS, &stats) < 0) {
+ IPACMERR("IOCTL WAN_IOC_RESET_TETHER_STATS call failed: %s", strerror(errno));
+ close(fd);
+ return FAIL_HARDWARE;
+ }
+ IPACMDBG_H("Reset Interface %s stats\n", upstream_name);
+ close(fd);
+ return IPACM_SUCCESS;
+}
+
+IPACM_OffloadManager* IPACM_OffloadManager::GetInstance()
+{
+ if(pInstance == NULL)
+ pInstance = new IPACM_OffloadManager();
+
+ return pInstance;
+}
+
+bool IPACM_OffloadManager::search_framwork_cache(char * interface_name)
+{
+ bool rel = false;
+
+ /* IPACM needs to kee old FDs, can't clear */
+ IPACMDBG_H("check netdev(%s)\n", interface_name);
+
+ for(int i = 0; i < MAX_EVENT_CACHE ;i++)
+ {
+ if(event_cache[i].valid == true)
+ {
+ //do the compare
+ if (strncmp(event_cache[i].dev_name,
+ interface_name,
+ sizeof(event_cache[i].dev_name)) == 0)
+ {
+ IPACMDBG_H("found netdev (%s) in entry (%d) with event (%d)\n", interface_name, i, event_cache[i].event);
+ /* post event again */
+ if (event_cache[i].event == IPA_DOWNSTREAM_ADD)
+ addDownstream(interface_name, event_cache[i].prefix_cache);
+ else if (event_cache[i].event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT)
+ setUpstream(interface_name, event_cache[i].prefix_cache, event_cache[i].prefix_cache_v6);
+ else
+ IPACMERR("wrong event cached (%d)", event_cache[i].event);
+ event_cache[i].valid = false;
+ rel = true;
+ }
+ }
+ }
+ IPACMDBG_H(" not found netdev (%s) has cached event\n", interface_name);
+ return rel;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Routing.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Routing.cpp
new file mode 100644
index 0000000..2a2555a
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Routing.cpp
@@ -0,0 +1,276 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Routing.cpp
+
+ @brief
+ This file implements the IPACM routing functionality.
+
+ @Author
+
+*/
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Routing.h"
+#include <IPACM_Log.h>
+
+const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Routing::IPACM_Routing()
+{
+ m_fd = open(DEVICE_NAME, O_RDWR);
+ if (0 == m_fd)
+ {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ }
+}
+
+IPACM_Routing::~IPACM_Routing()
+{
+ close(m_fd);
+}
+
+bool IPACM_Routing::DeviceNodeIsOpened()
+{
+ int res = fcntl(m_fd, F_GETFL);
+
+ if (m_fd > 0 && res >= 0) return true;
+ else return false;
+
+}
+
+bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
+{
+ int retval = 0, cnt=0;
+ bool isInvalid = false;
+
+ if (!DeviceNodeIsOpened())
+ {
+ IPACMERR("Device is not opened\n");
+ return false;
+ }
+
+ for(cnt=0; cnt<ruleTable->num_rules; cnt++)
+ {
+ if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX)
+ {
+ IPACMERR("Invalid dst pipe, Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
+ isInvalid = true;
+ }
+ }
+
+ if(isInvalid)
+ {
+ return false;
+ }
+
+ retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
+ if (retval)
+ {
+ IPACMERR("Failed adding routing rule %p\n", ruleTable);
+ return false;
+ }
+
+ for(cnt=0; cnt<ruleTable->num_rules; cnt++)
+ {
+ IPACMDBG("Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
+ }
+
+ IPACMDBG_H("Added routing rule %p\n", ruleTable);
+ return true;
+}
+
+bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
+ if (retval)
+ {
+ IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
+ return false;
+ }
+
+ IPACMDBG_H("Deleted routing rule %p\n", ruleTable);
+ return true;
+}
+
+bool IPACM_Routing::Commit(enum ipa_ip_type ip)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+ if (retval)
+ {
+ IPACMERR("Failed commiting routing rules.\n");
+ return false;
+ }
+
+ IPACMDBG_H("Commited routing rules to IPA HW.\n");
+ return true;
+}
+
+bool IPACM_Routing::Reset(enum ipa_ip_type ip)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
+ retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+ if (retval)
+ {
+ IPACMERR("Failed resetting routing block.\n");
+ return false;
+ }
+
+ IPACMDBG_H("Reset command issued to IPA routing block.\n");
+ return true;
+}
+
+bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
+ if (retval)
+ {
+ IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
+ return false;
+ }
+ IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
+ /* put routing table right after successfully get routing table */
+ PutRoutingTable(routingTable->hdl);
+
+ return true;
+}
+
+bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
+ if (retval)
+ {
+ IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
+ return false;
+ }
+
+ IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
+ return true;
+}
+
+bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
+{
+ const uint8_t NUM_RULES = 1;
+ struct ipa_ioc_del_rt_rule *rt_rule;
+ struct ipa_rt_rule_del *rt_rule_entry;
+ bool res = true;
+ int len = 0;
+
+ if (rt_rule_hdl == 0)
+ {
+ IPACMERR(" No route handle passed. Ignoring it\n");
+ return res;
+ }
+
+ len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
+ rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
+ if (rt_rule == NULL)
+ {
+ IPACMERR("unable to allocate memory for del route rule\n");
+ return false;
+ }
+
+ memset(rt_rule, 0, len);
+ rt_rule->commit = 1;
+ rt_rule->num_hdls = NUM_RULES;
+ rt_rule->ip = ip;
+
+ rt_rule_entry = &rt_rule->hdl[0];
+ rt_rule_entry->status = -1;
+ rt_rule_entry->hdl = rt_rule_hdl;
+
+ IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
+ if ((false == DeleteRoutingRule(rt_rule)) ||
+ (rt_rule_entry->status))
+ {
+ PERROR("Routing rule deletion failed!\n");
+ goto fail;
+ res = false;
+ }
+
+fail:
+ free(rt_rule);
+
+ return res;
+}
+
+bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules)
+{
+ int retval = 0, cnt;
+
+ if (!DeviceNodeIsOpened())
+ {
+ IPACMERR("Device is not opened\n");
+ return false;
+ }
+
+ retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules);
+ if (retval)
+ {
+ IPACMERR("Failed modifying routing rules %p\n", mdfyRules);
+ return false;
+ }
+
+ for(cnt=0; cnt<mdfyRules->num_rules; cnt++)
+ {
+ if(mdfyRules->rules[cnt].status != 0)
+ {
+ IPACMERR("Unable to modify rule: %d\n", cnt);
+ }
+ }
+
+ IPACMDBG_H("Modified routing rules %p\n", mdfyRules);
+ return true;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Wan.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Wan.cpp
new file mode 100644
index 0000000..749e09c
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Wan.cpp
@@ -0,0 +1,6232 @@
+/*
+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 <fcntl.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Xml.h>
+#include <IPACM_Log.h>
+#include "IPACM_EvtDispatcher.h"
+#include <IPACM_IfaceManager.h>
+#include "linux/rmnet_ipa_fd_ioctl.h"
+#include "IPACM_Config.h"
+#include "IPACM_Defs.h"
+#include <IPACM_ConntrackListener.h>
+#include "linux/ipa_qmi_service_v01.h"
+#ifdef FEATURE_IPACM_HAL
+#include "IPACM_OffloadManager.h"
+#endif
+
+bool IPACM_Wan::wan_up = false;
+bool IPACM_Wan::wan_up_v6 = false;
+uint8_t IPACM_Wan::xlat_mux_id = 0;
+
+uint32_t IPACM_Wan::curr_wan_ip = 0;
+int IPACM_Wan::num_v4_flt_rule = 0;
+int IPACM_Wan::num_v6_flt_rule = 0;
+
+struct ipa_flt_rule_add IPACM_Wan::flt_rule_v4[IPA_MAX_FLT_RULE];
+struct ipa_flt_rule_add IPACM_Wan::flt_rule_v6[IPA_MAX_FLT_RULE];
+
+char IPACM_Wan::wan_up_dev_name[IF_NAME_LEN];
+
+bool IPACM_Wan::backhaul_is_sta_mode = false;
+bool IPACM_Wan::is_ext_prop_set = false;
+
+int IPACM_Wan::num_ipv4_modem_pdn = 0;
+int IPACM_Wan::num_ipv6_modem_pdn = 0;
+
+bool IPACM_Wan::embms_is_on = false;
+bool IPACM_Wan::backhaul_is_wan_bridge = false;
+
+uint32_t IPACM_Wan::backhaul_ipv6_prefix[2];
+
+#ifdef FEATURE_IPA_ANDROID
+uint32_t IPACM_Wan::ipa_if_num_tether_v4_total = 0;
+uint32_t IPACM_Wan::ipa_if_num_tether_v6_total = 0;
+
+int IPACM_Wan::ipa_if_num_tether_v4[IPA_MAX_IFACE_ENTRIES];
+int IPACM_Wan::ipa_if_num_tether_v6[IPA_MAX_IFACE_ENTRIES];
+#endif
+
+IPACM_Wan::IPACM_Wan(int iface_index,
+ ipacm_wan_iface_type is_sta_mode,
+ uint8_t *mac_addr) : IPACM_Iface(iface_index)
+{
+ num_firewall_v4 = 0;
+ num_firewall_v6 = 0;
+ wan_route_rule_v4_hdl = NULL;
+ wan_route_rule_v6_hdl = NULL;
+ wan_route_rule_v6_hdl_a5 = NULL;
+ wan_client = NULL;
+ mac_addr = NULL;
+
+ if(iface_query != NULL)
+ {
+ wan_route_rule_v4_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+ wan_route_rule_v6_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+ wan_route_rule_v6_hdl_a5 = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+ IPACMDBG_H("IPACM->IPACM_Wan(%d) constructor: Tx:%d\n", ipa_if_num, iface_query->num_tx_props);
+ }
+ m_is_sta_mode = is_sta_mode;
+
+ wan_v4_addr_set = false;
+ wan_v4_addr_gw_set = false;
+ wan_v6_addr_gw_set = false;
+ active_v4 = false;
+ active_v6 = false;
+ header_set_v4 = false;
+ header_set_v6 = false;
+ header_partial_default_wan_v4 = false;
+ header_partial_default_wan_v6 = false;
+ hdr_hdl_sta_v4 = 0;
+ hdr_hdl_sta_v6 = 0;
+ num_ipv6_dest_flt_rule = 0;
+ memset(ipv6_dest_flt_rule_hdl, 0, MAX_DEFAULT_v6_ROUTE_RULES*sizeof(uint32_t));
+ memset(ipv6_prefix, 0, sizeof(ipv6_prefix));
+ memset(wan_v6_addr_gw, 0, sizeof(wan_v6_addr_gw));
+ ext_prop = NULL;
+ is_ipv6_frag_firewall_flt_rule_installed = false;
+ ipv6_frag_firewall_flt_rule_hdl = 0;
+
+ num_wan_client = 0;
+ header_name_count = 0;
+ memset(invalid_mac, 0, sizeof(invalid_mac));
+
+ is_xlat = false;
+ hdr_hdl_dummy_v6 = 0;
+ hdr_proc_hdl_dummy_v6 = 0;
+ is_default_gateway = false;
+ m_fd_ipa = 0;
+ wan_client_len = 0;
+
+ if(iface_query != NULL)
+ {
+ wan_client_len = (sizeof(ipa_wan_client)) + (iface_query->num_tx_props * sizeof(wan_client_rt_hdl));
+ wan_client = (ipa_wan_client *)calloc(IPA_MAX_NUM_WAN_CLIENTS, wan_client_len);
+ if (wan_client == NULL)
+ {
+ IPACMERR("unable to allocate memory\n");
+ return;
+ }
+ IPACMDBG_H("index:%d constructor: Tx properties:%d\n", iface_index, iface_query->num_tx_props);
+ }
+
+
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ IPACMDBG_H("The new WAN interface is modem.\n");
+ is_default_gateway = false;
+ query_ext_prop();
+ }
+ else
+ {
+ IPACMDBG_H("The new WAN interface is WLAN STA.\n");
+ }
+
+ m_fd_ipa = open(IPA_DEVICE_NAME, O_RDWR);
+ if(0 == m_fd_ipa)
+ {
+ IPACMERR("Failed to open %s\n",IPA_DEVICE_NAME);
+ }
+
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == EMBMS_IF)
+ {
+ IPACMDBG(" IPACM->IPACM_Wan_eMBMS(%d)\n", ipa_if_num);
+ embms_is_on = true;
+ install_wan_filtering_rule(false);
+ /* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+ if(tx_prop != NULL)
+ {
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+ }
+ }
+ else
+ {
+ IPACMDBG(" IPACM->IPACM_Wan(%d)\n", ipa_if_num);
+ }
+ return;
+}
+
+IPACM_Wan::~IPACM_Wan()
+{
+ IPACM_EvtDispatcher::deregistr(this);
+ IPACM_IfaceManager::deregistr(this);
+ return;
+}
+
+/* handle new_address event */
+int IPACM_Wan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule = NULL;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ struct ipa_ioc_add_flt_rule *flt_rule;
+ struct ipa_flt_rule_add flt_rule_entry;
+ struct ipa_ioc_get_hdr hdr;
+
+ const int NUM_RULES = 1;
+ uint32_t num_ipv6_addr;
+ int res = IPACM_SUCCESS,len;
+#ifdef FEATURE_IPACM_HAL
+ IPACM_OffloadManager* OffloadMng;
+#endif
+
+ memset(&hdr, 0, sizeof(hdr));
+ if(tx_prop == NULL || rx_prop == NULL)
+ {
+ IPACMDBG_H("Either tx or rx property is NULL, return.\n");
+ return IPACM_SUCCESS;
+ }
+
+ /* Update the IP Type. */
+ config_ip_type(data->iptype);
+
+ if (data->iptype == IPA_IP_v6)
+ {
+ for(num_ipv6_addr=0;num_ipv6_addr<num_dft_rt_v6;num_ipv6_addr++)
+ {
+ if((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
+ (ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
+ (ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
+ (ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
+ {
+ IPACMDBG_H("find matched ipv6 address, index:%d \n", num_ipv6_addr);
+ return IPACM_SUCCESS;
+ break;
+ }
+ }
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = data->iptype;
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
+
+ rt_rule_entry = &rt_rule->rules[0];
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+ hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if(m_header.GetHeaderHandle(&hdr) == false)
+ {
+ IPACMERR("Failed to get QMAP header.\n");
+ return IPACM_FAILURE;
+ }
+ rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+ }
+ rt_rule_entry->at_rear = false;
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+ }
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ ipv6_addr[num_dft_rt_v6][0] = data->ipv6_addr[0];
+ ipv6_addr[num_dft_rt_v6][1] = data->ipv6_addr[1];
+ ipv6_addr[num_dft_rt_v6][2] = data->ipv6_addr[2];
+ ipv6_addr[num_dft_rt_v6][3] = data->ipv6_addr[3];
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = false;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6] = rt_rule_entry->rt_rule_hdl;
+
+ /* setup same rule for v6_wan table*/
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1] = rt_rule_entry->rt_rule_hdl;
+
+ IPACMDBG_H("ipv6 wan iface rt-rule hdl=0x%x hdl=0x%x, num_dft_rt_v6: %d \n",
+ dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6],
+ dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES + 2*num_dft_rt_v6+1],num_dft_rt_v6);
+
+ /* add default filtering rules when wan-iface get global v6-prefix */
+ if (num_dft_rt_v6 == 1)
+ {
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ modem_ipv6_pdn_index = num_ipv6_modem_pdn;
+ num_ipv6_modem_pdn++;
+ IPACMDBG_H("Now the number of modem ipv6 pdn is %d.\n", num_ipv6_modem_pdn);
+ init_fl_rule_ex(data->iptype);
+ }
+ else
+ {
+ init_fl_rule(data->iptype);
+ }
+ }
+
+ /* add WAN DL interface IP specific flt rule for IPv6 when backhaul is not Q6 */
+ if(m_is_sta_mode != Q6_WAN)
+ {
+ if(rx_prop != NULL && is_global_ipv6_addr(data->ipv6_addr)
+ && num_ipv6_dest_flt_rule < MAX_DEFAULT_v6_ROUTE_RULES)
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+
+ flt_rule = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!flt_rule)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ flt_rule->commit = 1;
+ flt_rule->ep = rx_prop->rx[0].src_pipe;
+ flt_rule->global = false;
+ flt_rule->ip = IPA_IP_v6;
+ flt_rule->num_rules = 1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(flt_rule_entry.rule.attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ memcpy(flt_rule_entry.rule.attrib.u.v6.dst_addr, data->ipv6_addr, sizeof(flt_rule_entry.rule.attrib.u.v6.dst_addr));
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ memcpy(&(flt_rule->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (m_filtering.AddFilteringRule(flt_rule) == false)
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ free(flt_rule);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ ipv6_dest_flt_rule_hdl[num_ipv6_dest_flt_rule] = flt_rule->rules[0].flt_rule_hdl;
+ IPACMDBG_H("IPv6 dest filter rule %d HDL:0x%x\n", num_ipv6_dest_flt_rule, ipv6_dest_flt_rule_hdl[num_ipv6_dest_flt_rule]);
+ num_ipv6_dest_flt_rule++;
+ free(flt_rule);
+ }
+ }
+ }
+ /* store ipv6 prefix if the ipv6 address is not link local */
+ if(is_global_ipv6_addr(data->ipv6_addr))
+ {
+ memcpy(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix));
+ }
+ num_dft_rt_v6++;
+ }
+ else
+ {
+ if(wan_v4_addr_set)
+ {
+ /* check iface ipv4 same or not */
+ if(data->ipv4_addr == wan_v4_addr)
+ {
+ IPACMDBG_H("Already setup device (%s) ipv4 and it didn't change(0x%x)\n", dev_name, data->ipv4_addr);
+ return IPACM_SUCCESS;
+ }
+ else
+ {
+ IPACMDBG_H(" device (%s) ipv4 addr is changed\n", dev_name);
+ /* Delete default v4 RT rule */
+ IPACMDBG_H("Delete default v4 routing rules\n");
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+ {
+ IPACMERR("Routing old RT rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = data->iptype;
+ rt_rule_entry = &rt_rule->rules[0];
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+ hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if(m_header.GetHeaderHandle(&hdr) == false)
+ {
+ IPACMERR("Failed to get QMAP header.\n");
+ return IPACM_FAILURE;
+ }
+ rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+ }
+ rt_rule_entry->at_rear = false;
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+ /* still need setup v4 default routing rule to A5*/
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, sizeof(rt_rule->rt_tbl_name));
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = false;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG_H("ipv4 wan iface rt-rule hdll=0x%x\n", dft_rt_rule_hdl[0]);
+ /* initial multicast/broadcast/fragment filter rule */
+
+ /* only do one time */
+ if(!wan_v4_addr_set)
+ {
+ /* initial multicast/broadcast/fragment filter rule */
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ modem_ipv4_pdn_index = num_ipv4_modem_pdn;
+ num_ipv4_modem_pdn++;
+ IPACMDBG_H("Now the number of modem ipv4 pdn is %d.\n", num_ipv4_modem_pdn);
+ init_fl_rule_ex(data->iptype);
+ }
+ else
+ {
+ init_fl_rule(data->iptype);
+ }
+ }
+
+ wan_v4_addr = data->ipv4_addr;
+ wan_v4_addr_set = true;
+
+ if (m_is_sta_mode == Q6_WAN)
+ curr_wan_ip = data->ipv4_addr;
+
+ IPACMDBG_H("Receved wan ipv4-addr:0x%x\n",wan_v4_addr);
+ }
+
+#ifdef FEATURE_IPACM_HAL
+ /* check if having pending add_downstream cache*/
+ OffloadMng = IPACM_OffloadManager::GetInstance();
+ if (OffloadMng == NULL) {
+ IPACMERR("failed to get IPACM_OffloadManager instance !\n");
+ } else {
+ IPACMDBG_H(" check iface %s if having add_downstream cache events\n", dev_name);
+ OffloadMng->search_framwork_cache(dev_name);
+ }
+#endif
+ IPACMDBG_H("number of default route rules %d\n", num_dft_rt_v6);
+
+fail:
+ 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_WLAN_LINK_DOWN_EVENT:
+ {
+ if(m_is_sta_mode == WLAN_WAN)
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_WLAN_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ /* reset the STA-iface category to unknown */
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat = UNKNOWN_IF;
+ IPACMDBG_H("IPA_WAN_STA (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ delete this;
+ return;
+ }
+ }
+ }
+ break;
+
+ case IPA_WAN_XLAT_CONNECT_EVENT:
+ {
+ IPACMDBG_H("Recieved IPA_WAN_XLAT_CONNECT_EVENT\n");
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+ if ((ipa_interface_index == ipa_if_num) && (m_is_sta_mode == Q6_WAN))
+ {
+ is_xlat = true;
+ IPACMDBG_H("WAN-LTE (%s) link up, iface: %d is_xlat: %d\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,data->if_index, is_xlat);
+ }
+ break;
+ }
+ case IPA_CFG_CHANGE_EVENT:
+ {
+ if ( (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == ipa_if_cate) &&
+ (m_is_sta_mode ==ECM_WAN))
+ {
+ IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT and category did not change(wan_mode:%d)\n", m_is_sta_mode);
+ IPACMDBG_H("Now the cradle wan mode is %d.\n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode);
+ if(is_default_gateway == true)
+ {
+ if(backhaul_is_wan_bridge == false && IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == BRIDGE)
+ {
+ IPACMDBG_H("Cradle wan mode switch to bridge mode.\n");
+ backhaul_is_wan_bridge = true;
+ }
+ else if(backhaul_is_wan_bridge == true && IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+ {
+ IPACMDBG_H("Cradle wan mode switch to router mode.\n");
+ backhaul_is_wan_bridge = false;
+ }
+ else
+ {
+ IPACMDBG_H("No cradle mode switch, return.\n");
+ return;
+ }
+ /* post wan mode change event to LAN/WLAN */
+ if(IPACM_Wan::wan_up == true)
+ {
+ IPACMDBG_H("This interface is default GW.\n");
+ ipacm_cmd_q_data evt_data;
+ memset(&evt_data, 0, sizeof(evt_data));
+
+ ipacm_event_cradle_wan_mode *data_wan_mode = NULL;
+ data_wan_mode = (ipacm_event_cradle_wan_mode *)malloc(sizeof(ipacm_event_cradle_wan_mode));
+ if(data_wan_mode == NULL)
+ {
+ IPACMERR("unable to allocate memory.\n");
+ return;
+ }
+ data_wan_mode->cradle_wan_mode = IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode;
+ evt_data.event = IPA_CRADLE_WAN_MODE_SWITCH;
+ evt_data.evt_data = data_wan_mode;
+ IPACMDBG_H("Posting IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ /* update the firewall flt rule actions */
+ if(active_v4)
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ config_dft_firewall_rules(IPA_IP_v4);
+ }
+ if(active_v6)
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ config_dft_firewall_rules(IPA_IP_v6);
+ }
+ }
+ else
+ {
+ IPACMDBG_H("This interface is not default GW, ignore.\n");
+ }
+ }
+ else if ( (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat != ipa_if_cate) &&
+ (m_is_sta_mode ==ECM_WAN))
+ {
+ IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT and category changed(wan_mode:%d)\n", m_is_sta_mode);
+ /* posting link-up event for cradle use-case */
+ ipacm_cmd_q_data evt_data;
+ memset(&evt_data, 0, sizeof(evt_data));
+
+ ipacm_event_data_fid *data_fid = NULL;
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for IPA_USB_LINK_UP_EVENT data_fid\n");
+ return;
+ }
+ if(IPACM_Iface::ipa_get_if_index(dev_name, &(data_fid->if_index)))
+ {
+ IPACMERR("Error while getting interface index for %s device", dev_name);
+ }
+ evt_data.event = IPA_USB_LINK_UP_EVENT;
+ evt_data.evt_data = data_fid;
+ IPACMDBG_H("Posting event:%d\n", evt_data.event);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+ /* delete previous instance */
+ handle_down_evt();
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ delete this;
+ return;
+ }
+ }
+ break;
+
+ case IPA_LINK_DOWN_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ IPACMDBG_H("Received IPA_LINK_DOWN_EVENT\n");
+ handle_down_evt_ex();
+ IPACMDBG_H("IPA_WAN_Q6 (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ delete this;
+ return;
+ }
+ else if (m_is_sta_mode == ECM_WAN)
+ {
+ IPACMDBG_H("Received IPA_LINK_DOWN_EVENT(wan_mode:%d)\n", m_is_sta_mode);
+ /* delete previous instance */
+ handle_down_evt();
+ IPACMDBG_H("IPA_WAN_CRADLE (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ delete this;
+ return;
+ }
+ }
+ }
+ break;
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ if ( (data->iptype == IPA_IP_v4 && data->ipv4_addr == 0) ||
+ (data->iptype == IPA_IP_v6 &&
+ data->ipv6_addr[0] == 0 && data->ipv6_addr[1] == 0 &&
+ data->ipv6_addr[2] == 0 && data->ipv6_addr[3] == 0) )
+ {
+ IPACMDBG_H("Invalid address, ignore IPA_ADDR_ADD_EVENT event\n");
+ return;
+ }
+
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Get IPA_ADDR_ADD_EVENT: IF ip type %d, incoming ip type %d\n", ip_type, data->iptype);
+ /* check v4 not setup before, v6 can have 2 iface ip */
+ if( (data->iptype == IPA_IP_v4)
+ || ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
+ {
+ IPACMDBG_H("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
+ handle_addr_evt(data);
+ /* checking if SW-RT_enable */
+ if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true &&
+ m_is_sta_mode != Q6_WAN)
+ {
+ /* handle software routing enable event*/
+ IPACMDBG_H("IPA_SW_ROUTING_ENABLE for iface: %s \n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+ handle_software_routing_enable();
+ }
+
+ }
+ }
+ }
+ break;
+
+
+ case IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT:
+ {
+ ipacm_event_data_iptype *data = (ipacm_event_data_iptype *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+#ifndef FEATURE_IPACM_HAL
+ /* add the check see if tether_iface is valid or not */
+ if (iface_ipa_index_query(data->if_index_tether) == INVALID_IFACE)
+ {
+ IPACMERR("UPSTREAM_ROUTE_ADD tether_if(%d), not valid ignore\n", INVALID_IFACE);
+ return;
+ }
+#endif
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT (Android) for ip-type (%d)\n", data->iptype);
+ /* The special below condition is to handle default gateway */
+ if ((data->iptype == IPA_IP_v4) && (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX))
+ {
+ if (active_v4 == false)
+ {
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+ IPACMDBG_H("adding routing table(upstream), dev (%s) ip-type(%d) default gw (%x)\n", dev_name,data->iptype, wan_v4_addr_gw);
+ wan_v4_addr_gw = data->ipv4_addr_gw;
+ wan_v4_addr_gw_set = true;
+ /* Check & construct STA header */
+ handle_sta_header_add_evt();
+#else
+ IPACMDBG_H("adding routing table(upstream), dev (%s) ip-type(%d)\n", dev_name,data->iptype);
+#endif
+ if (active_v4 == false)
+ {
+ handle_route_add_evt(data->iptype); //sky
+ }
+ }
+#ifdef FEATURE_IPA_ANDROID
+#ifdef FEATURE_IPACM_HAL
+ post_wan_up_tether_evt(data->iptype, 0);
+#else
+ /* using ipa_if_index, not netdev_index */
+ post_wan_up_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
+#endif
+#endif
+ }
+ else if ((data->iptype == IPA_IP_v6) && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
+ {
+ if(ipv6_prefix[0] == 0 && ipv6_prefix[1] == 0)
+ {
+ IPACMDBG_H("IPv6 default route comes earlier than global IP, ignore.\n");
+ return;
+ }
+
+ if (active_v6 == false)
+ {
+ IPACMDBG_H("\n get default v6 route (dst:00.00.00.00) upstream\n");
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+ IPACMDBG_H(" IPV6 gateway: %08x:%08x:%08x:%08x \n",
+ data->ipv6_addr_gw[0], data->ipv6_addr_gw[1], data->ipv6_addr_gw[2], data->ipv6_addr_gw[3]);
+ wan_v6_addr_gw[0] = data->ipv6_addr_gw[0];
+ wan_v6_addr_gw[1] = data->ipv6_addr_gw[1];
+ wan_v6_addr_gw[2] = data->ipv6_addr_gw[2];
+ wan_v6_addr_gw[3] = data->ipv6_addr_gw[3];
+ wan_v6_addr_gw_set = true;
+ /* Check & construct STA header */
+ handle_sta_header_add_evt();
+#endif
+ if (active_v6 == false)
+ {
+ handle_route_add_evt(data->iptype);
+ }
+ }
+#ifdef FEATURE_IPA_ANDROID
+#ifdef FEATURE_IPACM_HAL
+ post_wan_up_tether_evt(data->iptype, 0);
+#else
+ /* using ipa_if_index, not netdev_index */
+ post_wan_up_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
+#endif
+#endif
+ }
+ }
+ else /* double check if current default iface is not itself */
+ {
+ if ((data->iptype == IPA_IP_v4) && (active_v4 == true))
+ {
+ IPACMDBG_H("Received v4 IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+ IPACMDBG_H("need clean default v4 route (dst:0.0.0.0) for old iface (%s)\n", dev_name);
+ wan_v4_addr_gw_set = false;
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ del_wan_firewall_rule(IPA_IP_v4);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v4);
+ }
+ else
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ handle_route_del_evt(IPA_IP_v4);
+ }
+ }
+ else if ((data->iptype == IPA_IP_v6) && (active_v6 == true))
+ {
+ IPACMDBG_H("Received v6 IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+ IPACMDBG_H("need clean default v6 route for old iface (%s)\n", dev_name);
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ del_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v6);
+ }
+ else
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ handle_route_del_evt(IPA_IP_v6);
+ }
+ }
+ }
+ }
+ break;
+
+ case IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT:
+ {
+ ipacm_event_data_iptype *data = (ipacm_event_data_iptype *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+#ifndef FEATURE_IPACM_HAL
+ /* add the check see if tether_iface is valid or not */
+ if (iface_ipa_index_query(data->if_index_tether) == INVALID_IFACE)
+ {
+ IPACMERR("UPSTREAM_ROUTE_DEL tether_if(%d), not valid ignore\n", INVALID_IFACE);
+ return;
+ }
+#endif
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT\n");
+ if ((data->iptype == IPA_IP_v4) && (active_v4 == true))
+ {
+ IPACMDBG_H("get del default v4 route (dst:0.0.0.0)\n");
+ wan_v4_addr_gw_set = false;
+#ifdef FEATURE_IPA_ANDROID
+#ifdef FEATURE_IPACM_HAL
+ post_wan_down_tether_evt(data->iptype, 0);
+#else
+ /* using ipa_if_index, not netdev_index */
+ post_wan_down_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
+ /* no any ipv4 tether iface support*/
+ if(IPACM_Wan::ipa_if_num_tether_v4_total != 0)
+ {
+ IPACMDBG_H("still have tether ipv4 client on upsteam iface\n");
+ return;
+ }
+#endif
+#endif
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ del_wan_firewall_rule(IPA_IP_v4);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v4);
+ }
+ else
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ handle_route_del_evt(IPA_IP_v4);
+ }
+ }
+ else if ((data->iptype == IPA_IP_v6) && (active_v6 == true))
+ {
+#ifdef FEATURE_IPA_ANDROID
+#ifdef FEATURE_IPACM_HAL
+ post_wan_down_tether_evt(data->iptype, 0);
+#else
+
+ /* using ipa_if_index, not netdev_index */
+ post_wan_down_tether_evt(data->iptype, iface_ipa_index_query(data->if_index_tether));
+ /* no any ipv6 tether iface support*/
+ if(IPACM_Wan::ipa_if_num_tether_v6_total != 0)
+ {
+ IPACMDBG_H("still have tether ipv6 client on upsteam iface\n");
+ return;
+ }
+#endif
+#endif
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ del_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v6);
+ }
+ else
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ handle_route_del_evt(IPA_IP_v6);
+ }
+ }
+ }
+ }
+ break;
+ case IPA_NETWORK_STATS_UPDATE_EVENT:
+ {
+ ipa_get_apn_data_stats_resp_msg_v01 *data = (ipa_get_apn_data_stats_resp_msg_v01 *)param;
+ if (!data->apn_data_stats_list_valid)
+ {
+ IPACMERR("not valid APN\n");
+ return;
+ }
+ else
+ {
+ handle_network_stats_update(data);
+ }
+ }
+ break;
+ case IPA_ROUTE_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_ROUTE_ADD_EVENT\n");
+ IPACMDBG_H("ipv4 addr 0x%x\n", data->ipv4_addr);
+ IPACMDBG_H("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
+
+ /* The special below condition is to handle default gateway */
+ if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == false)
+ && (ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX))
+ {
+ wan_v4_addr_gw = data->ipv4_addr_gw;
+ wan_v4_addr_gw_set = true;
+ IPACMDBG_H("adding routing table, dev (%s) ip-type(%d), default gw (%x)\n", dev_name,data->iptype, wan_v4_addr_gw);
+ /* Check & construct STA header */
+ handle_sta_header_add_evt();
+ handle_route_add_evt(data->iptype);
+ /* Add IPv6 routing table if XLAT is enabled */
+ if(is_xlat && (m_is_sta_mode == Q6_WAN) && (active_v6 == false))
+ {
+ IPACMDBG_H("XLAT enabled: adding IPv6 routing table dev (%s)\n", dev_name);
+ handle_route_add_evt(IPA_IP_v6);
+ }
+ }
+ else if ((data->iptype == IPA_IP_v6) &&
+ (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) &&
+ (active_v6 == false) && (ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX))
+ {
+ if(ipv6_prefix[0] == 0 && ipv6_prefix[1] == 0)
+ {
+ IPACMDBG_H("IPv6 default route comes earlier than global IP, ignore.\n");
+ return;
+ }
+
+ IPACMDBG_H("\n get default v6 route (dst:00.00.00.00)\n");
+ IPACMDBG_H(" IPV6 dst: %08x:%08x:%08x:%08x \n",
+ data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+ IPACMDBG_H(" IPV6 gateway: %08x:%08x:%08x:%08x \n",
+ data->ipv6_addr_gw[0], data->ipv6_addr_gw[1], data->ipv6_addr_gw[2], data->ipv6_addr_gw[3]);
+ wan_v6_addr_gw[0] = data->ipv6_addr_gw[0];
+ wan_v6_addr_gw[1] = data->ipv6_addr_gw[1];
+ wan_v6_addr_gw[2] = data->ipv6_addr_gw[2];
+ wan_v6_addr_gw[3] = data->ipv6_addr_gw[3];
+ wan_v6_addr_gw_set = true;
+ /* Check & construct STA header */
+ handle_sta_header_add_evt();
+ handle_route_add_evt(data->iptype);
+ }
+ }
+ else /* double check if current default iface is not itself */
+ {
+ if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == true))
+ {
+ IPACMDBG_H("Received v4 IPA_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+ IPACMDBG_H("ipv4 addr 0x%x\n", data->ipv4_addr);
+ IPACMDBG_H("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
+ IPACMDBG_H("need clean default v4 route (dst:0.0.0.0) for old iface (%s)\n", dev_name);
+ wan_v4_addr_gw_set = false;
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ del_wan_firewall_rule(IPA_IP_v4);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v4);
+ }
+ else
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ handle_route_del_evt(IPA_IP_v4);
+ }
+ }
+ else if ((data->iptype == IPA_IP_v6) && (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) && (active_v6 == true))
+ {
+ IPACMDBG_H("Received v6 IPA_ROUTE_ADD_EVENT for other iface (%s)\n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+ IPACMDBG_H("need clean default v6 route for old iface (%s)\n", dev_name);
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ del_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v6);
+ }
+ else
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ handle_route_del_evt(IPA_IP_v6);
+ }
+ }
+ }
+ }
+ break;
+
+ case IPA_ROUTE_DEL_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_ROUTE_DEL_EVENT\n");
+ if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask) && (active_v4 == true))
+ {
+ IPACMDBG_H("get del default v4 route (dst:0.0.0.0)\n");
+ wan_v4_addr_gw_set = false;
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ del_wan_firewall_rule(IPA_IP_v4);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v4);
+
+ if(is_xlat && active_v6 == true)
+ {
+ IPACMDBG_H("XLAT enabled: Delete IPv6 routing table dev (%s)\n", dev_name);
+ del_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v6);
+ }
+ }
+ else
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ handle_route_del_evt(IPA_IP_v4);
+ }
+ }
+ else if ((data->iptype == IPA_IP_v6) && (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]) && (active_v6 == true))
+ {
+
+ IPACMDBG_H("get del default v6 route (dst:00.00.00.00)\n");
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ del_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v6);
+ }
+ else
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ handle_route_del_evt(IPA_IP_v6);
+ }
+ }
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
+
+ if (m_is_sta_mode == WLAN_WAN)
+ {
+ if (data->iptype == IPA_IP_v4 && data->ipv4_addr == wan_v4_addr)
+ {
+ IPACMDBG_H("Ignore IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
+ IPACMDBG_H("for its own ipv4 address\n");
+ return;
+ }
+ else if (data->iptype == IPA_IP_v6)
+ {
+ for (uint32_t num_ipv6_addr = 0; num_ipv6_addr < num_dft_rt_v6; num_ipv6_addr++)
+ {
+ if ((ipv6_addr[num_ipv6_addr][0] == data->ipv6_addr[0]) &&
+ (ipv6_addr[num_ipv6_addr][1] == data->ipv6_addr[1]) &&
+ (ipv6_addr[num_ipv6_addr][2] == data->ipv6_addr[2]) &&
+ (ipv6_addr[num_ipv6_addr][3] == data->ipv6_addr[3]))
+ {
+ IPACMDBG_H("Ignore IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT in STA mode\n");
+ IPACMDBG_H("for its own ipv6 address\n");
+ return;
+ }
+ }
+ }
+ }
+
+ IPACMDBG_H("wan-iface got client \n");
+ /* first construc WAN-client full header */
+ if(memcmp(data->mac_addr,
+ invalid_mac,
+ sizeof(data->mac_addr)) == 0)
+ {
+ IPACMDBG_H("Received invalid Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->mac_addr[0], data->mac_addr[1], data->mac_addr[2],
+ data->mac_addr[3], data->mac_addr[4], data->mac_addr[5]);
+ return;
+ }
+
+ handle_wan_hdr_init(data->mac_addr);
+ IPACMDBG_H("construct wan-client header and route rules \n");
+ /* Associate with IP and construct RT-rule */
+ if (handle_wan_client_ipaddr(data) == IPACM_FAILURE)
+ {
+ return;
+ }
+ handle_wan_client_route_rule(data->mac_addr, data->iptype);
+ /* Check & construct STA header */
+ handle_sta_header_add_evt();
+ return;
+ }
+ }
+ break;
+
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG_H("Received IPA_SW_ROUTING_ENABLE\n");
+ /* handle software routing enable event */
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ install_wan_filtering_rule(true);
+ }
+ else
+ {
+ handle_software_routing_enable();
+ }
+ break;
+
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG_H("Received IPA_SW_ROUTING_DISABLE\n");
+ /* handle software routing disable event */
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ /* send current DL rules to modem */
+ install_wan_filtering_rule(false);
+ softwarerouting_act = false;
+ }
+ else
+ {
+ handle_software_routing_disable();
+ }
+ break;
+
+ case IPA_FIREWALL_CHANGE_EVENT:
+ IPACMDBG_H("Received IPA_FIREWALL_CHANGE_EVENT\n");
+
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ if(is_default_gateway == false)
+ {
+ IPACMDBG_H("Interface %s is not default gw, return.\n", dev_name);
+ return;
+ }
+
+ if(ip_type == IPA_IP_v4)
+ {
+ del_wan_firewall_rule(IPA_IP_v4);
+ config_wan_firewall_rule(IPA_IP_v4);
+ install_wan_filtering_rule(false);
+ }
+ else if(ip_type == IPA_IP_v6)
+ {
+ del_wan_firewall_rule(IPA_IP_v6);
+ config_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ }
+ else if(ip_type == IPA_IP_MAX)
+ {
+ del_wan_firewall_rule(IPA_IP_v4);
+ config_wan_firewall_rule(IPA_IP_v4);
+
+ del_wan_firewall_rule(IPA_IP_v6);
+ config_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ }
+ else
+ {
+ IPACMERR("IP type is not expected.\n");
+ }
+ }
+ else
+ {
+ if (active_v4)
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ config_dft_firewall_rules(IPA_IP_v4);
+ }
+ if (active_v6)
+ {
+
+ del_dft_firewall_rules(IPA_IP_v6);
+ config_dft_firewall_rules(IPA_IP_v6);
+ }
+ }
+ break;
+
+ case IPA_WLAN_SWITCH_TO_SCC:
+ if(IPACM_Wan::backhaul_is_sta_mode == true)
+ {
+ IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_SCC\n");
+ if(ip_type == IPA_IP_MAX)
+ {
+ handle_wlan_SCC_MCC_switch(true, IPA_IP_v4);
+ handle_wlan_SCC_MCC_switch(true, IPA_IP_v6);
+ handle_wan_client_SCC_MCC_switch(true, IPA_IP_v4);
+ handle_wan_client_SCC_MCC_switch(true, IPA_IP_v6);
+ }
+ else
+ {
+ handle_wlan_SCC_MCC_switch(true, ip_type);
+ handle_wan_client_SCC_MCC_switch(true, ip_type);
+ }
+ }
+ break;
+
+ case IPA_WLAN_SWITCH_TO_MCC:
+ if(IPACM_Wan::backhaul_is_sta_mode == true)
+ {
+ IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_MCC\n");
+ if(ip_type == IPA_IP_MAX)
+ {
+ handle_wlan_SCC_MCC_switch(false, IPA_IP_v4);
+ handle_wlan_SCC_MCC_switch(false, IPA_IP_v6);
+ handle_wan_client_SCC_MCC_switch(false, IPA_IP_v4);
+ handle_wan_client_SCC_MCC_switch(false, IPA_IP_v6);
+ }
+ else
+ {
+ handle_wlan_SCC_MCC_switch(false, ip_type);
+ handle_wan_client_SCC_MCC_switch(false, ip_type);
+ }
+ }
+ break;
+#ifdef FEATURE_IPACM_HAL
+ /* WA for WLAN to clean up NAT instance during SSR */
+ case IPA_SSR_NOTICE: //sky
+ IPACMDBG_H("Received IPA_SSR_NOTICE event.\n");
+ if(m_is_sta_mode == WLAN_WAN)
+ {
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return;
+}
+
+/* wan default route/filter rule configuration */
+int IPACM_Wan::handle_route_add_evt(ipa_ip_type iptype)
+{
+
+ /* add default WAN route */
+ struct ipa_ioc_add_rt_rule *rt_rule = NULL;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ uint32_t tx_index = 0;
+ const int NUM = 1;
+ ipacm_cmd_q_data evt_data;
+ struct ipa_ioc_get_hdr hdr;
+
+ IPACMDBG_H("ip-type:%d\n", iptype);
+
+ /* copy header from tx-property, see if partial or not */
+ /* assume all tx-property uses the same header name for v4 or v6*/
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No tx properties, ignore default route setting\n");
+ return IPACM_SUCCESS;
+ }
+
+ is_default_gateway = true;
+ IPACMDBG_H("Default route is added to iface %s.\n", dev_name);
+
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == BRIDGE)
+ {
+ IPACM_Wan::backhaul_is_wan_bridge = true;
+ }
+ else
+ {
+ IPACM_Wan::backhaul_is_wan_bridge = false;
+ }
+ IPACMDBG_H("backhaul_is_wan_bridge ?: %d \n", IPACM_Wan::backhaul_is_wan_bridge);
+
+ if (m_is_sta_mode !=Q6_WAN)
+ {
+ IPACM_Wan::backhaul_is_sta_mode = true;
+ if((iptype==IPA_IP_v4) && (header_set_v4 != true))
+ {
+ header_partial_default_wan_v4 = true;
+ IPACMDBG_H("STA ipv4-header haven't constructed \n");
+ return IPACM_SUCCESS;
+ }
+ else if((iptype==IPA_IP_v6) && (header_set_v6 != true))
+ {
+ header_partial_default_wan_v6 = true;
+ IPACMDBG_H("STA ipv6-header haven't constructed \n");
+ return IPACM_SUCCESS;
+ }
+ }
+ else
+ {
+ IPACM_Wan::backhaul_is_sta_mode = false;
+ IPACMDBG_H("reset backhaul to LTE \n");
+
+ if (iface_query != NULL && iface_query->num_ext_props > 0)
+ {
+ if(ext_prop == NULL)
+ {
+ IPACMERR("Extended property is empty.\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->SetQmapId(ext_prop->ext[0].mux_id);
+ IPACMDBG_H("Setting up QMAP ID %d.\n", ext_prop->ext[0].mux_id);
+ }
+ }
+ else
+ {
+ IPACMERR("iface_query is empty.\n");
+ return IPACM_FAILURE;
+ }
+ }
+#if 0
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==iptype)
+ break;
+ }
+
+ if(tx_prop->tx[cnt].hdr_name != NULL)
+ {
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG_H("header name: %s\n", sCopyHeader.name);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ IPACMERR("ioctl copy header failed");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ if(sCopyHeader.is_partial)
+ {
+ IPACMDBG_H("Not setup default WAN routing rules cuz the header is not complete\n");
+ if(iptype==IPA_IP_v4)
+ {
+ header_partial_default_wan_v4 = true;
+ }
+ else
+ {
+ header_partial_default_wan_v6 = true;
+ }
+ return IPACM_SUCCESS;
+ }
+ else
+ {
+ if(iptype==IPA_IP_v4)
+ {
+ header_partial_default_wan_v4 = false;
+ }
+ else
+ {
+ header_partial_default_wan_v6 = false;
+ }
+ }
+ }
+#endif
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)NUM;
+ rt_rule->ip = iptype;
+
+
+ IPACMDBG_H(" WAN table created %s \n", rt_rule->rt_tbl_name);
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = true;
+
+ if(m_is_sta_mode != Q6_WAN)
+ {
+ IPACMDBG_H(" WAN instance is in STA mode \n");
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if(iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+ tx_index, tx_prop->tx[tx_index].ip,iptype);
+ continue;
+ }
+
+ /* use the STA-header handler */
+ if (iptype == IPA_IP_v4)
+ {
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name, sizeof(rt_rule->rt_tbl_name));
+ rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v4;
+ }
+ else
+ {
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name, sizeof(rt_rule->rt_tbl_name));
+ rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v6;
+ }
+
+ if(IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ if (iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = 0;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
+#ifdef FEATURE_IPA_V3
+
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ wan_route_rule_v4_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG_H("Got ipv4 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+ wan_route_rule_v4_hdl[tx_index],
+ tx_index,
+ iptype);
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ wan_route_rule_v6_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG_H("Set ipv6 wan-route rule hdl for v6_lan_table:0x%x,tx:%d,ip-type: %d \n",
+ wan_route_rule_v6_hdl[tx_index],
+ tx_index,
+ iptype);
+ }
+ }
+ }
+
+ /* add a catch-all rule in wan dl routing table */
+
+ if (iptype == IPA_IP_v6)
+ {
+ strlcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, sizeof(rt_rule->rt_tbl_name));
+ memset(rt_rule_entry, 0, sizeof(struct ipa_rt_rule_add));
+ rt_rule_entry->at_rear = true;
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ memset(&hdr, 0, sizeof(hdr));
+ strlcpy(hdr.name, tx_prop->tx[0].hdr_name, sizeof(hdr.name));
+ hdr.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if(m_header.GetHeaderHandle(&hdr) == false)
+ {
+ IPACMERR("Failed to get QMAP header.\n");
+ return IPACM_FAILURE;
+ }
+ rt_rule_entry->rule.hdr_hdl = hdr.hdl;
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_WAN_CONS;
+ }
+ else
+ {
+ /* create dummy ethernet header for v6 RX path */
+ IPACMDBG_H("Construct dummy ethernet_header\n");
+ if (add_dummy_rx_hdr())
+ {
+ IPACMERR("Construct dummy ethernet_header failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ rt_rule_entry->rule.hdr_proc_ctx_hdl = hdr_proc_hdl_dummy_v6;
+ rt_rule_entry->rule.dst = IPA_CLIENT_APPS_LAN_CONS;
+ }
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ wan_route_rule_v6_hdl_a5[0] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG_H("Set ipv6 wan-route rule hdl for v6_wan_table:0x%x,tx:%d,ip-type: %d \n",
+ wan_route_rule_v6_hdl_a5[0], 0, iptype);
+ }
+
+ ipacm_event_iface_up *wanup_data;
+ wanup_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+ if (wanup_data == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ memset(wanup_data, 0, sizeof(ipacm_event_iface_up));
+
+ if (iptype == IPA_IP_v4)
+ {
+ IPACM_Wan::wan_up = true;
+ active_v4 = true;
+ memcpy(IPACM_Wan::wan_up_dev_name,
+ dev_name,
+ sizeof(IPACM_Wan::wan_up_dev_name));
+
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ config_wan_firewall_rule(IPA_IP_v4);
+ install_wan_filtering_rule(false);
+ }
+ else
+ {
+ config_dft_firewall_rules(IPA_IP_v4);
+ }
+
+ memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
+ wanup_data->ipv4_addr = wan_v4_addr;
+ if (m_is_sta_mode!=Q6_WAN)
+ {
+ wanup_data->is_sta = true;
+ }
+ else
+ {
+ wanup_data->is_sta = false;
+ }
+ IPACMDBG_H("Posting IPA_HANDLE_WAN_UP with below information:\n");
+ IPACMDBG_H("if_name:%s, ipv4_address:0x%x, is sta mode:%d\n",
+ wanup_data->ifname, wanup_data->ipv4_addr, wanup_data->is_sta);
+ memset(&evt_data, 0, sizeof(evt_data));
+
+ /* send xlat configuration for installing uplink rules */
+ if(is_xlat && (m_is_sta_mode == Q6_WAN))
+ {
+ IPACM_Wan::xlat_mux_id = ext_prop->ext[0].mux_id;
+ wanup_data->xlat_mux_id = IPACM_Wan::xlat_mux_id;
+ IPACMDBG_H("Set xlat configuraiton with below information:\n");
+ IPACMDBG_H("xlat_enabled: %d xlat_mux_id: %d \n",
+ is_xlat, xlat_mux_id);
+ }
+ else
+ {
+ IPACM_Wan::xlat_mux_id = 0;
+ wanup_data->xlat_mux_id = 0;
+ IPACMDBG_H("No xlat configuratio:\n");
+ }
+ evt_data.event = IPA_HANDLE_WAN_UP;
+ evt_data.evt_data = (void *)wanup_data;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ else
+ {
+ memcpy(backhaul_ipv6_prefix, ipv6_prefix, sizeof(backhaul_ipv6_prefix));
+ IPACMDBG_H("Setup backhaul ipv6 prefix to be 0x%08x%08x.\n", backhaul_ipv6_prefix[0], backhaul_ipv6_prefix[1]);
+
+ IPACM_Wan::wan_up_v6 = true;
+ active_v6 = true;
+ memcpy(IPACM_Wan::wan_up_dev_name,
+ dev_name,
+ sizeof(IPACM_Wan::wan_up_dev_name));
+
+ if(m_is_sta_mode == Q6_WAN)
+ {
+ config_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ }
+ else
+ {
+ config_dft_firewall_rules(IPA_IP_v6);
+ }
+
+ memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
+ if (m_is_sta_mode!=Q6_WAN)
+ {
+ wanup_data->is_sta = true;
+ }
+ else
+ {
+ wanup_data->is_sta = false;
+ }
+ memcpy(wanup_data->ipv6_prefix, ipv6_prefix, sizeof(wanup_data->ipv6_prefix));
+ IPACMDBG_H("Posting IPA_HANDLE_WAN_UP_V6 with below information:\n");
+ IPACMDBG_H("if_name:%s, is sta mode: %d\n", wanup_data->ifname, wanup_data->is_sta);
+ IPACMDBG_H("ipv6 prefix: 0x%08x%08x.\n", ipv6_prefix[0], ipv6_prefix[1]);
+ memset(&evt_data, 0, sizeof(evt_data));
+ evt_data.event = IPA_HANDLE_WAN_UP_V6;
+ evt_data.evt_data = (void *)wanup_data;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ /* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+
+ if(rt_rule != NULL)
+ {
+ free(rt_rule);
+ }
+ return IPACM_SUCCESS;
+}
+
+#ifdef FEATURE_IPA_ANDROID
+/* wan default route/filter rule configuration */
+int IPACM_Wan::post_wan_up_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether)
+{
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_iface_up_tehter *wanup_data;
+
+ wanup_data = (ipacm_event_iface_up_tehter *)malloc(sizeof(ipacm_event_iface_up_tehter));
+ if (wanup_data == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return IPACM_FAILURE;
+ }
+ memset(wanup_data, 0, sizeof(ipacm_event_iface_up_tehter));
+
+ wanup_data->if_index_tether = ipa_if_num_tether;
+ if (m_is_sta_mode!=Q6_WAN)
+ {
+ wanup_data->is_sta = true;
+ }
+ else
+ {
+ wanup_data->is_sta = false;
+ }
+ IPACMDBG_H("Posting IPA_HANDLE_WAN_UP_TETHER with below information:\n");
+ IPACMDBG_H("tether_if_name:%s, is sta mode:%d\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name, wanup_data->is_sta);
+ memset(&evt_data, 0, sizeof(evt_data));
+
+ if (iptype == IPA_IP_v4)
+ {
+ evt_data.event = IPA_HANDLE_WAN_UP_TETHER;
+ /* Add support tether ifaces to its array*/
+ IPACM_Wan::ipa_if_num_tether_v4[IPACM_Wan::ipa_if_num_tether_v4_total] = ipa_if_num_tether;
+ IPACMDBG_H("adding tether iface(%s) ipa_if_num_tether_v4_total(%d) on wan_iface(%s)\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name,
+ IPACM_Wan::ipa_if_num_tether_v4_total,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+ IPACM_Wan::ipa_if_num_tether_v4_total++;
+ }
+ else
+ {
+ evt_data.event = IPA_HANDLE_WAN_UP_V6_TETHER;
+ memcpy(wanup_data->ipv6_prefix, ipv6_prefix, sizeof(wanup_data->ipv6_prefix));
+ /* Add support tether ifaces to its array*/
+ IPACM_Wan::ipa_if_num_tether_v6[IPACM_Wan::ipa_if_num_tether_v6_total] = ipa_if_num_tether;
+ IPACMDBG_H("adding tether iface(%s) ipa_if_num_tether_v6_total(%d) on wan_iface(%s)\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name,
+ IPACM_Wan::ipa_if_num_tether_v6_total,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+ IPACM_Wan::ipa_if_num_tether_v6_total++;
+ }
+ evt_data.evt_data = (void *)wanup_data;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+ return IPACM_SUCCESS;
+}
+
+
+/* wan default route/filter rule configuration */
+int IPACM_Wan::post_wan_down_tether_evt(ipa_ip_type iptype, int ipa_if_num_tether)
+{
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_iface_up_tehter *wandown_data;
+
+ wandown_data = (ipacm_event_iface_up_tehter *)malloc(sizeof(ipacm_event_iface_up_tehter));
+ if (wandown_data == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return IPACM_FAILURE;
+ }
+ memset(wandown_data, 0, sizeof(ipacm_event_iface_up_tehter));
+
+ wandown_data->if_index_tether = ipa_if_num_tether;
+ if (m_is_sta_mode!=Q6_WAN)
+ {
+ wandown_data->is_sta = true;
+ }
+ else
+ {
+ wandown_data->is_sta = false;
+ }
+ IPACMDBG_H("Posting IPA_HANDLE_WAN_DOWN_TETHER with below information:\n");
+ IPACMDBG_H("tether_if_name:%s, is sta mode:%d\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether].iface_name, wandown_data->is_sta);
+ memset(&evt_data, 0, sizeof(evt_data));
+
+ if (iptype == IPA_IP_v4)
+ {
+ if(delete_tether_iface(iptype, ipa_if_num_tether))
+ {
+ IPACMDBG_H("Not finding the tethered client on ipv4.\n");
+ free(wandown_data);
+ return IPACM_SUCCESS;
+ }
+ evt_data.event = IPA_HANDLE_WAN_DOWN_TETHER;
+ }
+ else
+ {
+ if(delete_tether_iface(iptype, ipa_if_num_tether))
+ {
+ IPACMDBG_H("Not finding the tethered client on ipv6.\n");
+ free(wandown_data);
+ return IPACM_SUCCESS;
+ }
+ evt_data.event = IPA_HANDLE_WAN_DOWN_V6_TETHER;
+ }
+ evt_data.evt_data = (void *)wandown_data;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ return IPACM_SUCCESS;
+}
+#endif
+
+/* construct complete ethernet header */
+int IPACM_Wan::handle_sta_header_add_evt()
+{
+ int res = IPACM_SUCCESS, index = IPACM_INVALID_INDEX;
+ if((header_set_v4 == true) || (header_set_v6 == true))
+ {
+ IPACMDBG_H("Already add STA full header\n");
+ return IPACM_SUCCESS;
+ }
+
+ /* checking if the ipv4 same as default route */
+ if(wan_v4_addr_gw_set)
+ {
+ index = get_wan_client_index_ipv4(wan_v4_addr_gw);
+ if (index != IPACM_INVALID_INDEX)
+ {
+ IPACMDBG_H("Matched client index: %d\n", index);
+ IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wan_client, index)->mac[0],
+ get_client_memptr(wan_client, index)->mac[1],
+ get_client_memptr(wan_client, index)->mac[2],
+ get_client_memptr(wan_client, index)->mac[3],
+ get_client_memptr(wan_client, index)->mac[4],
+ get_client_memptr(wan_client, index)->mac[5]);
+
+ if(get_client_memptr(wan_client, index)->ipv4_header_set)
+ {
+ hdr_hdl_sta_v4 = get_client_memptr(wan_client, index)->hdr_hdl_v4;
+ header_set_v4 = true;
+ IPACMDBG_H("add full ipv4 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v4);
+ /* store external_ap's MAC */
+ memcpy(ext_router_mac_addr, get_client_memptr(wan_client, index)->mac, sizeof(ext_router_mac_addr));
+ }
+ else
+ {
+ IPACMERR(" wan-client got ipv4 however didn't construct complete ipv4 header \n");
+ return IPACM_FAILURE;
+ }
+
+ if(get_client_memptr(wan_client, index)->ipv6_header_set)
+ {
+ hdr_hdl_sta_v6 = get_client_memptr(wan_client, index)->hdr_hdl_v6;
+ header_set_v6 = true;
+ IPACMDBG_H("add full ipv6 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v6);
+ }
+ else
+ {
+ IPACMERR(" wan-client got ipv6 however didn't construct complete ipv6 header \n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMDBG_H(" currently can't find matched wan-client's MAC-addr, waiting for header construction\n");
+ return IPACM_SUCCESS;
+ }
+ }
+
+ /* checking if the ipv4 same as default route */
+ if(wan_v6_addr_gw_set)
+ {
+ index = get_wan_client_index_ipv6(wan_v6_addr_gw);
+ if (index != IPACM_INVALID_INDEX)
+ {
+ IPACMDBG_H("Matched client index: %d\n", index);
+ IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wan_client, index)->mac[0],
+ get_client_memptr(wan_client, index)->mac[1],
+ get_client_memptr(wan_client, index)->mac[2],
+ get_client_memptr(wan_client, index)->mac[3],
+ get_client_memptr(wan_client, index)->mac[4],
+ get_client_memptr(wan_client, index)->mac[5]);
+
+ if(get_client_memptr(wan_client, index)->ipv6_header_set)
+ {
+ hdr_hdl_sta_v6 = get_client_memptr(wan_client, index)->hdr_hdl_v6;
+ header_set_v6 = true;
+ IPACMDBG_H("add full ipv6 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v6);
+ /* store external_ap's MAC */
+ memcpy(ext_router_mac_addr, get_client_memptr(wan_client, index)->mac, sizeof(ext_router_mac_addr));
+ }
+ else
+ {
+ IPACMERR(" wan-client got ipv6 however didn't construct complete ipv4 header \n");
+ return IPACM_FAILURE;
+ }
+
+ if(get_client_memptr(wan_client, index)->ipv4_header_set)
+ {
+ hdr_hdl_sta_v4 = get_client_memptr(wan_client, index)->hdr_hdl_v4;
+ header_set_v4 = true;
+ IPACMDBG_H("add full ipv4 header hdl: (%x)\n", get_client_memptr(wan_client, index)->hdr_hdl_v4);
+ }
+ else
+ {
+ IPACMERR(" wan-client got ipv4 however didn't construct complete ipv4 header \n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMDBG_H(" currently can't find matched wan-client's MAC-addr, waiting for header construction\n");
+ return IPACM_SUCCESS;
+ }
+ }
+
+ /* see if default routes are setup before constructing full header */
+ if(header_partial_default_wan_v4 == true)
+ {
+ handle_route_add_evt(IPA_IP_v4);
+ }
+
+ if(header_partial_default_wan_v6 == true)
+ {
+ handle_route_add_evt(IPA_IP_v6);
+ }
+ return res;
+}
+
+/* For checking attribute mask field in firewall rules for IPv6 only */
+bool IPACM_Wan::check_dft_firewall_rules_attr_mask(IPACM_firewall_conf_t *firewall_config)
+{
+ uint32_t attrib_mask = 0ul;
+ attrib_mask = IPA_FLT_SRC_PORT_RANGE |
+ IPA_FLT_DST_PORT_RANGE |
+ IPA_FLT_TYPE |
+ IPA_FLT_CODE |
+ IPA_FLT_SPI |
+ IPA_FLT_SRC_PORT |
+ IPA_FLT_DST_PORT;
+
+ for (int i = 0; i < firewall_config->num_extd_firewall_entries; i++)
+ {
+ if (firewall_config->extd_firewall_entries[i].ip_vsn == 6)
+ {
+ if (firewall_config->extd_firewall_entries[i].attrib.attrib_mask & attrib_mask)
+ {
+ IPACMDBG_H("IHL based attribute mask is found: install IPv6 frag firewall rule \n");
+ return true;
+ }
+ }
+ }
+ IPACMDBG_H("IHL based attribute mask is not found: no IPv6 frag firewall rule \n");
+ return false;
+}
+
+/* for STA mode: add firewall rules */
+int IPACM_Wan::config_dft_firewall_rules(ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i, rule_v4 = 0, rule_v6 = 0, len;
+
+ IPACMDBG_H("ip-family: %d; \n", iptype);
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ /* default firewall is disable and the rule action is drop */
+ memset(&firewall_config, 0, sizeof(firewall_config));
+ strlcpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
+
+ IPACMDBG_H("Firewall XML file is %s \n", firewall_config.firewall_config_file);
+ if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
+ {
+ IPACMDBG_H("QCMAP Firewall XML read OK \n");
+ /* find the number of v4/v6 firewall rules */
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+ {
+ rule_v4++;
+ }
+ else
+ {
+ rule_v6++;
+ }
+ }
+ IPACMDBG_H("firewall rule v4:%d v6:%d total:%d\n", rule_v4, rule_v6, firewall_config.num_extd_firewall_entries);
+ }
+ else
+ {
+ IPACMERR("QCMAP Firewall XML read failed, no that file, use default configuration \n");
+ }
+
+ /* construct ipa_ioc_add_flt_rule with N firewall rules */
+ ipa_ioc_add_flt_rule *m_pFilteringTable = NULL;
+ len = sizeof(struct ipa_ioc_add_flt_rule) + 1 * sizeof(struct ipa_flt_rule_add);
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!m_pFilteringTable)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ if(iptype == IPA_IP_v6 &&
+ firewall_config.firewall_enable == true &&
+ check_dft_firewall_rules_attr_mask(&firewall_config))
+ {
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = false;
+ flt_rule_entry.rule.hashable = false;
+#endif
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ memcpy(&flt_rule_entry.rule.attrib, &rx_prop->rx[0].attrib, sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ ipv6_frag_firewall_flt_rule_hdl = m_pFilteringTable->rules[0].flt_rule_hdl;
+ is_ipv6_frag_firewall_flt_rule_installed = true;
+ IPACMDBG_H("Installed IPv6 frag firewall rule, handle %d.\n", ipv6_frag_firewall_flt_rule_hdl);
+ }
+ }
+
+ if (iptype == IPA_IP_v4)
+ {
+ if (rule_v4 == 0)
+ {
+ memset(m_pFilteringTable, 0, len);
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_lan_v4) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ /* firewall disable, all traffic are allowed */
+ if(firewall_config.firewall_enable == true)
+ {
+ flt_rule_entry.at_rear = true;
+
+ /* default action for v4 is go DST_NAT unless user set to exception*/
+ if(firewall_config.rule_action_accept == true)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ }
+ else
+ {
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ }
+ }
+ else
+ {
+ flt_rule_entry.at_rear = true;
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.hashable = true;
+#endif
+ 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
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+ else
+ {
+ memset(m_pFilteringTable, 0, len);
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ IPACMDBG_H("Retreiving Routing handle for routing table name:%s\n",
+ IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(&rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("Routing handle for wan routing table:0x%x\n", IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl);
+
+ if(firewall_config.firewall_enable == true)
+ {
+ rule_v4 = 0;
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+
+ /* Accept v4 matched rules*/
+ if(firewall_config.rule_action_accept == true)
+ {
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&flt_rule_entry.rule.attrib,
+ &firewall_config.extd_firewall_entries[i].attrib,
+ sizeof(struct ipa_rule_attrib));
+
+ IPACMDBG_H("rx property attrib mask: 0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ /* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
+ if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol
+ == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+ {
+ /* insert TCP rule*/
+ flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ /* save v4 firewall filter rule handler */
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+
+ /* insert UDP rule*/
+ flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ /* save v4 firewall filter rule handler */
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+ }
+ else
+ {
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ /* save v4 firewall filter rule handler */
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+ }
+ }
+ } /* end of firewall ipv4 filter rule add for loop*/
+ }
+ /* configure default filter rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ /* firewall disable, all traffic are allowed */
+ if(firewall_config.firewall_enable == true)
+ {
+ flt_rule_entry.at_rear = true;
+
+ /* default action for v4 is go DST_NAT unless user set to exception*/
+ if(firewall_config.rule_action_accept == true)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ }
+ else
+ {
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ }
+ }
+ else
+ {
+ flt_rule_entry.at_rear = true;
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_mode == ROUTER)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG_H("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+
+ }
+ else
+ {
+ if (rule_v6 == 0)
+ {
+ memset(m_pFilteringTable, 0, len);
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ /* Construct ICMP rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+ /* copy filter hdls */
+ dft_wan_fl_hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+ /* End of construct ICMP rule */
+
+ /* v6 default route */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v6)) //rt_tbl_wan_v6 rt_tbl_v6
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_wan_v6) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
+
+ /* firewall disable, all traffic are allowed */
+ if(firewall_config.firewall_enable == true)
+ {
+ flt_rule_entry.at_rear = true;
+
+ /* default action for v6 is PASS_TO_ROUTE unless user set to exception*/
+ if(firewall_config.rule_action_accept == true)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ }
+ else
+ {
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ 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
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+ else
+ {
+ memset(m_pFilteringTable, 0, len);
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v6))
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_wan_v6) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ if(firewall_config.firewall_enable == true)
+ {
+ rule_v6 = 0;
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ /* matched rules for v6 go PASS_TO_ROUTE */
+ if(firewall_config.rule_action_accept == true)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &firewall_config.extd_firewall_entries[i].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ /* check if the rule is define as TCP/UDP */
+ if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+ {
+ /* insert TCP rule*/
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ /* save v4 firewall filter rule handler */
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+
+ /* insert UDP rule*/
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ /* save v6 firewall filter rule handler */
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+ }
+ else
+ {
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ /* save v6 firewall filter rule handler */
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+ }
+ }
+ } /* end of firewall ipv6 filter rule add for loop*/
+ }
+
+ /* Construct ICMP rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.eq_attrib_type = 0;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+ /* copy filter hdls */
+ dft_wan_fl_hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ /* End of construct ICMP rule */
+
+ /* setup default wan filter rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.hdl;
+
+ /* firewall disable, all traffic are allowed */
+ if(firewall_config.firewall_enable == true)
+ {
+ flt_rule_entry.at_rear = true;
+
+ /* default action for v6 is PASS_TO_ROUTE unless user set to exception*/
+ if(firewall_config.rule_action_accept == true)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ }
+ else
+ {
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ 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
+ {
+ IPACM_Iface::ipacmcfg->increaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ IPACMDBG_H("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+ /* copy filter hdls*/
+ dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+ }
+
+ if(m_pFilteringTable != NULL)
+ {
+ free(m_pFilteringTable);
+ }
+ return IPACM_SUCCESS;
+}
+
+/* configure the initial firewall filter rules */
+int IPACM_Wan::config_dft_firewall_rules_ex(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i;
+ int num_rules = 0, original_num_rules = 0;
+ ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+ ipa_ioc_generate_flt_eq flt_eq;
+ int pos = rule_offset;
+
+ IPACMDBG_H("ip-family: %d; \n", iptype);
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ if(rules == NULL || rule_offset < 0)
+ {
+ IPACMERR("No filtering table is available.\n");
+ return IPACM_FAILURE;
+ }
+
+ /* default firewall is disable and the rule action is drop */
+ memset(&firewall_config, 0, sizeof(firewall_config));
+ strlcpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
+
+ IPACMDBG_H("Firewall XML file is %s \n", firewall_config.firewall_config_file);
+ if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
+ {
+ IPACMDBG_H("QCMAP Firewall XML read OK \n");
+ }
+ else
+ {
+ IPACMERR("QCMAP Firewall XML read failed, no that file, use default configuration \n");
+ }
+
+ /* add IPv6 frag rule when firewall is enabled*/
+ if(iptype == IPA_IP_v6 &&
+ firewall_config.firewall_enable == true &&
+ check_dft_firewall_rules_attr_mask(&firewall_config))
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = false;
+#endif
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.at_rear = false;
+ flt_rule_entry.rule.hashable = false;
+#endif
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ rt_tbl_idx.ip = IPA_IP_v6;
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ return IPACM_FAILURE;
+ }
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+ IPACMDBG_H("IPv6 frag flt rule uses routing table index %d\n", rt_tbl_idx.idx);
+
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+
+ change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = IPA_IP_v6;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ pos++;
+ IPACM_Wan::num_v6_flt_rule++;
+ }
+
+ if (iptype == IPA_IP_v4)
+ {
+ original_num_rules = IPACM_Wan::num_v4_flt_rule;
+ if(firewall_config.firewall_enable == true)
+ {
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+
+ /* Accept v4 matched rules*/
+ if(firewall_config.rule_action_accept == true)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ rt_tbl_idx.ip = iptype;
+ if(flt_rule_entry.rule.action == IPA_PASS_TO_ROUTING)
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ }
+ else /*pass to dst nat*/
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, IPA_RESOURCE_NAME_MAX);
+ }
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ return IPACM_FAILURE;
+ }
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &firewall_config.extd_firewall_entries[i].attrib,
+ sizeof(struct ipa_rule_attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
+
+ /* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
+ if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+ {
+ /* insert TCP rule*/
+ flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
+ pos++;
+ num_firewall_v4++;
+ IPACM_Wan::num_v4_flt_rule++;
+
+ /* insert UDP rule*/
+ flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
+ pos++;
+ num_firewall_v4++;
+ IPACM_Wan::num_v4_flt_rule++;
+ }
+ else
+ {
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
+ pos++;
+ num_firewall_v4++;
+ IPACM_Wan::num_v4_flt_rule++;
+ }
+ }
+ } /* end of firewall ipv4 filter rule add for loop*/
+ }
+ /* configure default filter rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+
+ /* firewall disable, all traffic are allowed */
+ if(firewall_config.firewall_enable == true)
+ {
+ /* default action for v4 is go DST_NAT unless user set to exception*/
+ if(firewall_config.rule_action_accept == true)
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ }
+ }
+ else
+ {
+ if(isWan_Bridge_Mode())
+ {
+ IPACMDBG_H("ODU is in bridge mode. \n");
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ }
+ else
+ {
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ }
+ }
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ rt_tbl_idx.ip = iptype;
+
+ if(flt_rule_entry.rule.action == IPA_PASS_TO_ROUTING)
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ }
+ else /*pass to dst nat*/
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name, IPA_RESOURCE_NAME_MAX);
+ }
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ return IPACM_FAILURE;
+ }
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACMDBG_H("Filter rule attrib mask: 0x%x\n", rules[pos].rule.attrib.attrib_mask);
+ pos++;
+ num_firewall_v4++;
+ IPACM_Wan::num_v4_flt_rule++;
+
+ num_rules = IPACM_Wan::num_v4_flt_rule - original_num_rules - 1;
+ }
+ else
+ {
+ original_num_rules = IPACM_Wan::num_v6_flt_rule;
+
+ if(firewall_config.firewall_enable == true)
+ {
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ rt_tbl_idx.ip = iptype;
+
+ /* matched rules for v6 go PASS_TO_ROUTE */
+ if(firewall_config.rule_action_accept == true)
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
+ }
+ else
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ }
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ return IPACM_FAILURE;
+ }
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &firewall_config.extd_firewall_entries[i].attrib,
+ sizeof(struct ipa_rule_attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+ /* check if the rule is define as TCP/UDP */
+ if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+ {
+ /* insert TCP rule*/
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ pos++;
+ num_firewall_v6++;
+ IPACM_Wan::num_v6_flt_rule++;
+
+ /* insert UDP rule*/
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ pos++;
+ num_firewall_v6++;
+ IPACM_Wan::num_v6_flt_rule++;
+ }
+ else
+ {
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ pos++;
+ num_firewall_v6++;
+ IPACM_Wan::num_v6_flt_rule++;
+ }
+ }
+ } /* end of firewall ipv6 filter rule add for loop*/
+ }
+
+ /* setup default wan filter rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ rt_tbl_idx.ip = iptype;
+ /* firewall disable, all traffic are allowed */
+ if(firewall_config.firewall_enable == true)
+ {
+ /* default action for v6 is PASS_TO_ROUTE unless user set to exception*/
+ if(firewall_config.rule_action_accept == true)
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ }
+ else
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
+ }
+ }
+ else
+ {
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name, IPA_RESOURCE_NAME_MAX);
+ }
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ return IPACM_FAILURE;
+ }
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[1].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(rules[pos]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ pos++;
+ num_firewall_v6++;
+ IPACM_Wan::num_v6_flt_rule++;
+
+ num_rules = IPACM_Wan::num_v6_flt_rule - original_num_rules - 1;
+ }
+ IPACMDBG_H("Constructed %d firewall rules for ip type %d\n", num_rules, iptype);
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Wan::init_fl_rule_ex(ipa_ip_type iptype)
+{
+ int res = IPACM_SUCCESS;
+
+ /* ADD corresponding ipa_rm_resource_name of RX-endpoint before adding all IPV4V6 FT-rules */
+ IPACMDBG_H(" dun add producer dependency from %s with registered rx-prop\n", dev_name);
+
+ if(iptype == IPA_IP_v4)
+ {
+ if(modem_ipv4_pdn_index == 0) /* install ipv4 default modem DL filtering rules only once */
+ {
+ /* reset the num_v4_flt_rule*/
+ IPACM_Wan::num_v4_flt_rule = 0;
+ add_dft_filtering_rule(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4);
+ }
+ }
+ else if(iptype == IPA_IP_v6)
+ {
+ if(modem_ipv6_pdn_index == 0) /* install ipv6 default modem DL filtering rules only once */
+ {
+ /* reset the num_v6_flt_rule*/
+ IPACM_Wan::num_v6_flt_rule = 0;
+ add_dft_filtering_rule(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6);
+ }
+ }
+ else
+ {
+ IPACMERR("IP type is not expected.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ install_wan_filtering_rule(false);
+
+fail:
+ return res;
+}
+
+int IPACM_Wan::add_icmp_alg_rules(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
+{
+ int res = IPACM_SUCCESS, i, original_num_rules = 0, num_rules = 0;
+ struct ipa_flt_rule_add flt_rule_entry;
+ IPACM_Config* ipacm_config = IPACM_Iface::ipacmcfg;
+ ipa_ioc_generate_flt_eq flt_eq;
+ ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+
+ if(rules == NULL || rule_offset < 0)
+ {
+ IPACMERR("No filtering table is available.\n");
+ return IPACM_FAILURE;
+ }
+
+ if(iptype == IPA_IP_v4)
+ {
+ original_num_rules = IPACM_Wan::num_v4_flt_rule;
+
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("WAN DL routing table %s has index %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, rt_tbl_idx.idx);
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ /* Configuring ICMP filtering rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ /* Multiple PDNs may exist so keep meta-data */
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+ flt_rule_entry.rule.attrib.u.v4.protocol = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACM_Wan::num_v4_flt_rule++;
+
+ /* Configure ALG filtering rules */
+ /* maintain meta data mask */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+ for(i = 0; i < ipacm_config->ipa_num_alg_ports; i++)
+ {
+ flt_rule_entry.rule.attrib.src_port = ipacm_config->alg_table[i].port;
+ flt_rule_entry.rule.attrib.u.v4.protocol = ipacm_config->alg_table[i].protocol;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(rules[rule_offset + 1 + i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACM_Wan::num_v4_flt_rule++;
+ }
+
+ /* maintain meta data mask */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_PORT;
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+ for(i = 0; i < ipacm_config->ipa_num_alg_ports; i++)
+ {
+ flt_rule_entry.rule.attrib.dst_port = ipacm_config->alg_table[i].port;
+ flt_rule_entry.rule.attrib.u.v4.protocol = ipacm_config->alg_table[i].protocol;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[rule_offset + ipacm_config->ipa_num_alg_ports + 1 + i]),
+ &flt_rule_entry,
+ sizeof(struct ipa_flt_rule_add));
+ IPACM_Wan::num_v4_flt_rule++;
+ }
+ num_rules = IPACM_Wan::num_v4_flt_rule - original_num_rules;
+ }
+ else /* IPv6 case */
+ {
+ original_num_rules = IPACM_Wan::num_v6_flt_rule;
+
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("WAN DL routing table %s has index %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, rt_tbl_idx.idx);
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ /* Configuring ICMP filtering rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[1].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ /* Multiple PDNs may exist so keep meta-data */
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = (uint8_t)IPACM_FIREWALL_IPPROTO_ICMP6;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACM_Wan::num_v6_flt_rule++;
+
+ num_rules = IPACM_Wan::num_v6_flt_rule - original_num_rules;
+ }
+
+fail:
+ IPACMDBG_H("Constructed %d ICMP/ALG rules for ip type %d\n", num_rules, iptype);
+ return res;
+}
+
+int IPACM_Wan::query_ext_prop()
+{
+ int fd, ret = IPACM_SUCCESS;
+ uint32_t cnt;
+
+ if (iface_query->num_ext_props > 0)
+ {
+ fd = open(IPA_DEVICE_NAME, O_RDWR);
+ IPACMDBG_H("iface query-property \n");
+ if (0 == fd)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+
+ ext_prop = (struct ipa_ioc_query_intf_ext_props *)
+ calloc(1, sizeof(struct ipa_ioc_query_intf_ext_props) +
+ iface_query->num_ext_props * sizeof(struct ipa_ioc_ext_intf_prop));
+ if(ext_prop == NULL)
+ {
+ IPACMERR("Unable to allocate memory.\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(ext_prop->name, dev_name,
+ sizeof(dev_name));
+ ext_prop->num_ext_props = iface_query->num_ext_props;
+
+ IPACMDBG_H("Query extended property for iface %s\n", ext_prop->name);
+
+ ret = ioctl(fd, IPA_IOC_QUERY_INTF_EXT_PROPS, ext_prop);
+ if (ret < 0)
+ {
+ IPACMERR("ioctl IPA_IOC_QUERY_INTF_EXT_PROPS failed\n");
+ /* ext_prop memory will free when iface-down*/
+ free(ext_prop);
+ close(fd);
+ return ret;
+ }
+
+ IPACMDBG_H("Wan interface has %d tx props, %d rx props and %d ext props\n",
+ iface_query->num_tx_props, iface_query->num_rx_props, iface_query->num_ext_props);
+
+ for (cnt = 0; cnt < ext_prop->num_ext_props; cnt++)
+ {
+#ifndef FEATURE_IPA_V3
+ IPACMDBG_H("Ex(%d): ip-type: %d, mux_id: %d, flt_action: %d\n, rt_tbl_idx: %d, is_xlat_rule: %d flt_hdl: %d\n",
+ cnt, ext_prop->ext[cnt].ip, ext_prop->ext[cnt].mux_id, ext_prop->ext[cnt].action,
+ ext_prop->ext[cnt].rt_tbl_idx, ext_prop->ext[cnt].is_xlat_rule, ext_prop->ext[cnt].filter_hdl);
+#else /* defined (FEATURE_IPA_V3) */
+ IPACMDBG_H("Ex(%d): ip-type: %d, mux_id: %d, flt_action: %d\n, rt_tbl_idx: %d, is_xlat_rule: %d rule_id: %d\n",
+ cnt, ext_prop->ext[cnt].ip, ext_prop->ext[cnt].mux_id, ext_prop->ext[cnt].action,
+ ext_prop->ext[cnt].rt_tbl_idx, ext_prop->ext[cnt].is_xlat_rule, ext_prop->ext[cnt].rule_id);
+#endif
+ }
+
+ if(IPACM_Wan::is_ext_prop_set == false)
+ {
+ IPACM_Iface::ipacmcfg->SetExtProp(ext_prop);
+ IPACM_Wan::is_ext_prop_set = true;
+ }
+ close(fd);
+ }
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Wan::config_wan_firewall_rule(ipa_ip_type iptype)
+{
+ int res = IPACM_SUCCESS;
+
+ IPACMDBG_H("Configure WAN DL firewall rules.\n");
+
+ if(iptype == IPA_IP_v4)
+ {
+ IPACM_Wan::num_v4_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
+ if(IPACM_FAILURE == add_icmp_alg_rules(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4))
+ {
+ IPACMERR("Failed to add ICMP and ALG port filtering rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMDBG_H("Succeded in constructing ICMP/ALG rules for ip type %d\n", iptype);
+
+ if(IPACM_FAILURE == config_dft_firewall_rules_ex(flt_rule_v4, IPACM_Wan::num_v4_flt_rule, IPA_IP_v4))
+ {
+ IPACMERR("Failed to add firewall filtering rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMDBG_H("Succeded in constructing firewall rules for ip type %d\n", iptype);
+ }
+ else if(iptype == IPA_IP_v6)
+ {
+#ifdef FEATURE_IPA_ANDROID
+ add_tcpv6_filtering_rule(flt_rule_v6, IPACM_Wan::num_v6_flt_rule);
+#endif
+ IPACM_Wan::num_v6_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6;
+ if(IPACM_FAILURE == add_icmp_alg_rules(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6))
+ {
+ IPACMERR("Failed to add ICMP and ALG port filtering rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMDBG_H("Succeded in constructing ICMP/ALG rules for ip type %d\n", iptype);
+
+ if(IPACM_FAILURE == config_dft_firewall_rules_ex(flt_rule_v6, IPACM_Wan::num_v6_flt_rule, IPA_IP_v6))
+ {
+ IPACMERR("Failed to add firewall filtering rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMDBG_H("Succeded in constructing firewall rules for ip type %d\n", iptype);
+ }
+ else
+ {
+ IPACMERR("IP type is not expected.\n");
+ return IPACM_FAILURE;
+ }
+
+fail:
+ return res;
+}
+
+int IPACM_Wan::add_dft_filtering_rule(struct ipa_flt_rule_add *rules, int rule_offset, ipa_ip_type iptype)
+{
+ struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+ struct ipa_flt_rule_add flt_rule_entry;
+ struct ipa_ioc_generate_flt_eq flt_eq;
+ int res = IPACM_SUCCESS;
+
+ if(rules == NULL)
+ {
+ IPACMERR("No filtering table available.\n");
+ return IPACM_FAILURE;
+ }
+ if(rx_prop == NULL)
+ {
+ IPACMERR("No tx property.\n");
+ return IPACM_FAILURE;
+ }
+
+ if (iptype == IPA_IP_v4)
+ {
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ IPACMDBG_H("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+
+ /* Configuring Multicast Filtering Rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ /* remove meta data mask since we only install default flt rules once for all modem PDN*/
+ flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xF0000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000;
+
+ change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring Broadcast Filtering Rule */
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF;
+
+ change_to_network_order(IPA_IP_v4, &flt_rule_entry.rule.attrib);
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(rules[rule_offset + 1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACM_Wan::num_v4_flt_rule += IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
+ IPACMDBG_H("Constructed %d default filtering rules for ip type %d\n", IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4, iptype);
+ }
+ else /*insert rules for ipv6*/
+ {
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ /* Configuring Multicast Filtering Rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ /* remove meta data mask since we only install default flt rules once for all modem PDN*/
+ flt_rule_entry.rule.attrib.attrib_mask &= ~((uint32_t)IPA_FLT_META_DATA);
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFF000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFF000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
+
+ change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring fe80::/10 Link-Scoped Unicast Filtering Rule */
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFC00000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFE800000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
+
+ change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[rule_offset + 1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring fec0::/10 Reserved by IETF Filtering Rule */
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFFC00000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0xFEC00000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0x00000000;
+
+ change_to_network_order(IPA_IP_v6, &flt_rule_entry.rule.attrib);
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = iptype;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(rules[rule_offset + 2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACM_Wan::num_v6_flt_rule += IPA_V2_NUM_MULTICAST_WAN_FILTER_RULE_IPV6;
+ IPACMDBG_H("Constructed %d default filtering rules for ip type %d\n", IPA_V2_NUM_MULTICAST_WAN_FILTER_RULE_IPV6, iptype);
+ }
+
+fail:
+ return res;
+}
+
+int IPACM_Wan::add_tcpv6_filtering_rule(struct ipa_flt_rule_add *rules, int rule_offset)
+{
+ struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+ struct ipa_flt_rule_add flt_rule_entry;
+ struct ipa_ioc_generate_flt_eq flt_eq;
+ int res = IPACM_SUCCESS;
+
+ if(rules == NULL)
+ {
+ IPACMERR("No filtering table available.\n");
+ return IPACM_FAILURE;
+ }
+ if(rx_prop == NULL)
+ {
+ IPACMERR("No tx property.\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = IPA_IP_v6;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.retain_hdr = 1;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ IPACMDBG_H("Add TCP ctrl rules: total num %d\n", IPA_V2_NUM_TCP_WAN_FILTER_RULE_IPV6);
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = IPA_IP_v6;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<1);
+ flt_rule_entry.rule.eq_attrib.protocol_eq_present = 1;
+ flt_rule_entry.rule.eq_attrib.protocol_eq = IPACM_FIREWALL_IPPROTO_TCP;
+
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<7);
+#else
+ flt_rule_entry.rule.eq_attrib.rule_eq_bitmap |= (1<<8);
+#endif
+ flt_rule_entry.rule.eq_attrib.num_ihl_offset_meq_32 = 1;
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].offset = 12;
+
+ /* add TCP FIN rule*/
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_FIN_SHIFT);
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_FIN_SHIFT);
+ memcpy(&(rules[rule_offset]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* add TCP SYN rule*/
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_SYN_SHIFT);
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_SYN_SHIFT);
+ memcpy(&(rules[rule_offset + 1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* add TCP RST rule*/
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].value = (((uint32_t)1)<<TCP_RST_SHIFT);
+ flt_rule_entry.rule.eq_attrib.ihl_offset_meq_32[0].mask = (((uint32_t)1)<<TCP_RST_SHIFT);
+ memcpy(&(rules[rule_offset + 2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACM_Wan::num_v6_flt_rule += IPA_V2_NUM_TCP_WAN_FILTER_RULE_IPV6;
+ IPACMDBG_H("Constructed %d ICMP filtering rules for ip type %d\n", IPA_V2_NUM_TCP_WAN_FILTER_RULE_IPV6, IPA_IP_v6);
+
+fail:
+ return res;
+}
+
+int IPACM_Wan::del_wan_firewall_rule(ipa_ip_type iptype)
+{
+ if(iptype == IPA_IP_v4)
+ {
+ IPACM_Wan::num_v4_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4;
+ memset(&IPACM_Wan::flt_rule_v4[IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4], 0,
+ (IPA_MAX_FLT_RULE - IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV4) * sizeof(struct ipa_flt_rule_add));
+ }
+ else if(iptype == IPA_IP_v6)
+ {
+ IPACM_Wan::num_v6_flt_rule = IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6;
+ memset(&IPACM_Wan::flt_rule_v6[IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6], 0,
+ (IPA_MAX_FLT_RULE - IPA_V2_NUM_DEFAULT_WAN_FILTER_RULE_IPV6) * sizeof(struct ipa_flt_rule_add));
+ }
+ else
+ {
+ IPACMERR("IP type is not expected.\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*for STA mode: clean firewall filter rules */
+int IPACM_Wan::del_dft_firewall_rules(ipa_ip_type iptype)
+{
+ /* free v4 firewall filter rule */
+ if (rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ if ((iptype == IPA_IP_v4) && (active_v4 == true))
+ {
+ if (num_firewall_v4 > IPACM_MAX_FIREWALL_ENTRIES)
+ {
+ IPACMERR("the number of v4 firewall entries overflow, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ if (num_firewall_v4 != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(firewall_hdl_v4,
+ IPA_IP_v4, num_firewall_v4) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_firewall_v4);
+ }
+ else
+ {
+ IPACMDBG_H("No ipv4 firewall rules, no need deleted\n");
+ }
+
+ if (m_filtering.DeleteFilteringHdls(dft_wan_fl_hdl,
+ IPA_IP_v4, 1) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, 1);
+
+ num_firewall_v4 = 0;
+ }
+
+ /* free v6 firewall filter rule */
+ if ((iptype == IPA_IP_v6) && (active_v6 == true))
+ {
+ if (num_firewall_v6 > IPACM_MAX_FIREWALL_ENTRIES)
+ {
+ IPACMERR("the number of v6 firewall entries overflow, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ if (num_firewall_v6 != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(firewall_hdl_v6,
+ IPA_IP_v6, num_firewall_v6) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_firewall_v6);
+ }
+ else
+ {
+ IPACMDBG_H("No ipv6 firewall rules, no need deleted\n");
+ }
+
+ if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[1],
+ IPA_IP_v6, 1) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[2],
+ IPA_IP_v6, 1) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+
+ if (is_ipv6_frag_firewall_flt_rule_installed &&
+ check_dft_firewall_rules_attr_mask(&firewall_config))
+ {
+ if (m_filtering.DeleteFilteringHdls(&ipv6_frag_firewall_flt_rule_hdl, IPA_IP_v6, 1) == false)
+ {
+ IPACMERR("Error deleting IPv6 frag filtering rules.\n");
+ return IPACM_FAILURE;
+ }
+ is_ipv6_frag_firewall_flt_rule_installed = false;
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, 1);
+ }
+ num_firewall_v6 = 0;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* for STA mode: wan default route/filter rule delete */
+int IPACM_Wan::handle_route_del_evt(ipa_ip_type iptype)
+{
+ uint32_t tx_index;
+ ipacm_cmd_q_data evt_data;
+
+ IPACMDBG_H("got handle_route_del_evt for STA-mode with ip-family:%d \n", iptype);
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No tx properties, ignore delete default route setting\n");
+ return IPACM_SUCCESS;
+ }
+
+ is_default_gateway = false;
+ IPACMDBG_H("Default route is deleted to iface %s.\n", dev_name);
+
+ if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
+ ((iptype == IPA_IP_v6) && (active_v6 == true)))
+ {
+
+ /* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if(iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d, no RT-rule deleted\n",
+ tx_index, tx_prop->tx[tx_index].ip,iptype);
+ continue;
+ }
+
+ if (iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n", tx_index, tx_prop->tx[tx_index].ip,iptype);
+
+ if (m_routing.DeleteRoutingHdl(wan_route_rule_v4_hdl[tx_index], IPA_IP_v4) == false)
+ {
+ IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v4, wan_route_rule_v4_hdl[tx_index], tx_index);
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d match ip-type: %d, RT-rule deleted\n", tx_index, tx_prop->tx[tx_index].ip,iptype);
+
+ if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl[tx_index], IPA_IP_v6) == false)
+ {
+ IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v6, wan_route_rule_v6_hdl[tx_index], tx_index);
+ return IPACM_FAILURE;
+ }
+ }
+ }
+
+ /* Delete the default wan route*/
+ if (iptype == IPA_IP_v6)
+ {
+ IPACMDBG_H("ip-type %d: default v6 wan RT-rule deleted\n",iptype);
+ if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl_a5[0], IPA_IP_v6) == false)
+ {
+ IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed!\n",IPA_IP_v6,wan_route_rule_v6_hdl_a5[0]);
+ return IPACM_FAILURE;
+ }
+ }
+ ipacm_event_iface_up *wandown_data;
+ wandown_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+ if (wandown_data == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return IPACM_FAILURE;
+ }
+ memset(wandown_data, 0, sizeof(ipacm_event_iface_up));
+
+ if (iptype == IPA_IP_v4)
+ {
+ wandown_data->ipv4_addr = wan_v4_addr;
+ if (m_is_sta_mode!=Q6_WAN)
+ {
+ wandown_data->is_sta = true;
+ }
+ else
+ {
+ wandown_data->is_sta = false;
+ }
+ evt_data.event = IPA_HANDLE_WAN_DOWN;
+ evt_data.evt_data = (void *)wandown_data;
+ /* Insert IPA_HANDLE_WAN_DOWN to command queue */
+ IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN for IPv4 (%d.%d.%d.%d) \n",
+ (unsigned char)(wandown_data->ipv4_addr),
+ (unsigned char)(wandown_data->ipv4_addr >> 8),
+ (unsigned char)(wandown_data->ipv4_addr >> 16),
+ (unsigned char)(wandown_data->ipv4_addr >> 24));
+
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG_H("setup wan_up/active_v4= false \n");
+ IPACM_Wan::wan_up = false;
+ active_v4 = false;
+ if(IPACM_Wan::wan_up_v6)
+ {
+ IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+ }
+ else
+ {
+ memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+ }
+ }
+ else
+ {
+ if (m_is_sta_mode!=Q6_WAN)
+ {
+ wandown_data->is_sta = true;
+ }
+ else
+ {
+ wandown_data->is_sta = false;
+ }
+ memcpy(wandown_data->ipv6_prefix, ipv6_prefix, sizeof(wandown_data->ipv6_prefix));
+ evt_data.event = IPA_HANDLE_WAN_DOWN_V6;
+ evt_data.evt_data = (void *)wandown_data;
+ /* Insert IPA_HANDLE_WAN_DOWN to command queue */
+ IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN for IPv6 with prefix 0x%08x%08x\n", ipv6_prefix[0], ipv6_prefix[1]);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG_H("setup wan_up_v6/active_v6= false \n");
+ IPACM_Wan::wan_up_v6 = false;
+ active_v6 = false;
+ if(IPACM_Wan::wan_up)
+ {
+ IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+ }
+ else
+ {
+ memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+ }
+ }
+ }
+ else
+ {
+ IPACMDBG_H(" The default WAN routing rules are deleted already \n");
+ }
+
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Wan::handle_route_del_evt_ex(ipa_ip_type iptype)
+{
+ ipacm_cmd_q_data evt_data;
+
+ IPACMDBG_H("got handle_route_del_evt_ex with ip-family:%d \n", iptype);
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No tx properties, ignore delete default route setting\n");
+ return IPACM_SUCCESS;
+ }
+
+ is_default_gateway = false;
+ IPACMDBG_H("Default route is deleted to iface %s.\n", dev_name);
+
+ if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
+ ((iptype == IPA_IP_v6) && (active_v6 == true)))
+ {
+
+ /* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+
+ /* Delete the default route*/
+ if (iptype == IPA_IP_v6)
+ {
+ IPACMDBG_H("ip-type %d: default v6 wan RT-rule deleted\n",iptype);
+ if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl_a5[0], IPA_IP_v6) == false)
+ {
+ IPACMDBG_H("IP-family:%d, Routing rule(hdl:0x%x) deletion failed!\n",IPA_IP_v6,wan_route_rule_v6_hdl_a5[0]);
+ return IPACM_FAILURE;
+ }
+ }
+
+ ipacm_event_iface_up *wandown_data;
+ wandown_data = (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+ if (wandown_data == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return IPACM_FAILURE;
+ }
+ memset(wandown_data, 0, sizeof(ipacm_event_iface_up));
+
+ if (iptype == IPA_IP_v4)
+ {
+ wandown_data->ipv4_addr = wan_v4_addr;
+ if (m_is_sta_mode!=Q6_WAN)
+ {
+ wandown_data->is_sta = true;
+ }
+ else
+ {
+ wandown_data->is_sta = false;
+ }
+ evt_data.event = IPA_HANDLE_WAN_DOWN;
+ evt_data.evt_data = (void *)wandown_data;
+ /* Insert IPA_HANDLE_WAN_DOWN to command queue */
+ IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN for IPv4 with address: 0x%x\n", wan_v4_addr);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+ IPACMDBG_H("setup wan_up/active_v4= false \n");
+ IPACM_Wan::wan_up = false;
+ active_v4 = false;
+ if(IPACM_Wan::wan_up_v6)
+ {
+ IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+ }
+ else
+ {
+ memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+ }
+ }
+ else
+ {
+ if (m_is_sta_mode!=Q6_WAN)
+ {
+ wandown_data->is_sta = true;
+ }
+ else
+ {
+ wandown_data->is_sta = false;
+ }
+ memcpy(wandown_data->ipv6_prefix, ipv6_prefix, sizeof(wandown_data->ipv6_prefix));
+ evt_data.event = IPA_HANDLE_WAN_DOWN_V6;
+ evt_data.evt_data = (void *)wandown_data;
+ IPACMDBG_H("posting IPA_HANDLE_WAN_DOWN_V6 for IPv6 with prefix 0x%08x%08x\n", ipv6_prefix[0], ipv6_prefix[1]);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+ IPACMDBG_H("setup wan_up_v6/active_v6= false \n");
+ IPACM_Wan::wan_up_v6 = false;
+ active_v6 = false;
+ if(IPACM_Wan::wan_up)
+ {
+ IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+ }
+ else
+ {
+ memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+ }
+ }
+ }
+ else
+ {
+ IPACMDBG_H(" The default WAN routing rules are deleted already \n");
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* configure the initial embms filter rules */
+int IPACM_Wan::config_dft_embms_rules(ipa_ioc_add_flt_rule *pFilteringTable_v4, ipa_ioc_add_flt_rule *pFilteringTable_v6)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+ struct ipa_ioc_generate_flt_eq flt_eq;
+
+ if (rx_prop == NULL)
+ {
+ IPACMDBG("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ if(pFilteringTable_v4 == NULL || pFilteringTable_v6 == NULL)
+ {
+ IPACMERR("Either v4 or v6 filtering table is empty.\n");
+ return IPACM_FAILURE;
+ }
+
+ /* set up ipv4 odu rule*/
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ /* get eMBMS ODU tbl index*/
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v4.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = IPA_IP_v4;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("Odu routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.at_rear = false;
+
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = IPA_IP_v4;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(pFilteringTable_v4->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* construc v6 rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ /* get eMBMS ODU tbl*/
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_odu_v6.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = IPA_IP_v6;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx))
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("Odu routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.at_rear = false;
+
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = IPA_IP_v6;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+
+ memcpy(&(pFilteringTable_v6->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ return IPACM_SUCCESS;
+}
+
+
+/*for STA mode: handle wan-iface down event */
+int IPACM_Wan::handle_down_evt()
+{
+ int res = IPACM_SUCCESS;
+ uint32_t i;
+
+ IPACMDBG_H(" wan handle_down_evt \n");
+
+ /* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ if (tx_prop != NULL)
+ {
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ }
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ goto fail;
+ }
+
+ /* make sure default routing rules and firewall rules are deleted*/
+ if (active_v4)
+ {
+ if (rx_prop != NULL)
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ }
+ handle_route_del_evt(IPA_IP_v4);
+ IPACMDBG_H("Delete default v4 routing rules\n");
+ }
+
+ if (active_v6)
+ {
+ if (rx_prop != NULL)
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ }
+ handle_route_del_evt(IPA_IP_v6);
+ IPACMDBG_H("Delete default v6 routing rules\n");
+ }
+
+ /* Delete default v4 RT rule */
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG_H("Delete default v4 routing rules\n");
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* delete default v6 RT rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ IPACMDBG_H("Delete default v6 routing rules\n");
+ /* May have multiple ipv6 iface-routing rules*/
+ for (i = 0; i < 2*num_dft_rt_v6; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ IPACMDBG_H("finished delete default v6 RT rules\n ");
+ }
+
+
+ /* clean wan-client header, routing rules */
+ IPACMDBG_H("left %d wan clients need to be deleted \n ", num_wan_client);
+ for (i = 0; i < num_wan_client; i++)
+ {
+ /* Del NAT rules before ipv4 RT rules are delete */
+ if(get_client_memptr(wan_client, i)->ipv4_set == true)
+ {
+ IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wan_client, i)->v4_addr);
+ CtList->HandleSTAClientDelEvt(get_client_memptr(wan_client, i)->v4_addr);
+ }
+
+ if (delete_wan_rtrules(i, IPA_IP_v4))
+ {
+ IPACMERR("unbale to delete wan-client v4 route rules for index %d\n", i);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ if (delete_wan_rtrules(i, IPA_IP_v6))
+ {
+ IPACMERR("unbale to delete ecm-client v6 route rules for index %d\n", i);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("Delete %d client header\n", num_wan_client);
+
+
+ if(get_client_memptr(wan_client, i)->ipv4_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wan_client, i)->hdr_hdl_v4)
+ == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ if(get_client_memptr(wan_client, i)->ipv6_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wan_client, i)->hdr_hdl_v6)
+ == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ } /* end of for loop */
+
+ /* free the edm clients cache */
+ IPACMDBG_H("Free wan clients cache\n");
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true)
+ {
+ handle_software_routing_disable();
+ }
+
+ /* free dft ipv4 filter rule handlers if any */
+ if (ip_type != IPA_IP_v6 && rx_prop != NULL)
+ {
+ if (dft_v4fl_rule_hdl[0] != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+ IPA_IP_v4,
+ IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Delete Filtering rules, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
+ IPACMDBG_H("finished delete default v4 filtering rules\n ");
+ }
+ }
+
+ /* free dft ipv6 filter rule handlers if any */
+ if (ip_type != IPA_IP_v4 && rx_prop != NULL)
+ {
+ if (dft_v6fl_rule_hdl[0] != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+ IPA_IP_v6,
+ IPV6_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("ErrorDeleting Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
+ }
+
+ if(num_ipv6_dest_flt_rule > 0 && num_ipv6_dest_flt_rule <= MAX_DEFAULT_v6_ROUTE_RULES)
+ {
+ if(m_filtering.DeleteFilteringHdls(ipv6_dest_flt_rule_hdl, IPA_IP_v6, num_ipv6_dest_flt_rule) == false)
+ {
+ IPACMERR("Failed to delete ipv6 dest flt rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, num_ipv6_dest_flt_rule);
+ }
+ IPACMDBG_H("finished delete default v6 filtering rules\n ");
+ }
+ if(hdr_proc_hdl_dummy_v6)
+ {
+ if(m_header.DeleteHeaderProcCtx(hdr_proc_hdl_dummy_v6) == false)
+ {
+ IPACMERR("Failed to delete hdr_proc_hdl_dummy_v6\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ if(hdr_hdl_dummy_v6)
+ {
+ if (m_header.DeleteHeaderHdl(hdr_hdl_dummy_v6) == false)
+ {
+ IPACMERR("Failed to delete hdr_hdl_dummy_v6\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+fail:
+ if (tx_prop != NULL)
+ {
+ free(tx_prop);
+ }
+ if (rx_prop != NULL)
+ {
+ free(rx_prop);
+ }
+ if (iface_query != NULL)
+ {
+ free(iface_query);
+ }
+ if (wan_route_rule_v4_hdl != NULL)
+ {
+ free(wan_route_rule_v4_hdl);
+ }
+ if (wan_route_rule_v6_hdl != NULL)
+ {
+ free(wan_route_rule_v6_hdl);
+ }
+ if (wan_route_rule_v6_hdl_a5 != NULL)
+ {
+ free(wan_route_rule_v6_hdl_a5);
+ }
+ if (wan_client != NULL)
+ {
+ free(wan_client);
+ }
+ close(m_fd_ipa);
+ return res;
+}
+
+int IPACM_Wan::handle_down_evt_ex()
+{
+ int res = IPACM_SUCCESS;
+ uint32_t i, tether_total;
+ int ipa_if_num_tether_tmp[IPA_MAX_IFACE_ENTRIES];
+
+ IPACMDBG_H(" wan handle_down_evt \n");
+
+ /* free ODU filter rule handlers */
+ if(IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat == EMBMS_IF)
+ {
+ embms_is_on = false;
+ /* Delete corresponding ipa_rm_resource_name of TX-endpoint after delete IPV4/V6 RT-rule */
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ if (tx_prop != NULL)
+ {
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ }
+
+ if (rx_prop != NULL)
+ {
+ install_wan_filtering_rule(false);
+ IPACMDBG("finished delete embms filtering rule\n ");
+ }
+ goto fail;
+ }
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ goto fail;
+ }
+
+ if(ip_type == IPA_IP_v4)
+ {
+ num_ipv4_modem_pdn--;
+ IPACMDBG_H("Now the number of ipv4 modem pdn is %d.\n", num_ipv4_modem_pdn);
+ /* only when default gw goes down we post WAN_DOWN event*/
+ if(is_default_gateway == true)
+ {
+ IPACM_Wan::wan_up = false;
+ del_wan_firewall_rule(IPA_IP_v4);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v4);
+#ifdef FEATURE_IPA_ANDROID
+ /* posting wan_down_tether for all lan clients */
+ for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
+ {
+ ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v4[i];
+ }
+ tether_total = IPACM_Wan::ipa_if_num_tether_v4_total;
+ for (i=0; i < tether_total; i++)
+ {
+ post_wan_down_tether_evt(IPA_IP_v4, ipa_if_num_tether_tmp[i]);
+ IPACMDBG_H("post_wan_down_tether_v4 iface(%d: %s)\n",
+ i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
+ }
+#endif
+ if(IPACM_Wan::wan_up_v6)
+ {
+ IPACMDBG_H("modem v6-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+ }
+ else
+ {
+ memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+ }
+ }
+
+ /* only when the last ipv4 modem interface goes down, delete ipv4 default flt rules*/
+ if(num_ipv4_modem_pdn == 0)
+ {
+ IPACMDBG_H("Now the number of modem ipv4 interface is 0, delete default flt rules.\n");
+ IPACM_Wan::num_v4_flt_rule = 0;
+ memset(IPACM_Wan::flt_rule_v4, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
+ install_wan_filtering_rule(false);
+ }
+
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ else if(ip_type == IPA_IP_v6)
+ {
+ if (num_dft_rt_v6 > 1)
+ num_ipv6_modem_pdn--;
+ IPACMDBG_H("Now the number of ipv6 modem pdn is %d.\n", num_ipv6_modem_pdn);
+ /* only when default gw goes down we post WAN_DOWN event*/
+ if(is_default_gateway == true)
+ {
+ IPACM_Wan::wan_up_v6 = false;
+ del_wan_firewall_rule(IPA_IP_v6);
+ install_wan_filtering_rule(false);
+ handle_route_del_evt_ex(IPA_IP_v6);
+#ifdef FEATURE_IPA_ANDROID
+ /* posting wan_down_tether for all lan clients */
+ for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
+ {
+ ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v6[i];
+ }
+ tether_total = IPACM_Wan::ipa_if_num_tether_v6_total;
+ for (i=0; i < tether_total; i++)
+ {
+ post_wan_down_tether_evt(IPA_IP_v6, ipa_if_num_tether_tmp[i]);
+ IPACMDBG_H("post_wan_down_tether_v6 iface(%d: %s)\n",
+ i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
+ }
+#endif
+ if(IPACM_Wan::wan_up)
+ {
+ IPACMDBG_H("modem v4-call still up(%s), not reset\n", IPACM_Wan::wan_up_dev_name);
+ }
+ else
+ {
+ memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+ }
+ }
+
+ /* only when the last ipv6 modem interface goes down, delete ipv6 default flt rules*/
+ if(num_ipv6_modem_pdn == 0)
+ {
+ IPACMDBG_H("Now the number of modem ipv6 interface is 0, delete default flt rules.\n");
+ IPACM_Wan::num_v6_flt_rule = 0;
+ memset(IPACM_Wan::flt_rule_v6, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
+ install_wan_filtering_rule(false);
+ }
+
+ for (i = 0; i < 2*num_dft_rt_v6; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+ else
+ {
+ num_ipv4_modem_pdn--;
+ IPACMDBG_H("Now the number of ipv4 modem pdn is %d.\n", num_ipv4_modem_pdn);
+ if (num_dft_rt_v6 > 1)
+ num_ipv6_modem_pdn--;
+ IPACMDBG_H("Now the number of ipv6 modem pdn is %d.\n", num_ipv6_modem_pdn);
+ /* only when default gw goes down we post WAN_DOWN event*/
+ if(is_default_gateway == true)
+ {
+ IPACM_Wan::wan_up = false;
+ del_wan_firewall_rule(IPA_IP_v4);
+ handle_route_del_evt_ex(IPA_IP_v4);
+#ifdef FEATURE_IPA_ANDROID
+ /* posting wan_down_tether for all lan clients */
+ for (i=0; i < IPACM_Wan::ipa_if_num_tether_v4_total; i++)
+ {
+ ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v4[i];
+ }
+ tether_total = IPACM_Wan::ipa_if_num_tether_v4_total;
+ for (i=0; i < tether_total; i++)
+ {
+ post_wan_down_tether_evt(IPA_IP_v4, ipa_if_num_tether_tmp[i]);
+ IPACMDBG_H("post_wan_down_tether_v4 iface(%d: %s)\n",
+ i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
+ }
+#endif
+ IPACM_Wan::wan_up_v6 = false;
+ del_wan_firewall_rule(IPA_IP_v6);
+ handle_route_del_evt_ex(IPA_IP_v6);
+#ifdef FEATURE_IPA_ANDROID
+ /* posting wan_down_tether for all lan clients */
+ for (i=0; i < IPACM_Wan::ipa_if_num_tether_v6_total; i++)
+ {
+ ipa_if_num_tether_tmp[i] = IPACM_Wan::ipa_if_num_tether_v6[i];
+ }
+ tether_total = IPACM_Wan::ipa_if_num_tether_v6_total;
+ for (i=0; i < tether_total; i++)
+ {
+ post_wan_down_tether_evt(IPA_IP_v6, ipa_if_num_tether_tmp[i]);
+ IPACMDBG_H("post_wan_down_tether_v6 iface(%d: %s)\n",
+ i, IPACM_Iface::ipacmcfg->iface_table[ipa_if_num_tether_tmp[i]].iface_name);
+ }
+#endif
+ memset(IPACM_Wan::wan_up_dev_name, 0, sizeof(IPACM_Wan::wan_up_dev_name));
+
+ install_wan_filtering_rule(false);
+ }
+
+ /* only when the last ipv4 modem interface goes down, delete ipv4 default flt rules*/
+ if(num_ipv4_modem_pdn == 0)
+ {
+ IPACMDBG_H("Now the number of modem ipv4 interface is 0, delete default flt rules.\n");
+ IPACM_Wan::num_v4_flt_rule = 0;
+ memset(IPACM_Wan::flt_rule_v4, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
+ install_wan_filtering_rule(false);
+ }
+ /* only when the last ipv6 modem interface goes down, delete ipv6 default flt rules*/
+ if(num_ipv6_modem_pdn == 0)
+ {
+ IPACMDBG_H("Now the number of modem ipv6 interface is 0, delete default flt rules.\n");
+ IPACM_Wan::num_v6_flt_rule = 0;
+ memset(IPACM_Wan::flt_rule_v6, 0, IPA_MAX_FLT_RULE * sizeof(struct ipa_flt_rule_add));
+ install_wan_filtering_rule(false);
+ }
+
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ for (i = 0; i < 2*num_dft_rt_v6; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true)
+ {
+ handle_software_routing_disable();
+ }
+
+fail:
+ if (tx_prop != NULL)
+ {
+ free(tx_prop);
+ }
+ if (rx_prop != NULL)
+ {
+ free(rx_prop);
+ }
+ if (ext_prop != NULL)
+ {
+ free(ext_prop);
+ }
+ if (iface_query != NULL)
+ {
+ free(iface_query);
+ }
+ if (wan_route_rule_v4_hdl != NULL)
+ {
+ free(wan_route_rule_v4_hdl);
+ }
+ if (wan_route_rule_v6_hdl != NULL)
+ {
+ free(wan_route_rule_v6_hdl);
+ }
+ if (wan_route_rule_v6_hdl_a5 != NULL)
+ {
+ free(wan_route_rule_v6_hdl_a5);
+ }
+ if (wan_client != NULL)
+ {
+ free(wan_client);
+ }
+ close(m_fd_ipa);
+ return res;
+}
+
+int IPACM_Wan::install_wan_filtering_rule(bool is_sw_routing)
+{
+ int len, res = IPACM_SUCCESS;
+ uint8_t mux_id;
+ ipa_ioc_add_flt_rule *pFilteringTable_v4 = NULL;
+ ipa_ioc_add_flt_rule *pFilteringTable_v6 = NULL;
+
+ mux_id = IPACM_Iface::ipacmcfg->GetQmapId();
+ if(rx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+ if (is_sw_routing == true ||
+ IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true)
+ {
+ /* contruct SW-RT rules to Q6*/
+ struct ipa_flt_rule_add flt_rule_entry;
+ struct ipa_ioc_get_rt_tbl_indx rt_tbl_idx;
+ ipa_ioc_generate_flt_eq flt_eq;
+
+ IPACMDBG("\n");
+ if (softwarerouting_act == true)
+ {
+ IPACMDBG("already setup software_routing rule for (%s)iface ip-family %d\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ip_type);
+ return IPACM_SUCCESS;
+ }
+
+ len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+ pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+ if (pFilteringTable_v4 == NULL)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable_v4, 0, len);
+ IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is 1\n");
+
+ pFilteringTable_v4->commit = 1;
+ pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable_v4->global = false;
+ pFilteringTable_v4->ip = IPA_IP_v4;
+ pFilteringTable_v4->num_rules = (uint8_t)1;
+
+ /* Configuring Software-Routing Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = IPA_IP_v4;
+ if(ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx) < 0)
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ flt_rule_entry.at_rear = false;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = IPA_IP_v4;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(pFilteringTable_v4->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ len = sizeof(struct ipa_ioc_add_flt_rule) + sizeof(struct ipa_flt_rule_add);
+ pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+ if (pFilteringTable_v6 == NULL)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ free(pFilteringTable_v4);
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable_v6, 0, len);
+ IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is 1\n");
+
+ pFilteringTable_v6->commit = 1;
+ pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable_v6->global = false;
+ pFilteringTable_v6->ip = IPA_IP_v6;
+ pFilteringTable_v6->num_rules = (uint8_t)1;
+
+ /* Configuring Software-Routing Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ memset(&rt_tbl_idx, 0, sizeof(rt_tbl_idx));
+ strlcpy(rt_tbl_idx.name, IPACM_Iface::ipacmcfg->rt_tbl_wan_dl.name, IPA_RESOURCE_NAME_MAX);
+ rt_tbl_idx.name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ rt_tbl_idx.ip = IPA_IP_v6;
+ if(ioctl(m_fd_ipa, IPA_IOC_QUERY_RT_TBL_INDEX, &rt_tbl_idx) < 0)
+ {
+ IPACMERR("Failed to get routing table index from name\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACMDBG_H("Routing table %s has index %d\n", rt_tbl_idx.name, rt_tbl_idx.idx);
+
+ flt_rule_entry.at_rear = false;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+#ifdef FEATURE_IPA_V3
+ flt_rule_entry.rule.hashable = true;
+#endif
+ flt_rule_entry.rule.rt_tbl_idx = rt_tbl_idx.idx;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.retain_hdr = 0;
+ flt_rule_entry.rule.to_uc = 0;
+ flt_rule_entry.rule.eq_attrib_type = 1;
+
+ memset(&flt_eq, 0, sizeof(flt_eq));
+ memcpy(&flt_eq.attrib, &flt_rule_entry.rule.attrib, sizeof(flt_eq.attrib));
+ flt_eq.ip = IPA_IP_v6;
+ if(0 != ioctl(m_fd_ipa, IPA_IOC_GENERATE_FLT_EQ, &flt_eq))
+ {
+ IPACMERR("Failed to get eq_attrib\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ memcpy(&flt_rule_entry.rule.eq_attrib,
+ &flt_eq.eq_attrib,
+ sizeof(flt_rule_entry.rule.eq_attrib));
+ memcpy(&(pFilteringTable_v6->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ softwarerouting_act = true;
+ /* end of contruct SW-RT rules to Q6*/
+ }
+ else
+ {
+ if(embms_is_on == false)
+ {
+ if(IPACM_Wan::num_v4_flt_rule > 0)
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) + IPACM_Wan::num_v4_flt_rule * sizeof(struct ipa_flt_rule_add);
+ pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+
+ IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is %d\n", IPACM_Wan::num_v4_flt_rule);
+
+ if (pFilteringTable_v4 == NULL)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable_v4, 0, len);
+ pFilteringTable_v4->commit = 1;
+ pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable_v4->global = false;
+ pFilteringTable_v4->ip = IPA_IP_v4;
+ pFilteringTable_v4->num_rules = (uint8_t)IPACM_Wan::num_v4_flt_rule;
+
+ memcpy(pFilteringTable_v4->rules, IPACM_Wan::flt_rule_v4, IPACM_Wan::num_v4_flt_rule * sizeof(ipa_flt_rule_add));
+ }
+
+ if(IPACM_Wan::num_v6_flt_rule > 0)
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) + IPACM_Wan::num_v6_flt_rule * sizeof(struct ipa_flt_rule_add);
+ pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+
+ IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is %d\n", IPACM_Wan::num_v6_flt_rule);
+
+ if (pFilteringTable_v6 == NULL)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ free(pFilteringTable_v4);
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable_v6, 0, len);
+ pFilteringTable_v6->commit = 1;
+ pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable_v6->global = false;
+ pFilteringTable_v6->ip = IPA_IP_v6;
+ pFilteringTable_v6->num_rules = (uint8_t)IPACM_Wan::num_v6_flt_rule;
+
+ memcpy(pFilteringTable_v6->rules, IPACM_Wan::flt_rule_v6, IPACM_Wan::num_v6_flt_rule * sizeof(ipa_flt_rule_add));
+ }
+ }
+ else //embms is on, always add 1 embms rule on top of WAN DL flt table
+ {
+ /* allocate ipv4 filtering table */
+ len = sizeof(struct ipa_ioc_add_flt_rule) + (1 + IPACM_Wan::num_v4_flt_rule) * sizeof(struct ipa_flt_rule_add);
+ pFilteringTable_v4 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+ IPACMDBG_H("Total number of WAN DL filtering rule for IPv4 is %d\n", IPACM_Wan::num_v4_flt_rule + 1);
+ if (pFilteringTable_v4 == NULL)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable_v4, 0, len);
+ pFilteringTable_v4->commit = 1;
+ pFilteringTable_v4->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable_v4->global = false;
+ pFilteringTable_v4->ip = IPA_IP_v4;
+ pFilteringTable_v4->num_rules = (uint8_t)IPACM_Wan::num_v4_flt_rule + 1;
+
+ /* allocate ipv6 filtering table */
+ len = sizeof(struct ipa_ioc_add_flt_rule) + (1 + IPACM_Wan::num_v6_flt_rule) * sizeof(struct ipa_flt_rule_add);
+ pFilteringTable_v6 = (struct ipa_ioc_add_flt_rule*)malloc(len);
+ IPACMDBG_H("Total number of WAN DL filtering rule for IPv6 is %d\n", IPACM_Wan::num_v6_flt_rule + 1);
+ if (pFilteringTable_v6 == NULL)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ free(pFilteringTable_v4);
+ return IPACM_FAILURE;
+ }
+ memset(pFilteringTable_v6, 0, len);
+ pFilteringTable_v6->commit = 1;
+ pFilteringTable_v6->ep = rx_prop->rx[0].src_pipe;
+ pFilteringTable_v6->global = false;
+ pFilteringTable_v6->ip = IPA_IP_v6;
+ pFilteringTable_v6->num_rules = (uint8_t)IPACM_Wan::num_v6_flt_rule + 1;
+
+ config_dft_embms_rules(pFilteringTable_v4, pFilteringTable_v6);
+ if(IPACM_Wan::num_v4_flt_rule > 0)
+ {
+ memcpy(&(pFilteringTable_v4->rules[1]), IPACM_Wan::flt_rule_v4, IPACM_Wan::num_v4_flt_rule * sizeof(ipa_flt_rule_add));
+ }
+
+ if(IPACM_Wan::num_v6_flt_rule > 0)
+ {
+ memcpy(&(pFilteringTable_v6->rules[1]), IPACM_Wan::flt_rule_v6, IPACM_Wan::num_v6_flt_rule * sizeof(ipa_flt_rule_add));
+ }
+ }
+ }
+
+ if(false == m_filtering.AddWanDLFilteringRule(pFilteringTable_v4, pFilteringTable_v6, mux_id))
+ {
+ IPACMERR("Failed to install WAN DL filtering table.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+fail:
+ if(pFilteringTable_v4 != NULL)
+ {
+ free(pFilteringTable_v4);
+ }
+ if(pFilteringTable_v6 != NULL)
+ {
+ free(pFilteringTable_v6);
+ }
+ return res;
+}
+
+void IPACM_Wan::change_to_network_order(ipa_ip_type iptype, ipa_rule_attrib* attrib)
+{
+ if(attrib == NULL)
+ {
+ IPACMERR("Attribute pointer is NULL.\n");
+ return;
+ }
+
+ if(iptype == IPA_IP_v6)
+ {
+ int i;
+ for(i=0; i<4; i++)
+ {
+ attrib->u.v6.src_addr[i] = htonl(attrib->u.v6.src_addr[i]);
+ attrib->u.v6.src_addr_mask[i] = htonl(attrib->u.v6.src_addr_mask[i]);
+ attrib->u.v6.dst_addr[i] = htonl(attrib->u.v6.dst_addr[i]);
+ attrib->u.v6.dst_addr_mask[i] = htonl(attrib->u.v6.dst_addr_mask[i]);
+ }
+ }
+ else
+ {
+ IPACMDBG_H("IP type is not IPv6, do nothing: %d\n", iptype);
+ }
+
+ return;
+}
+
+bool IPACM_Wan::is_global_ipv6_addr(uint32_t* ipv6_addr)
+{
+ if(ipv6_addr == NULL)
+ {
+ IPACMERR("IPv6 address is empty.\n");
+ return false;
+ }
+ IPACMDBG_H("Get ipv6 address with first word 0x%08x.\n", ipv6_addr[0]);
+
+ uint32_t ipv6_link_local_prefix, ipv6_link_local_prefix_mask;
+ ipv6_link_local_prefix = 0xFE800000;
+ ipv6_link_local_prefix_mask = 0xFFC00000;
+ if((ipv6_addr[0] & ipv6_link_local_prefix_mask) == (ipv6_link_local_prefix & ipv6_link_local_prefix_mask))
+ {
+ IPACMDBG_H("This IPv6 address is link local.\n");
+ return false;
+ }
+ else
+ {
+ IPACMDBG_H("This IPv6 address is not link local.\n");
+ return true;
+ }
+}
+
+/* handle STA WAN-client */
+/* handle WAN client initial, construct full headers (tx property) */
+int IPACM_Wan::handle_wan_hdr_init(uint8_t *mac_addr)
+{
+
+#define WAN_IFACE_INDEX_LEN 2
+
+ int res = IPACM_SUCCESS, len = 0;
+ char index[WAN_IFACE_INDEX_LEN];
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+ uint32_t cnt;
+ int clnt_indx;
+
+ clnt_indx = get_wan_client_index(mac_addr);
+
+ if (clnt_indx != IPACM_INVALID_INDEX)
+ {
+ IPACMERR("eth client is found/attached already with index %d \n", clnt_indx);
+ return IPACM_FAILURE;
+ }
+
+ /* add header to IPA */
+ if (num_wan_client >= IPA_MAX_NUM_WAN_CLIENTS)
+ {
+ IPACMERR("Reached maximum number(%d) of eth clients\n", IPA_MAX_NUM_WAN_CLIENTS);
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("WAN client number: %d\n", num_wan_client);
+
+ memcpy(get_client_memptr(wan_client, num_wan_client)->mac,
+ mac_addr,
+ sizeof(get_client_memptr(wan_client, num_wan_client)->mac));
+
+ IPACMDBG_H("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ IPACMDBG_H("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wan_client, num_wan_client)->mac[0],
+ get_client_memptr(wan_client, num_wan_client)->mac[1],
+ get_client_memptr(wan_client, num_wan_client)->mac[2],
+ get_client_memptr(wan_client, num_wan_client)->mac[3],
+ get_client_memptr(wan_client, num_wan_client)->mac[4],
+ get_client_memptr(wan_client, num_wan_client)->mac[5]);
+
+ /* add header to IPA */
+ if(tx_prop != NULL)
+ {
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+
+ /* copy partial header for v4*/
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v4)
+ {
+ IPACMDBG_H("Got partial v4-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr,
+ sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n",
+ sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+
+ /* only copy 6 bytes mac-address */
+ if(sCopyHeader.is_eth2_ofst_valid == false)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[0],
+ mac_addr, IPA_MAC_ADDR_SIZE);
+ }
+ else
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+ mac_addr, IPA_MAC_ADDR_SIZE);
+ }
+
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ snprintf(index,sizeof(index), "%d", ipa_if_num);
+ strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+ pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WAN_PARTIAL_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ snprintf(index,sizeof(index), "%d", header_name_count);
+ if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = 0;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ pHeaderDescriptor->hdr[0].status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
+ IPACMDBG_H("eth-client(%d) v4 full header name:%s header handle:(0x%x)\n",
+ num_wan_client,
+ pHeaderDescriptor->hdr[0].name,
+ get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v4);
+ get_client_memptr(wan_client, num_wan_client)->ipv4_header_set=true;
+
+ break;
+ }
+ }
+
+
+ /* copy partial header for v6*/
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+ {
+
+ IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr,
+ sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ if(sCopyHeader.is_eth2_ofst_valid == false)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[0],
+ mac_addr, IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
+ }
+ else
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[sCopyHeader.eth2_ofst],
+ mac_addr, IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
+ }
+
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ snprintf(index,sizeof(index), "%d", ipa_if_num);
+ strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+ pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WAN_PARTIAL_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ snprintf(index,sizeof(index), "%d", header_name_count);
+ if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = 0;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ pHeaderDescriptor->hdr[0].status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
+ IPACMDBG_H("eth-client(%d) v6 full header name:%s header handle:(0x%x)\n",
+ num_wan_client,
+ pHeaderDescriptor->hdr[0].name,
+ get_client_memptr(wan_client, num_wan_client)->hdr_hdl_v6);
+
+ get_client_memptr(wan_client, num_wan_client)->ipv6_header_set=true;
+
+ break;
+
+ }
+ }
+ /* initialize wifi client*/
+ get_client_memptr(wan_client, num_wan_client)->route_rule_set_v4 = false;
+ get_client_memptr(wan_client, num_wan_client)->route_rule_set_v6 = 0;
+ get_client_memptr(wan_client, num_wan_client)->ipv4_set = false;
+ get_client_memptr(wan_client, num_wan_client)->ipv6_set = 0;
+ num_wan_client++;
+ header_name_count++; //keep increasing header_name_count
+ res = IPACM_SUCCESS;
+ IPACMDBG_H("eth client number: %d\n", num_wan_client);
+ }
+ else
+ {
+ return res;
+ }
+fail:
+ free(pHeaderDescriptor);
+
+ return res;
+}
+
+/*handle eth client */
+int IPACM_Wan::handle_wan_client_ipaddr(ipacm_event_data_all *data)
+{
+ int clnt_indx;
+ int v6_num;
+
+ IPACMDBG_H("number of wan clients: %d\n", num_wan_client);
+ IPACMDBG_H(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->mac_addr[0],
+ data->mac_addr[1],
+ data->mac_addr[2],
+ data->mac_addr[3],
+ data->mac_addr[4],
+ data->mac_addr[5]);
+
+ clnt_indx = get_wan_client_index(data->mac_addr);
+
+ if (clnt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMERR("wan client not found/attached \n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("Ip-type received %d\n", data->iptype);
+ if (data->iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("ipv4 address: 0x%x\n", data->ipv4_addr);
+ if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+ {
+ if (get_client_memptr(wan_client, clnt_indx)->ipv4_set == false)
+ {
+ get_client_memptr(wan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+ get_client_memptr(wan_client, clnt_indx)->ipv4_set = true;
+ /* Add NAT rules after ipv4 RT rules are set */
+ CtList->HandleSTAClientAddEvt(data->ipv4_addr);
+ }
+ else
+ {
+ /* check if client got new IPv4 address*/
+ if(data->ipv4_addr == get_client_memptr(wan_client, clnt_indx)->v4_addr)
+ {
+ IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
+ /* Del NAT rules before ipv4 RT rules are delete */
+ CtList->HandleSTAClientDelEvt(get_client_memptr(wan_client, clnt_indx)->v4_addr);
+ delete_wan_rtrules(clnt_indx,IPA_IP_v4);
+ get_client_memptr(wan_client, clnt_indx)->route_rule_set_v4 = false;
+ get_client_memptr(wan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+ /* Add NAT rules after ipv4 RT rules are set */
+ CtList->HandleSTAClientAddEvt(data->ipv4_addr);
+ }
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Invalid client IPv4 address \n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+ (data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] != 0)) /* check if all 0 not valid ipv6 address */
+ {
+ IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+ if(get_client_memptr(wan_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
+ {
+
+ for(v6_num=0;v6_num < get_client_memptr(wan_client, clnt_indx)->ipv6_set;v6_num++)
+ {
+ if( data->ipv6_addr[0] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][0] &&
+ data->ipv6_addr[1] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][1] &&
+ data->ipv6_addr[2]== get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][2] &&
+ data->ipv6_addr[3] == get_client_memptr(wan_client, clnt_indx)->v6_addr[v6_num][3])
+ {
+ IPACMDBG_H("Already see this ipv6 addr for client:%d\n", clnt_indx);
+ return IPACM_FAILURE; /* not setup the RT rules*/
+ }
+ }
+
+ /* not see this ipv6 before for wifi client*/
+ get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
+ get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][1] = data->ipv6_addr[1];
+ get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][2] = data->ipv6_addr[2];
+ get_client_memptr(wan_client, clnt_indx)->v6_addr[get_client_memptr(wan_client, clnt_indx)->ipv6_set][3] = data->ipv6_addr[3];
+ get_client_memptr(wan_client, clnt_indx)->ipv6_set++;
+ }
+ else
+ {
+ IPACMDBG_H("Already got 3 ipv6 addr for client:%d\n", clnt_indx);
+ return IPACM_FAILURE; /* not setup the RT rules*/
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Invalid IPV6 address\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle wan client routing rule*/
+int IPACM_Wan::handle_wan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ uint32_t tx_index;
+ int wan_index,v6_num;
+ const int NUM = 1;
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ IPACMDBG_H("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ wan_index = get_wan_client_index(mac_addr);
+ if (wan_index == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG_H("wan client not found/attached \n");
+ return IPACM_SUCCESS;
+ }
+
+ if (iptype==IPA_IP_v4) {
+ IPACMDBG_H("wan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wan_index, iptype,
+ get_client_memptr(wan_client, wan_index)->ipv4_set,
+ get_client_memptr(wan_client, wan_index)->route_rule_set_v4);
+ } else {
+ IPACMDBG_H("wan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wan_index, iptype,
+ get_client_memptr(wan_client, wan_index)->ipv6_set,
+ get_client_memptr(wan_client, wan_index)->route_rule_set_v6);
+ }
+
+ /* Add default routing rules if not set yet */
+ if ((iptype == IPA_IP_v4
+ && get_client_memptr(wan_client, wan_index)->route_rule_set_v4 == false
+ && get_client_memptr(wan_client, wan_index)->ipv4_set == true)
+ || (iptype == IPA_IP_v6
+ && get_client_memptr(wan_client, wan_index)->route_rule_set_v6 < get_client_memptr(wan_client, wan_index)->ipv6_set
+ ))
+ {
+
+ /* Add corresponding ipa_rm_resource_name of TX-endpoint up before IPV6 RT-rule set */
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", tx_prop->tx[0].dst_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe]);
+ IPACM_Iface::ipacmcfg->AddRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[tx_prop->tx[0].dst_pipe],false);
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_add));
+
+ if (rt_rule == NULL)
+ {
+ PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)NUM;
+ rt_rule->ip = iptype;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if(iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+ tx_index, tx_prop->tx[tx_index].ip,iptype);
+ continue;
+ }
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 0;
+
+ if (iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wan_index,
+ get_client_memptr(wan_client, wan_index)->v4_addr);
+
+ IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+ wan_index,
+ get_client_memptr(wan_client, wan_index)->hdr_hdl_v4);
+ strlcpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name,
+ sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, wan_index)->hdr_hdl_v4;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wan_client, wan_index)->v4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ /* copy ipv4 RT hdl */
+ get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4 =
+ rt_rule->rules[0].rt_rule_hdl;
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4, iptype);
+ } else {
+
+ for(v6_num = get_client_memptr(wan_client, wan_index)->route_rule_set_v6;v6_num < get_client_memptr(wan_client, wan_index)->ipv6_set;v6_num++)
+ {
+ IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+ wan_index,
+ get_client_memptr(wan_client, wan_index)->hdr_hdl_v6);
+
+ /* v6 LAN_RT_TBL */
+ strlcpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+ sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ /* Uplink going to wan clients should go to IPA */
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+ memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, wan_index)->hdr_hdl_v6;;
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6[v6_num], iptype);
+
+ /*Copy same rule to v6 WAN RT TBL*/
+ strlcpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
+ sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ /* Downlink traffic from Wan clients, should go exception */
+ rt_rule_entry->rule.dst = iface_query->excp_pipe;
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.hdr_hdl = 0;
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, wan_index)->v6_addr[v6_num][3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wan_client, wan_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num], iptype);
+ }
+ }
+
+ } /* end of for loop */
+
+ free(rt_rule);
+
+ if (iptype == IPA_IP_v4)
+ {
+ get_client_memptr(wan_client, wan_index)->route_rule_set_v4 = true;
+ }
+ else
+ {
+ get_client_memptr(wan_client, wan_index)->route_rule_set_v6 = get_client_memptr(wan_client, wan_index)->ipv6_set;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* TODO Handle wan client routing rules also */
+void IPACM_Wan::handle_wlan_SCC_MCC_switch(bool isSCCMode, ipa_ip_type iptype)
+{
+ struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+ struct ipa_rt_rule_mdfy *rt_rule_entry;
+ uint32_t tx_index = 0;
+
+ IPACMDBG("\n");
+ if (tx_prop == NULL || is_default_gateway == false)
+ {
+ IPACMDBG_H("No tx properties or no default route set yet\n");
+ return;
+ }
+
+ const int NUM = tx_prop->num_tx_props;
+
+ for (tx_index = 0; tx_index < tx_prop->num_tx_props; tx_index++)
+ {
+ if (tx_prop->tx[tx_index].ip != iptype)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d Ignore\n",
+ tx_index, tx_prop->tx[tx_index].ip, iptype);
+ continue;
+ }
+
+ if (rt_rule == NULL)
+ {
+ rt_rule = (struct ipa_ioc_mdfy_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_mdfy_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_mdfy));
+
+ if (rt_rule == NULL)
+ {
+ IPACMERR("Unable to allocate memory for modify rt rule\n");
+ return;
+ }
+ IPACMDBG("Allocated memory for %d rules successfully\n", NUM);
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = 0;
+ rt_rule->ip = iptype;
+ }
+
+ rt_rule_entry = &rt_rule->rules[rt_rule->num_rules];
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+ if (iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = 0;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0;
+ rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v4;
+ rt_rule_entry->rt_rule_hdl = wan_route_rule_v4_hdl[tx_index];
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0;
+
+ rt_rule_entry->rule.hdr_hdl = hdr_hdl_sta_v6;
+ rt_rule_entry->rt_rule_hdl = wan_route_rule_v6_hdl[tx_index];
+ }
+ IPACMDBG_H("Header handle: 0x%x\n", rt_rule_entry->rule.hdr_hdl);
+
+ if (isSCCMode)
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+ else
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+
+ rt_rule->num_rules++;
+ }
+
+ if (rt_rule != NULL)
+ {
+
+ if (rt_rule->num_rules > 0)
+ {
+ if (false == m_routing.ModifyRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule modify failed!\n");
+ free(rt_rule);
+ return;
+ }
+
+ IPACMDBG("Routing rule modified successfully \n");
+ }
+
+ free(rt_rule);
+ }
+
+ return;
+}
+
+void IPACM_Wan::handle_wan_client_SCC_MCC_switch(bool isSCCMode, ipa_ip_type iptype)
+{
+ struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+ struct ipa_rt_rule_mdfy *rt_rule_entry;
+
+ uint32_t tx_index = 0, clnt_index =0;
+ int v6_num = 0;
+ const int NUM_RULES = 1;
+
+ int size = sizeof(struct ipa_ioc_mdfy_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_mdfy);
+
+ IPACMDBG("isSCCMode: %d\n",isSCCMode);
+
+ if (tx_prop == NULL || is_default_gateway == false)
+ {
+ IPACMDBG_H("No tx properties or no default route set yet\n");
+ return;
+ }
+
+ rt_rule = (struct ipa_ioc_mdfy_rt_rule *)calloc(1, size);
+ if (rt_rule == NULL)
+ {
+ IPACMERR("Unable to allocate memory for modify rt rule\n");
+ return;
+ }
+
+
+ for (clnt_index = 0; clnt_index < num_wan_client; clnt_index++)
+ {
+ if (iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("wan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n",
+ clnt_index, iptype,
+ get_client_memptr(wan_client, clnt_index)->ipv4_set,
+ get_client_memptr(wan_client, clnt_index)->route_rule_set_v4);
+
+ if( get_client_memptr(wan_client, clnt_index)->route_rule_set_v4 == false ||
+ get_client_memptr(wan_client, clnt_index)->ipv4_set == false)
+ {
+ continue;
+ }
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d skip\n",
+ tx_index, tx_prop->tx[tx_index].ip, iptype);
+ continue;
+ }
+
+ memset(rt_rule, 0, size);
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = iptype;
+ rt_rule_entry = &rt_rule->rules[0];
+
+ IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", clnt_index,
+ get_client_memptr(wan_client, clnt_index)->v4_addr);
+
+ IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+ clnt_index,
+ get_client_memptr(wan_client, clnt_index)->hdr_hdl_v4);
+
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, clnt_index)->hdr_hdl_v4;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wan_client, clnt_index)->v4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+ /* copy ipv4 RT rule hdl */
+ IPACMDBG_H("rt rule hdl=%x\n",
+ get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4);
+
+ rt_rule_entry->rt_rule_hdl =
+ get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v4;
+
+ if (false == m_routing.ModifyRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule modify failed!\n");
+ free(rt_rule);
+ return;
+ }
+ }
+ }
+ else
+ {
+ IPACMDBG_H("wan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", clnt_index, iptype,
+ get_client_memptr(wan_client, clnt_index)->ipv6_set,
+ get_client_memptr(wan_client, clnt_index)->route_rule_set_v6);
+
+ if( get_client_memptr(wan_client, clnt_index)->route_rule_set_v6 == 0)
+ {
+ continue;
+ }
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d skip\n",
+ tx_index, tx_prop->tx[tx_index].ip, iptype);
+ continue;
+ }
+
+ memset(rt_rule, 0, size);
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = iptype;
+ rt_rule_entry = &rt_rule->rules[0];
+
+ /* Modify only rules in v6 WAN RT TBL*/
+ for (v6_num = 0;
+ v6_num < get_client_memptr(wan_client, clnt_index)->route_rule_set_v6;
+ v6_num++)
+ {
+ IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+ clnt_index,
+ get_client_memptr(wan_client, clnt_index)->hdr_hdl_v6);
+
+ /* Downlink traffic from Wan iface, directly through IPA */
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wan_client, clnt_index)->hdr_hdl_v6;
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wan_client, clnt_index)->v6_addr[v6_num][3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+ IPACMDBG_H("rt rule hdl=%x\n",
+ get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num]);
+
+ rt_rule_entry->rt_rule_hdl =
+ get_client_memptr(wan_client, clnt_index)->wan_rt_hdl[tx_index].wan_rt_rule_hdl_v6_wan[v6_num];
+
+ if (false == m_routing.ModifyRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule Modify failed!\n");
+ free(rt_rule);
+ return;
+ }
+ }
+ } /* end of for loop */
+ }
+
+ }
+
+ free(rt_rule);
+ return;
+}
+
+/*handle eth client */
+int IPACM_Wan::handle_network_stats_update(ipa_get_apn_data_stats_resp_msg_v01 *data)
+{
+ FILE *fp = NULL;
+
+ for (uint32_t apn_index =0; apn_index < data->apn_data_stats_list_len; apn_index++)
+ {
+ if(data->apn_data_stats_list[apn_index].mux_id == ext_prop->ext[0].mux_id)
+ {
+ IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_NETWORK_STATS, MUX ID %d TX (P%llu/B%llu) RX (P%llu/B%llu)\n",
+ data->apn_data_stats_list[apn_index].mux_id,
+ (long long)data->apn_data_stats_list[apn_index].num_ul_packets,
+ (long long)data->apn_data_stats_list[apn_index].num_ul_bytes,
+ (long long)data->apn_data_stats_list[apn_index].num_dl_packets,
+ (long long)data->apn_data_stats_list[apn_index].num_dl_bytes);
+ fp = fopen(IPA_NETWORK_STATS_FILE_NAME, "w");
+ if ( fp == NULL )
+ {
+ IPACMERR("Failed to write pipe stats to %s, error is %d - %s\n",
+ IPA_NETWORK_STATS_FILE_NAME, errno, strerror(errno));
+ return IPACM_FAILURE;
+ }
+
+ fprintf(fp, NETWORK_STATS,
+ dev_name,
+ (long long)data->apn_data_stats_list[apn_index].num_ul_packets,
+ (long long)data->apn_data_stats_list[apn_index].num_ul_bytes,
+ (long long)data->apn_data_stats_list[apn_index].num_dl_packets,
+ (long long)data->apn_data_stats_list[apn_index].num_dl_bytes);
+ fclose(fp);
+ break;
+ };
+ }
+ return IPACM_SUCCESS;
+}
+
+int IPACM_Wan::add_dummy_rx_hdr()
+{
+
+#define IFACE_INDEX_LEN 2
+ char index[IFACE_INDEX_LEN];
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+ int len = 0;
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_hdr_add *ipv6_hdr;
+ struct ethhdr *eth_ipv6;
+ struct ipa_ioc_add_hdr_proc_ctx* pHeaderProcTable = NULL;
+ uint32_t cnt;
+
+ /* get netdev-mac */
+ if(tx_prop != NULL)
+ {
+ /* copy partial header for v6 */
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+ {
+ IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n", sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* copy client mac_addr to partial header */
+ IPACMDBG_H("header eth2_ofst_valid: %d, eth2_ofst: %d\n",
+ sCopyHeader.is_eth2_ofst_valid, sCopyHeader.eth2_ofst);
+ /* only copy 6 bytes mac-address */
+ if(sCopyHeader.is_eth2_ofst_valid == false)
+ {
+ memcpy(netdev_mac, &sCopyHeader.hdr[0+IPA_MAC_ADDR_SIZE],
+ sizeof(netdev_mac));
+ }
+ else
+ {
+ memcpy(netdev_mac, &sCopyHeader.hdr[sCopyHeader.eth2_ofst+IPA_MAC_ADDR_SIZE],
+ sizeof(netdev_mac));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+ ipv6_hdr = &pHeaderDescriptor->hdr[0];
+ /* copy ethernet type to header */
+ eth_ipv6 = (struct ethhdr *) (ipv6_hdr->hdr +2);
+ memcpy(eth_ipv6->h_dest, netdev_mac, ETH_ALEN);
+ memcpy(eth_ipv6->h_source, ext_router_mac_addr, ETH_ALEN);
+ eth_ipv6->h_proto = htons(ETH_P_IPV6);
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(ipv6_hdr->name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ snprintf(index,sizeof(index), "%d", ipa_if_num);
+ strlcpy(ipv6_hdr->name, index, sizeof(ipv6_hdr->name));
+ ipv6_hdr->name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+ if (strlcat(ipv6_hdr->name, IPA_DUMMY_ETH_HDR_NAME_v6, sizeof(ipv6_hdr->name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(ipv6_hdr->name));
+ return IPACM_FAILURE;
+ }
+
+ ipv6_hdr->hdr_len = ETH_HLEN + 2;
+ ipv6_hdr->hdr_hdl = -1;
+ ipv6_hdr->is_partial = 0;
+ ipv6_hdr->status = -1;
+ ipv6_hdr->type = IPA_HDR_L2_ETHERNET_II;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ ipv6_hdr->status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", ipv6_hdr->status);
+ return IPACM_FAILURE;
+ }
+
+ hdr_hdl_dummy_v6 = ipv6_hdr->hdr_hdl;
+ IPACMDBG_H("dummy v6 full header name:%s header handle:(0x%x)\n",
+ ipv6_hdr->name,
+ hdr_hdl_dummy_v6);
+ /* add dummy hdr_proc_hdl */
+ len = sizeof(struct ipa_ioc_add_hdr_proc_ctx) + sizeof(struct ipa_hdr_proc_ctx_add);
+ pHeaderProcTable = (ipa_ioc_add_hdr_proc_ctx*)malloc(len);
+ if(pHeaderProcTable == NULL)
+ {
+ IPACMERR("Cannot allocate header processing table.\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(pHeaderProcTable, 0, len);
+ pHeaderProcTable->commit = 1;
+ pHeaderProcTable->num_proc_ctxs = 1;
+ pHeaderProcTable->proc_ctx[0].hdr_hdl = hdr_hdl_dummy_v6;
+ if (m_header.AddHeaderProcCtx(pHeaderProcTable) == false)
+ {
+ IPACMERR("Adding dummy hhdr_proc_hdl failed with status: %d\n", pHeaderProcTable->proc_ctx[0].status);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ hdr_proc_hdl_dummy_v6 = pHeaderProcTable->proc_ctx[0].proc_ctx_hdl;
+ IPACMDBG_H("dummy hhdr_proc_hdl is added successfully. (0x%x)\n", hdr_proc_hdl_dummy_v6);
+ }
+ return IPACM_SUCCESS;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Wlan.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Wlan.cpp
new file mode 100644
index 0000000..c912a6e
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Wlan.cpp
@@ -0,0 +1,2228 @@
+/*
+Copyright (c) 2013-2017, 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>
+#include <IPACM_ConntrackListener.h>
+
+
+/* static member to store the number of total wifi clients within all APs*/
+int IPACM_Wlan::total_num_wifi_clients = 0;
+
+int IPACM_Wlan::num_wlan_ap_iface = 0;
+
+IPACM_Wlan::IPACM_Wlan(int iface_index) : IPACM_Lan(iface_index)
+{
+#define WLAN_AMPDU_DEFAULT_FILTER_RULES 3
+
+ wlan_ap_index = IPACM_Wlan::num_wlan_ap_iface;
+ if(wlan_ap_index < 0 || wlan_ap_index > 1)
+ {
+ IPACMERR("Wlan_ap_index is not correct: %d, not creating instance.\n", wlan_ap_index);
+ if (tx_prop != NULL)
+ {
+ free(tx_prop);
+ }
+ if (rx_prop != NULL)
+ {
+ free(rx_prop);
+ }
+ if (iface_query != NULL)
+ {
+ free(iface_query);
+ }
+ delete this;
+ return;
+ }
+
+ num_wifi_client = 0;
+ header_name_count = 0;
+ wlan_client = NULL;
+ wlan_client_len = 0;
+
+ if(iface_query != NULL)
+ {
+ 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_H("index:%d constructor: Tx properties:%d\n", iface_index, iface_query->num_tx_props);
+ }
+ Nat_App = NatApp::GetInstance();
+ if (Nat_App == NULL)
+ {
+ IPACMERR("unable to get Nat App instance \n");
+ return;
+ }
+
+ IPACM_Wlan::num_wlan_ap_iface++;
+ IPACMDBG_H("Now the number of wlan AP iface is %d\n", IPACM_Wlan::num_wlan_ap_iface);
+
+ m_is_guest_ap = false;
+ if (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == INTERNET)
+ {
+ m_is_guest_ap = true;
+ }
+ IPACMDBG_H("%s: guest ap enable: %d \n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, m_is_guest_ap);
+
+#ifdef FEATURE_IPA_ANDROID
+ /* set the IPA-client pipe enum */
+ if(ipa_if_cate == WLAN_IF)
+ {
+#ifdef FEATURE_IPACM_HAL
+ handle_tethering_client(false, IPACM_CLIENT_MAX);
+#else
+ handle_tethering_client(false, IPACM_CLIENT_WLAN);
+#endif
+ }
+#endif
+ 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)
+{
+ if(is_active == false && event != IPA_LAN_DELETE_SELF)
+ {
+ IPACMDBG_H("The interface is no longer active, return.\n");
+ return;
+ }
+
+ int ipa_interface_index;
+ int wlan_index;
+ ipacm_ext_prop* ext_prop;
+ ipacm_event_iface_up_tehter* data_wan_tether;
+
+ switch (event)
+ {
+
+ case IPA_WLAN_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_H("Received IPA_WLAN_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ /* reset the AP-iface category to unknown */
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].if_cat = UNKNOWN_IF;
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ IPACM_Wlan::total_num_wifi_clients = (IPACM_Wlan::total_num_wifi_clients) - \
+ (num_wifi_client);
+ return;
+ }
+ }
+ break;
+
+ case IPA_PRIVATE_SUBNET_CHANGE_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ /* internel event: data->if_index is ipa_if_index */
+ if (data->if_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from itself posting, ignore\n");
+ return;
+ }
+ else
+ {
+ IPACMDBG_H("Received IPA_PRIVATE_SUBNET_CHANGE_EVENT from other LAN iface \n");
+#ifdef FEATURE_IPA_ANDROID
+ handle_private_subnet_android(IPA_IP_v4);
+#endif
+ IPACMDBG_H(" delete old private subnet rules, use new sets \n");
+ return;
+ }
+ }
+ break;
+
+ case IPA_LAN_DELETE_SELF:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ if(data->if_index == ipa_if_num)
+ {
+ IPACM_Wlan::num_wlan_ap_iface--;
+ IPACMDBG_H("Now the number of wlan AP iface is %d\n", IPACM_Wlan::num_wlan_ap_iface);
+
+ IPACMDBG_H("Received IPA_LAN_DELETE_SELF event.\n");
+ IPACMDBG_H("ipa_WLAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ delete this;
+ }
+ break;
+ }
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ if ( (data->iptype == IPA_IP_v4 && data->ipv4_addr == 0) ||
+ (data->iptype == IPA_IP_v6 &&
+ data->ipv6_addr[0] == 0 && data->ipv6_addr[1] == 0 &&
+ data->ipv6_addr[2] == 0 && data->ipv6_addr[3] == 0) )
+ {
+ IPACMDBG_H("Invalid address, ignore IPA_ADDR_ADD_EVENT event\n");
+ return;
+ }
+
+ if (ipa_interface_index == ipa_if_num)
+ {
+ /* check v4 not setup before, v6 can have 2 iface ip */
+ if( ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX))
+ || ((data->iptype==IPA_IP_v6) && (num_dft_rt_v6!=MAX_DEFAULT_v6_ROUTE_RULES)))
+ {
+ IPACMDBG_H("Got IPA_ADDR_ADD_EVENT ip-family:%d, v6 num %d: \n",data->iptype,num_dft_rt_v6);
+ /* Post event to NAT */
+ if (data->iptype == IPA_IP_v4)
+ {
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_iface_up *info;
+
+ info = (ipacm_event_iface_up *)
+ malloc(sizeof(ipacm_event_iface_up));
+ if (info == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+
+ memcpy(info->ifname, dev_name, IF_NAME_LEN);
+ info->ipv4_addr = data->ipv4_addr;
+ info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+ evt_data.event = IPA_HANDLE_WLAN_UP;
+ evt_data.evt_data = (void *)info;
+
+ /* Insert IPA_HANDLE_WLAN_UP to command queue */
+ IPACMDBG_H("posting IPA_HANDLE_WLAN_UP for IPv4 with below information\n");
+ IPACMDBG_H("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+ info->ipv4_addr, info->addr_mask);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ if(handle_addr_evt(data) == IPACM_FAILURE)
+ {
+ return;
+ }
+
+#ifdef FEATURE_IPA_ANDROID
+ add_dummy_private_subnet_flt_rule(data->iptype);
+ handle_private_subnet_android(data->iptype);
+#else
+ handle_private_subnet(data->iptype);
+#endif
+
+#ifndef FEATURE_IPACM_HAL
+ if (IPACM_Wan::isWanUP(ipa_if_num))
+ {
+ if(data->iptype == IPA_IP_v4 || data->iptype == IPA_IP_MAX)
+ {
+ if(IPACM_Wan::backhaul_is_sta_mode == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+ IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v4,
+ IPACM_Wan::getXlat_Mux_Id());
+ }
+ else
+ {
+ IPACM_Lan::handle_wan_up(IPA_IP_v4);
+ }
+ }
+ IPACMDBG_H("Finished checking wan_up\n");
+ } else {
+ IPACMDBG_H("Wan_V4 haven't up yet \n");
+ }
+
+ if(IPACM_Wan::isWanUP_V6(ipa_if_num))
+ {
+ if((data->iptype == IPA_IP_v6 || data->iptype == IPA_IP_MAX) && num_dft_rt_v6 == 1)
+ {
+ memcpy(ipv6_prefix, IPACM_Wan::backhaul_ipv6_prefix, sizeof(ipv6_prefix));
+ install_ipv6_prefix_flt_rule(IPACM_Wan::backhaul_ipv6_prefix);
+
+ if(IPACM_Wan::backhaul_is_sta_mode == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+ IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+ }
+ else
+ {
+ IPACM_Lan::handle_wan_up(IPA_IP_v6);
+ }
+ }
+ IPACMDBG_H("Finished checking wan_up_v6\n");
+ } else {
+ IPACMDBG_H("Wan_V6 haven't up yet \n");
+ }
+#endif
+ /* checking if SW-RT_enable */
+ if (IPACM_Iface::ipacmcfg->ipa_sw_rt_enable == true)
+ {
+ /* handle software routing enable event*/
+ IPACMDBG_H("IPA_SW_ROUTING_ENABLE for iface: %s \n",IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+ handle_software_routing_enable();
+ }
+ }
+ }
+ }
+ break;
+#ifdef FEATURE_IPA_ANDROID
+ case IPA_HANDLE_WAN_UP_TETHER:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP_TETHER event\n");
+
+ data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+ if(data_wan_tether == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+ data_wan_tether->if_index_tether,
+ IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+#ifndef FEATURE_IPACM_HAL
+ if (data_wan_tether->if_index_tether != ipa_if_num)
+ {
+ IPACMERR("IPA_HANDLE_WAN_UP_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num);
+ return;
+ }
+#endif
+ if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+#ifdef FEATURE_IPACM_HAL
+ if(is_upstream_set[IPA_IP_v4] == false)
+ {
+ IPACMDBG_H("Add upstream for IPv4.\n");
+ is_upstream_set[IPA_IP_v4] = true;
+ if(is_downstream_set[IPA_IP_v4] == true)
+ {
+ IPACMDBG_H("Downstream was set before, adding UL rules.\n");
+ if(data_wan_tether->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+ handle_wan_up_ex(ext_prop, IPA_IP_v4, 0);
+ } else {
+ handle_wan_up(IPA_IP_v4);
+ }
+ }
+ }
+#else
+ if(data_wan_tether->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+ handle_wan_up_ex(ext_prop, IPA_IP_v4, 0);
+ } else {
+ handle_wan_up(IPA_IP_v4);
+ }
+#endif
+ }
+ break;
+
+ case IPA_HANDLE_WAN_UP_V6_TETHER:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6_TETHER event\n");
+
+ data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+ if(data_wan_tether == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+ data_wan_tether->if_index_tether,
+ IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+#ifndef FEATURE_IPACM_HAL
+ if (data_wan_tether->if_index_tether != ipa_if_num)
+ {
+ IPACMERR("IPA_HANDLE_WAN_UP_V6_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num);
+ return;
+ }
+#endif
+ if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+#ifdef FEATURE_IPACM_HAL
+ if(is_upstream_set[IPA_IP_v6] == false)
+ {
+ IPACMDBG_H("Add upstream for IPv6.\n");
+ is_upstream_set[IPA_IP_v6] = true;
+
+ if(is_downstream_set[IPA_IP_v6] == true)
+ {
+ IPACMDBG_H("Downstream was set before, adding UL rules.\n");
+ memcpy(ipv6_prefix, data_wan_tether->ipv6_prefix, sizeof(ipv6_prefix));
+ install_ipv6_prefix_flt_rule(data_wan_tether->ipv6_prefix);
+ if(data_wan_tether->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+ handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+ }
+ else
+ {
+ handle_wan_up(IPA_IP_v6);
+ }
+ }
+ }
+#else
+ if(data_wan_tether->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+ handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+ }
+ else
+ {
+ handle_wan_up(IPA_IP_v6);
+ }
+#endif
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN_TETHER:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_TETHER event\n");
+ data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+ if(data_wan_tether == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ if(rx_prop == NULL)
+ {
+ IPACMERR("No rx prop.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+ data_wan_tether->if_index_tether,
+ IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+#ifndef FEATURE_IPACM_HAL
+ if (data_wan_tether->if_index_tether != ipa_if_num)
+ {
+ IPACMERR("IPA_HANDLE_WAN_DOWN_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num);
+ return;
+ }
+#endif
+ if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+#ifdef FEATURE_IPACM_HAL
+ if(is_upstream_set[IPA_IP_v4] == true)
+ {
+ IPACMDBG_H("Del upstream for IPv4.\n");
+ is_upstream_set[IPA_IP_v4] = false;
+ if(is_downstream_set[IPA_IP_v4] == true)
+ {
+ IPACMDBG_H("Downstream was set before, deleting UL rules.\n");
+ handle_wan_down(data_wan_tether->is_sta);
+ }
+ }
+#else
+ handle_wan_down(data_wan_tether->is_sta);
+#endif
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN_V6_TETHER:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6_TETHER event\n");
+ data_wan_tether = (ipacm_event_iface_up_tehter*)param;
+ if(data_wan_tether == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ if(rx_prop == NULL)
+ {
+ IPACMERR("No rx prop.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d, if_index_tether:%d tether_if_name:%s\n", data_wan_tether->is_sta,
+ data_wan_tether->if_index_tether,
+ IPACM_Iface::ipacmcfg->iface_table[data_wan_tether->if_index_tether].iface_name);
+#ifndef FEATURE_IPACM_HAL
+ if (data_wan_tether->if_index_tether != ipa_if_num)
+ {
+ IPACMERR("IPA_HANDLE_WAN_DOWN_V6_TETHER tether_if(%d), not valid (%d) ignore\n", data_wan_tether->if_index_tether, ipa_if_num);
+ return;
+ }
+#endif
+ if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+#ifdef FEATURE_IPACM_HAL
+ if(is_upstream_set[IPA_IP_v6] == true)
+ {
+ IPACMDBG_H("Del upstream for IPv6.\n");
+ is_upstream_set[IPA_IP_v6] = false;
+ if(is_downstream_set[IPA_IP_v6] == true)
+ {
+ IPACMDBG_H("Downstream was set before, deleting UL rules.\n");
+ /* reset usb-client ipv6 rt-rules */
+ handle_wlan_client_reset_rt(IPA_IP_v6);
+ handle_wan_down_v6(data_wan_tether->is_sta);
+ }
+ }
+#else
+ /* reset usb-client ipv6 rt-rules */
+ handle_wlan_client_reset_rt(IPA_IP_v6);
+ handle_wan_down_v6(data_wan_tether->is_sta);
+#endif
+ }
+ break;
+
+ case IPA_DOWNSTREAM_ADD:
+ {
+ ipacm_event_ipahal_stream *data = (ipacm_event_ipahal_stream *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if(ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_DOWNSTREAM_ADD event.\n");
+ if(is_downstream_set[data->prefix.iptype] == false)
+ {
+ IPACMDBG_H("Add downstream for IP iptype %d.\n", data->prefix.iptype);
+ is_downstream_set[data->prefix.iptype] = true;
+ memcpy(&prefix[data->prefix.iptype], &data->prefix,
+ sizeof(prefix[data->prefix.iptype]));
+
+ if(is_upstream_set[data->prefix.iptype] == true)
+ {
+ IPACMDBG_H("Upstream was set before, adding modem UL rules.\n");
+ if(ip_type == IPA_IP_MAX || ip_type == data->prefix.iptype)
+ {
+ if (data->prefix.iptype == IPA_IP_v6) /* ipv6 only */
+ {
+ /* Only offload clients has same prefix as Android gave */
+ ipv6_prefix[0] = data->prefix.v6Addr[0];
+ ipv6_prefix[1] = data->prefix.v6Addr[1];
+ IPACMDBG_H("ipv6_prefix0x%x:%x\n", ipv6_prefix[0], ipv6_prefix[1]);
+ install_ipv6_prefix_flt_rule(ipv6_prefix);
+ }
+
+ if (IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(data->prefix.iptype);
+ handle_wan_up_ex(ext_prop, data->prefix.iptype, 0);
+ } else {
+ handle_wan_up(data->prefix.iptype); /* STA */
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ case IPA_DOWNSTREAM_DEL:
+ {
+ ipacm_event_ipahal_stream *data = (ipacm_event_ipahal_stream *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if(ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG_H("Received IPA_DOWNSTREAM_DEL event.\n");
+ if(is_downstream_set[data->prefix.iptype] == true)
+ {
+ IPACMDBG_H("Del downstream for IP iptype %d.\n", data->prefix.iptype);
+ is_downstream_set[data->prefix.iptype] = false;
+
+ if(is_upstream_set[data->prefix.iptype] == true)
+ {
+ IPACMDBG_H("Upstream was set before, deleting UL rules.\n");
+ if (data->prefix.iptype == IPA_IP_v4)
+ {
+ handle_wan_down(IPACM_Wan::backhaul_is_sta_mode); /* LTE STA */
+ } else {
+ handle_wlan_client_reset_rt(IPA_IP_v6);
+ handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode); /* LTE STA */
+ }
+ }
+ }
+ }
+ break;
+ }
+#else
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP event\n");
+
+ ipacm_event_iface_up* data_wan = (ipacm_event_iface_up*)param;
+ if(data_wan == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+ if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+ if(data_wan->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v4);
+ IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v4, data_wan->xlat_mux_id);
+ }
+ else
+ {
+ IPACM_Lan::handle_wan_up(IPA_IP_v4);
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_UP_V6:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_UP_V6 event\n");
+
+ data_wan = (ipacm_event_iface_up*)param;
+ if(data_wan == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+ if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+ memcpy(ipv6_prefix, data_wan->ipv6_prefix, sizeof(ipv6_prefix));
+ install_ipv6_prefix_flt_rule(data_wan->ipv6_prefix);
+
+ if(data_wan->is_sta == false)
+ {
+ ext_prop = IPACM_Iface::ipacmcfg->GetExtProp(IPA_IP_v6);
+ IPACM_Lan::handle_wan_up_ex(ext_prop, IPA_IP_v6, 0);
+ }
+ else
+ {
+ IPACM_Lan::handle_wan_up(IPA_IP_v6);
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN event\n");
+ data_wan = (ipacm_event_iface_up*)param;
+ if(data_wan == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ IPACMDBG_H("Backhaul is sta mode?%d\n", data_wan->is_sta);
+ if (rx_prop != NULL)
+ {
+ if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+ handle_wan_down(data_wan->is_sta);
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN_V6:
+ IPACMDBG_H("Received IPA_HANDLE_WAN_DOWN_V6 event\n");
+ data_wan = (ipacm_event_iface_up*)param;
+ if(data_wan == NULL)
+ {
+ IPACMERR("No event data is found.\n");
+ return;
+ }
+ /* clean up v6 RT rules*/
+ IPACMDBG_H("Received IPA_WAN_V6_DOWN in WLAN-instance and need clean up client IPv6 address \n");
+ /* reset wifi-client ipv6 rt-rules */
+ handle_wlan_client_reset_rt(IPA_IP_v6);
+ IPACMDBG_H("Backhaul is sta mode ? %d\n", data_wan->is_sta);
+ if (rx_prop != NULL)
+ {
+ if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+ handle_wan_down_v6(data_wan->is_sta);
+ }
+ }
+ break;
+#endif
+
+ case IPA_WLAN_CLIENT_ADD_EVENT_EX:
+ {
+ ipacm_event_data_wlan_ex *data = (ipacm_event_data_wlan_ex *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ int i;
+ for(i=0; i<data->num_of_attribs; i++)
+ {
+ if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+ {
+ eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_ADD, IPA_IP_MAX, data->attribs[i].u.mac_addr, NULL, NULL);
+ break;
+ }
+ }
+ IPACMDBG_H("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
+ handle_wlan_client_init_ex(data);
+ }
+ }
+ 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_H("Received IPA_WLAN_CLIENT_DEL_EVENT\n");
+ eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_DEL, IPA_IP_MAX, data->mac_addr, NULL, NULL);
+ 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_H("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_H("Received IPA_WLAN_CLIENT_RECOVER_EVENT\n");
+
+ wlan_index = get_wlan_client_index(data->mac_addr);
+ if ((wlan_index != IPACM_INVALID_INDEX) &&
+ (get_client_memptr(wlan_client, wlan_index)->power_save_set == true))
+ {
+
+ IPACMDBG_H("change wlan client out of power safe mode \n");
+ get_client_memptr(wlan_client, wlan_index)->power_save_set = false;
+
+ /* First add route rules and then nat rules */
+ if(get_client_memptr(wlan_client, wlan_index)->ipv4_set == true) /* for ipv4 */
+ {
+ IPACMDBG_H("recover client index(%d):ipv4 address: 0x%x\n",
+ wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+ IPACMDBG_H("Adding Route Rules\n");
+ handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v4);
+ IPACMDBG_H("Adding Nat Rules\n");
+ Nat_App->ResetPwrSaveIf(get_client_memptr(wlan_client, wlan_index)->v4_addr);
+ }
+
+ if(get_client_memptr(wlan_client, wlan_index)->ipv6_set != 0) /* 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_H("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);
+ if (data->iptype == IPA_IP_v4)
+ {
+ /* Add NAT rules after ipv4 RT rules are set */
+ CtList->HandleNeighIpAddrAddEvt(data);
+ //Nat_App->ResetPwrSaveIf(data->ipv4_addr);
+ }
+ }
+ }
+ break;
+
+ /* handle software routing enable event, iface will update softwarerouting_act to true*/
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG_H("Received IPA_SW_ROUTING_ENABLE\n");
+ IPACM_Iface::handle_software_routing_enable();
+ break;
+
+ /* handle software routing disable event, iface will update softwarerouting_act to false*/
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG_H("Received IPA_SW_ROUTING_DISABLE\n");
+ IPACM_Iface::handle_software_routing_disable();
+ break;
+
+ case IPA_WLAN_SWITCH_TO_SCC:
+ IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_SCC\n");
+ if(ip_type == IPA_IP_MAX)
+ {
+ handle_SCC_MCC_switch(IPA_IP_v4);
+ handle_SCC_MCC_switch(IPA_IP_v6);
+ }
+ else
+ {
+ handle_SCC_MCC_switch(ip_type);
+ }
+ eth_bridge_post_event(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH, IPA_IP_MAX, NULL, NULL, NULL);
+ break;
+
+ case IPA_WLAN_SWITCH_TO_MCC:
+ IPACMDBG_H("Received IPA_WLAN_SWITCH_TO_MCC\n");
+ if(ip_type == IPA_IP_MAX)
+ {
+ handle_SCC_MCC_switch(IPA_IP_v4);
+ handle_SCC_MCC_switch(IPA_IP_v6);
+ }
+ else
+ {
+ handle_SCC_MCC_switch(ip_type);
+ }
+ eth_bridge_post_event(IPA_ETH_BRIDGE_WLAN_SCC_MCC_SWITCH, IPA_IP_MAX, NULL, NULL, NULL);
+ break;
+
+ case IPA_CRADLE_WAN_MODE_SWITCH:
+ {
+ IPACMDBG_H("Received IPA_CRADLE_WAN_MODE_SWITCH event.\n");
+ ipacm_event_cradle_wan_mode* wan_mode = (ipacm_event_cradle_wan_mode*)param;
+ if(wan_mode == NULL)
+ {
+ IPACMERR("Event data is empty.\n");
+ return;
+ }
+
+ if(wan_mode->cradle_wan_mode == BRIDGE)
+ {
+ handle_cradle_wan_mode_switch(true);
+ }
+ else
+ {
+ handle_cradle_wan_mode_switch(false);
+ }
+ }
+ break;
+ case IPA_CFG_CHANGE_EVENT:
+ {
+ IPACMDBG_H("Received IPA_CFG_CHANGE_EVENT event for %s with new wlan-mode: %s old wlan-mode: %s\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name,
+ (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == 0) ? "full" : "internet",
+ (m_is_guest_ap == true) ? "internet" : "full");
+ /* Add Natting iface to IPACM_Config if there is Rx/Tx property */
+ if (rx_prop != NULL || tx_prop != NULL)
+ {
+ IPACMDBG_H(" Has rx/tx properties registered for iface %s, add for NATTING \n", dev_name);
+ IPACM_Iface::ipacmcfg->AddNatIfaces(dev_name);
+ }
+
+ if (m_is_guest_ap == true && (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == FULL))
+ {
+ m_is_guest_ap = false;
+ IPACMDBG_H("wlan mode is switched to full access mode. \n");
+ eth_bridge_handle_wlan_mode_switch();
+ }
+ else if (m_is_guest_ap == false && (IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].wlan_mode == INTERNET))
+ {
+ m_is_guest_ap = true;
+ IPACMDBG_H("wlan mode is switched to internet only access mode. \n");
+ eth_bridge_handle_wlan_mode_switch();
+ }
+ else
+ {
+ IPACMDBG_H("No change in %s access mode. \n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name);
+ }
+ }
+ break;
+ case IPA_TETHERING_STATS_UPDATE_EVENT:
+ {
+ IPACMDBG_H("Received IPA_TETHERING_STATS_UPDATE_EVENT event.\n");
+ if (IPACM_Wan::isWanUP(ipa_if_num) || IPACM_Wan::isWanUP_V6(ipa_if_num))
+ {
+ if(IPACM_Wan::backhaul_is_sta_mode == false) /* LTE */
+ {
+ ipa_get_data_stats_resp_msg_v01 *data = (ipa_get_data_stats_resp_msg_v01 *)param;
+ if (data->ipa_stats_type != QMI_IPA_STATS_TYPE_PIPE_V01)
+ {
+ IPACMERR("not valid pipe stats\n");
+ return;
+ }
+ handle_tethering_stats_event(data);
+ };
+ }
+ }
+ break;
+#ifdef FEATURE_IPACM_HAL
+ /* WA for WLAN to clean up NAT instance during SSR */
+ case IPA_SSR_NOTICE:
+ {
+ IPACMDBG_H("Received IPA_SSR_NOTICE event.\n");
+ IPACM_Iface::ipacmcfg->DelNatIfaces(dev_name); // delete NAT-iface
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ return;
+}
+
+/* handle wifi client initial,copy all partial headers (tx property) */
+int IPACM_Wlan::handle_wlan_client_init_ex(ipacm_event_data_wlan_ex *data)
+{
+
+#define WLAN_IFACE_INDEX_LEN 2
+
+ int res = IPACM_SUCCESS, len = 0, i, evt_size;
+ char index[WLAN_IFACE_INDEX_LEN];
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+ uint32_t cnt;
+
+ /* start of adding header */
+ IPACMDBG_H("Wifi client number for this iface: %d & total number of wlan clients: %d\n",
+ num_wifi_client,IPACM_Wlan::total_num_wifi_clients);
+
+ 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_H("Wifi client number: %d\n", num_wifi_client);
+
+ /* add header to IPA */
+ if(tx_prop != NULL)
+ {
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+
+ evt_size = sizeof(ipacm_event_data_wlan_ex) + data->num_of_attribs * sizeof(struct ipa_wlan_hdr_attrib_val);
+ get_client_memptr(wlan_client, num_wifi_client)->p_hdr_info = (ipacm_event_data_wlan_ex*)malloc(evt_size);
+ memcpy(get_client_memptr(wlan_client, num_wifi_client)->p_hdr_info, data, evt_size);
+
+ /* copy partial header for v4*/
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v4)
+ {
+ IPACMDBG_H("Got partial v4-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ 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);
+ }
+
+ for(i = 0; i < data->num_of_attribs; i++)
+ {
+ if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+ {
+ memcpy(get_client_memptr(wlan_client, num_wifi_client)->mac,
+ data->attribs[i].u.mac_addr,
+ sizeof(get_client_memptr(wlan_client, num_wifi_client)->mac));
+
+ /* copy client mac_addr to partial header */
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset],
+ get_client_memptr(wlan_client, num_wifi_client)->mac,
+ IPA_MAC_ADDR_SIZE);
+ /* replace src mac to bridge mac_addr if any */
+ if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset+IPA_MAC_ADDR_SIZE],
+ IPACM_Iface::ipacmcfg->bridge_mac,
+ IPA_MAC_ADDR_SIZE);
+ IPACMDBG_H("device is in bridge mode \n");
+ }
+
+ }
+ else if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_STA_ID)
+ {
+ /* copy client id to header */
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset],
+ &data->attribs[i].u.sta_id, sizeof(data->attribs[i].u.sta_id));
+ }
+ else
+ {
+ IPACMDBG_H("The attribute type is not expected!\n");
+ }
+ }
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ snprintf(index,sizeof(index), "%d", ipa_if_num);
+ strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+ pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+ if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WLAN_PARTIAL_HDR_NAME_v4, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ snprintf(index,sizeof(index), "%d", header_name_count);
+ if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+
+ pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = 0;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ pHeaderDescriptor->hdr[0].status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl_v4 = pHeaderDescriptor->hdr[0].hdr_hdl;
+ IPACMDBG_H("client(%d) v4 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_v4);
+ get_client_memptr(wlan_client, num_wifi_client)->ipv4_header_set=true;
+ break;
+ }
+ }
+
+ /* copy partial header for v6*/
+ for (cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ if(tx_prop->tx[cnt].ip==IPA_IP_v6)
+ {
+ IPACMDBG_H("Got partial v6-header name from %d tx props\n", cnt);
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[cnt].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG_H("header name: %s in tx:%d\n", sCopyHeader.name,cnt);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG_H("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ 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);
+ }
+
+ for(i = 0; i < data->num_of_attribs; i++)
+ {
+ if(data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_MAC_ADDR)
+ {
+ memcpy(get_client_memptr(wlan_client, num_wifi_client)->mac,
+ data->attribs[i].u.mac_addr,
+ sizeof(get_client_memptr(wlan_client, num_wifi_client)->mac));
+
+ /* copy client mac_addr to partial header */
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset],
+ get_client_memptr(wlan_client, num_wifi_client)->mac,
+ IPA_MAC_ADDR_SIZE);
+
+ /* replace src mac to bridge mac_addr if any */
+ if (IPACM_Iface::ipacmcfg->ipa_bridge_enable)
+ {
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset+IPA_MAC_ADDR_SIZE],
+ IPACM_Iface::ipacmcfg->bridge_mac,
+ IPA_MAC_ADDR_SIZE);
+ IPACMDBG_H("device is in bridge mode \n");
+ }
+ }
+ else if (data->attribs[i].attrib_type == WLAN_HDR_ATTRIB_STA_ID)
+ {
+ /* copy client id to header */
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[data->attribs[i].offset],
+ &data->attribs[i].u.sta_id, sizeof(data->attribs[i].u.sta_id));
+ }
+ else
+ {
+ IPACMDBG_H("The attribute type is not expected!\n");
+ }
+ }
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ snprintf(index,sizeof(index), "%d", ipa_if_num);
+ strlcpy(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name));
+ pHeaderDescriptor->hdr[0].name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ if (strlcat(pHeaderDescriptor->hdr[0].name, IPA_WLAN_PARTIAL_HDR_NAME_v6, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ snprintf(index,sizeof(index), "%d", header_name_count);
+ if (strlcat(pHeaderDescriptor->hdr[0].name, index, sizeof(pHeaderDescriptor->hdr[0].name)) > IPA_RESOURCE_NAME_MAX)
+ {
+ IPACMERR(" header name construction failed exceed length (%zu)\n", strlen(pHeaderDescriptor->hdr[0].name));
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = 0;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ pHeaderDescriptor->hdr[0].status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl_v6 = pHeaderDescriptor->hdr[0].hdr_hdl;
+ IPACMDBG_H("client(%d) v6 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_v6);
+
+ get_client_memptr(wlan_client, num_wifi_client)->ipv6_header_set=true;
+ break;
+ }
+ }
+
+ /* 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 = 0;
+ get_client_memptr(wlan_client, num_wifi_client)->ipv4_set = false;
+ get_client_memptr(wlan_client, num_wifi_client)->ipv6_set = 0;
+ get_client_memptr(wlan_client, num_wifi_client)->power_save_set=false;
+ num_wifi_client++;
+ header_name_count++; //keep increasing header_name_count
+ IPACM_Wlan::total_num_wifi_clients++;
+ res = IPACM_SUCCESS;
+ IPACMDBG_H("Wifi client number: %d\n", num_wifi_client);
+ }
+ else
+ {
+ return res;
+ }
+
+fail:
+ free(pHeaderDescriptor);
+ return res;
+}
+
+/*handle wifi client */
+int IPACM_Wlan::handle_wlan_client_ipaddr(ipacm_event_data_all *data)
+{
+ int clnt_indx;
+ int v6_num;
+ uint32_t ipv6_link_local_prefix = 0xFE800000;
+ uint32_t ipv6_link_local_prefix_mask = 0xFFC00000;
+
+ IPACMDBG_H("number of wifi clients: %d\n", num_wifi_client);
+ IPACMDBG_H(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->mac_addr[0],
+ data->mac_addr[1],
+ data->mac_addr[2],
+ data->mac_addr[3],
+ data->mac_addr[4],
+ data->mac_addr[5]);
+
+ clnt_indx = get_wlan_client_index(data->mac_addr);
+
+ if (clnt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMERR("wlan client not found/attached \n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("Ip-type received %d\n", data->iptype);
+ if (data->iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("ipv4 address: 0x%x\n", data->ipv4_addr);
+ if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+ {
+ if (get_client_memptr(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
+ {
+ /* check if client got new IPv4 address*/
+ if(data->ipv4_addr == get_client_memptr(wlan_client, clnt_indx)->v4_addr)
+ {
+ IPACMDBG_H("Already setup ipv4 addr for client:%d, ipv4 address didn't change\n", clnt_indx);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG_H("ipv4 addr for client:%d is changed \n", clnt_indx);
+ /* delete NAT rules first */
+ CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, clnt_indx)->v4_addr);
+ delete_default_qos_rtrules(clnt_indx,IPA_IP_v4);
+ get_client_memptr(wlan_client, clnt_indx)->route_rule_set_v4 = false;
+ get_client_memptr(wlan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+ }
+ }
+ }
+ else
+ {
+ IPACMDBG_H("Invalid client IPv4 address \n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+ (data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] != 0)) /* check if all 0 not valid ipv6 address */
+ {
+ IPACMDBG_H("ipv6 address: 0x%x:%x:%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+ if( (data->ipv6_addr[0] & ipv6_link_local_prefix_mask) != (ipv6_link_local_prefix & ipv6_link_local_prefix_mask) &&
+ memcmp(ipv6_prefix, data->ipv6_addr, sizeof(ipv6_prefix)) != 0)
+ {
+ IPACMDBG_H("This IPv6 address is not global IPv6 address with correct prefix, ignore.\n");
+ IPACMDBG_H("ipv6 address: 0x%x:%x ipv6_prefix0x%x:%x\n", data->ipv6_addr[0], data->ipv6_addr[1], ipv6_prefix[0], ipv6_prefix[1]);
+ return IPACM_FAILURE;
+ }
+
+ if(get_client_memptr(wlan_client, clnt_indx)->ipv6_set < IPV6_NUM_ADDR)
+ {
+
+ for(v6_num=0;v6_num < get_client_memptr(wlan_client, clnt_indx)->ipv6_set;v6_num++)
+ {
+ if( data->ipv6_addr[0] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][0] &&
+ data->ipv6_addr[1] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][1] &&
+ data->ipv6_addr[2]== get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][2] &&
+ data->ipv6_addr[3] == get_client_memptr(wlan_client, clnt_indx)->v6_addr[v6_num][3])
+ {
+ IPACMDBG_H("Already see this ipv6 addr for client:%d\n", clnt_indx);
+ return IPACM_FAILURE; /* not setup the RT rules*/
+ break;
+ }
+ }
+
+ /* not see this ipv6 before for wifi client*/
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][0] = data->ipv6_addr[0];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][1] = data->ipv6_addr[1];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][2] = data->ipv6_addr[2];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[get_client_memptr(wlan_client, clnt_indx)->ipv6_set][3] = data->ipv6_addr[3];
+ get_client_memptr(wlan_client, clnt_indx)->ipv6_set++;
+ }
+ else
+ {
+ IPACMDBG_H("Already got %d ipv6 addr for client:%d\n", IPV6_NUM_ADDR, clnt_indx);
+ return IPACM_FAILURE; /* not setup the RT rules*/
+ }
+ }
+ else
+ {
+ IPACMDBG_H("IPV6 address is invalid\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ 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,v6_num;
+ const int NUM = 1;
+
+ if(tx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return IPACM_SUCCESS;
+ }
+
+ IPACMDBG_H("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ wlan_index = get_wlan_client_index(mac_addr);
+ if (wlan_index == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG_H("wlan client not found/attached \n");
+ return IPACM_SUCCESS;
+ }
+
+ /* during power_save mode, even receive IP_ADDR_ADD, not setting RT rules*/
+ if (get_client_memptr(wlan_client, wlan_index)->power_save_set == true)
+ {
+ IPACMDBG_H("wlan client is in power safe mode \n");
+ return IPACM_SUCCESS;
+ }
+
+ if (iptype==IPA_IP_v4)
+ {
+ IPACMDBG_H("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);
+ }
+ else
+ {
+ IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wlan_index, iptype,
+ get_client_memptr(wlan_client, wlan_index)->ipv6_set,
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6);
+ }
+
+
+ /* Add default 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 < get_client_memptr(wlan_client, wlan_index)->ipv6_set
+ ))
+ {
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_add));
+
+ if (rt_rule == NULL)
+ {
+ PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)NUM;
+ rt_rule->ip = iptype;
+
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+
+ if(iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d conflict ip-type: %d no RT-rule added\n",
+ tx_index, tx_prop->tx[tx_index].ip,iptype);
+ continue;
+ }
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 0;
+
+ if (iptype == IPA_IP_v4)
+ {
+ IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+ IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+ wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4);
+ strlcpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
+ sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+
+ if(IPACM_Iface::ipacmcfg->isMCC_Mode)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_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;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = false;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ /* copy ipv4 RT hdl */
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+ rt_rule->rules[0].rt_rule_hdl;
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
+ }
+ else
+ {
+ for(v6_num = get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6;v6_num < get_client_memptr(wlan_client, wlan_index)->ipv6_set;v6_num++)
+ {
+ IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+ wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6);
+
+ /* v6 LAN_RT_TBL */
+ strlcpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+ sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ /* Support QCMAP LAN traffic feature, send to A5 */
+ rt_rule_entry->rule.dst = iface_query->excp_pipe;
+ memset(&rt_rule_entry->rule.attrib, 0, sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.hdr_hdl = 0;
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[v6_num], iptype);
+
+ /*Copy same rule to v6 WAN RT TBL*/
+ strlcpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_wan_v6.name,
+ sizeof(rt_rule->rt_tbl_name));
+ rt_rule->rt_tbl_name[IPA_RESOURCE_NAME_MAX-1] = '\0';
+ /* Downlink traffic from Wan iface, directly through IPA */
+ if(IPACM_Iface::ipacmcfg->isMCC_Mode)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6;
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+#ifdef FEATURE_IPA_V3
+ rt_rule_entry->rule.hashable = true;
+#endif
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num] = rt_rule->rules[0].rt_rule_hdl;
+
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num], iptype);
+ }
+ }
+
+ } /* end of for loop */
+
+ 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 = get_client_memptr(wlan_client, wlan_index)->ipv6_set;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle wifi client power-save mode*/
+int IPACM_Wlan::handle_wlan_client_pwrsave(uint8_t *mac_addr)
+{
+ int clt_indx;
+ IPACMDBG_H("wlan->handle_wlan_client_pwrsave();\n");
+
+ clt_indx = get_wlan_client_index(mac_addr);
+ if (clt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG_H("wlan client not attached\n");
+ return IPACM_SUCCESS;
+ }
+
+ if (get_client_memptr(wlan_client, clt_indx)->power_save_set == false)
+ {
+ /* First reset nat rules and then route rules */
+ if(get_client_memptr(wlan_client, clt_indx)->ipv4_set == true)
+ {
+ IPACMDBG_H("Deleting Nat Rules\n");
+ Nat_App->UpdatePwrSaveIf(get_client_memptr(wlan_client, clt_indx)->v4_addr);
+ }
+
+ IPACMDBG_H("Deleting default qos Route Rules\n");
+ delete_default_qos_rtrules(clt_indx, IPA_IP_v4);
+ delete_default_qos_rtrules(clt_indx, IPA_IP_v6);
+ get_client_memptr(wlan_client, clt_indx)->power_save_set = true;
+ }
+ else
+ {
+ IPACMDBG_H("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;
+ int num_v6;
+
+ IPACMDBG_H("total client: %d\n", num_wifi_client_tmp);
+
+ clt_indx = get_wlan_client_index(mac_addr);
+ if (clt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG_H("wlan client not attached\n");
+ return IPACM_SUCCESS;
+ }
+
+ /* First reset nat rules and then route rules */
+ if(get_client_memptr(wlan_client, clt_indx)->ipv4_set == true)
+ {
+ IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wlan_client, clt_indx)->v4_addr);
+ CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, clt_indx)->v4_addr);
+ }
+
+ if (delete_default_qos_rtrules(clt_indx, IPA_IP_v4))
+ {
+ IPACMERR("unbale to delete v4 default qos route rules for index: %d\n", clt_indx);
+ return IPACM_FAILURE;
+ }
+
+ if (delete_default_qos_rtrules(clt_indx, IPA_IP_v6))
+ {
+ IPACMERR("unbale to delete v6 default qos route rules for indexn: %d\n", clt_indx);
+ return IPACM_FAILURE;
+ }
+
+ /* Delete wlan client header */
+ if(get_client_memptr(wlan_client, clt_indx)->ipv4_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, clt_indx)->hdr_hdl_v4)
+ == false)
+ {
+ return IPACM_FAILURE;
+ }
+ get_client_memptr(wlan_client, clt_indx)->ipv4_header_set = false;
+ }
+
+ if(get_client_memptr(wlan_client, clt_indx)->ipv6_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, clt_indx)->hdr_hdl_v6)
+ == false)
+ {
+ return IPACM_FAILURE;
+ }
+ get_client_memptr(wlan_client, clt_indx)->ipv6_header_set = false;
+ }
+
+ /* Reset ip_set to 0*/
+ get_client_memptr(wlan_client, clt_indx)->ipv4_set = false;
+ get_client_memptr(wlan_client, clt_indx)->ipv6_set = 0;
+ get_client_memptr(wlan_client, clt_indx)->ipv4_header_set = false;
+ get_client_memptr(wlan_client, clt_indx)->ipv6_header_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 = 0;
+ free(get_client_memptr(wlan_client, clt_indx)->p_hdr_info);
+
+ for (; clt_indx < num_wifi_client_tmp - 1; clt_indx++)
+ {
+ get_client_memptr(wlan_client, clt_indx)->p_hdr_info = get_client_memptr(wlan_client, (clt_indx + 1))->p_hdr_info;
+
+ 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_v4 = get_client_memptr(wlan_client, (clt_indx + 1))->hdr_hdl_v4;
+ get_client_memptr(wlan_client, clt_indx)->hdr_hdl_v6 = get_client_memptr(wlan_client, (clt_indx + 1))->hdr_hdl_v6;
+ 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)->ipv4_header_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv4_header_set;
+ get_client_memptr(wlan_client, clt_indx)->ipv6_header_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv6_header_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;
+
+ for(num_v6=0;num_v6< get_client_memptr(wlan_client, clt_indx)->ipv6_set;num_v6++)
+ {
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[num_v6][0] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[num_v6][0];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[num_v6][1] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[num_v6][1];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[num_v6][2] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[num_v6][2];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[num_v6][3] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[num_v6][3];
+ }
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ get_client_memptr(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;
+
+ for(num_v6=0;num_v6< get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6;num_v6++)
+ {
+ get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[num_v6] =
+ get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6[num_v6];
+ get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[num_v6] =
+ get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[num_v6];
+ }
+ }
+ }
+
+ IPACMDBG_H(" %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_H(" Number of wifi client: %d\n", num_wifi_client);
+
+ return IPACM_SUCCESS;
+}
+
+/*handle wlan iface down event*/
+int IPACM_Wlan::handle_down_evt()
+{
+ int res = IPACM_SUCCESS, num_private_subnet_fl_rule;
+ uint32_t i;
+ num_private_subnet_fl_rule = 0;
+
+ IPACMDBG_H("WLAN ip-type: %d \n", ip_type);
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ IPACMERR("Invalid iptype: 0x%x\n", ip_type);
+ goto fail;
+ }
+
+ /* delete wan filter rule */
+ if (IPACM_Wan::isWanUP(ipa_if_num) && rx_prop != NULL)
+ {
+ IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
+ IPACM_Lan::handle_wan_down(IPACM_Wan::backhaul_is_sta_mode);
+#ifdef FEATURE_IPA_ANDROID
+ /* Clean-up tethered-iface list */
+ IPACM_Wan::delete_tether_iface(IPA_IP_v4, ipa_if_num);
+#endif
+ }
+
+ if (IPACM_Wan::isWanUP_V6(ipa_if_num) && rx_prop != NULL)
+ {
+ IPACMDBG_H("LAN IF goes down, backhaul type %d\n", IPACM_Wan::backhaul_is_sta_mode);
+ handle_wan_down_v6(IPACM_Wan::backhaul_is_sta_mode);
+#ifdef FEATURE_IPA_ANDROID
+ /* Clean-up tethered-iface list */
+ IPACM_Wan::delete_tether_iface(IPA_IP_v6, ipa_if_num);
+#endif
+ }
+ IPACMDBG_H("finished deleting wan filtering rules\n ");
+
+ /* Delete v4 filtering rules */
+ if (ip_type != IPA_IP_v6 && rx_prop != NULL)
+ {
+ /* delete IPv4 icmp filter rules */
+ if(m_filtering.DeleteFilteringHdls(ipv4_icmp_flt_rule_hdl, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE) == false)
+ {
+ IPACMERR("Error Deleting ICMPv4 Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, NUM_IPV4_ICMP_FLT_RULE);
+ if (dft_v4fl_rule_hdl[0] != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Deleting Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPV4_DEFAULT_FILTERTING_RULES);
+ IPACMDBG_H("Deleted default v4 filter rules successfully.\n");
+ }
+ /* delete private-ipv4 filter rules */
+#ifdef FEATURE_IPA_ANDROID
+ if(m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES) == false)
+ {
+ IPACMERR("Error deleting private subnet IPv4 flt rules.\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, IPA_MAX_PRIVATE_SUBNET_ENTRIES);
+#else
+ num_private_subnet_fl_rule = IPACM_Iface::ipacmcfg->ipa_num_private_subnet > IPA_MAX_PRIVATE_SUBNET_ENTRIES?
+ IPA_MAX_PRIVATE_SUBNET_ENTRIES : IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+ if(m_filtering.DeleteFilteringHdls(private_fl_rule_hdl, IPA_IP_v4, num_private_subnet_fl_rule) == false)
+ {
+ IPACMERR("Error deleting private subnet flt rules, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v4, num_private_subnet_fl_rule);
+#endif
+ IPACMDBG_H("Deleted private subnet v4 filter rules successfully.\n");
+ }
+
+ /* Delete v6 filtering rules */
+ if (ip_type != IPA_IP_v4 && rx_prop != NULL)
+ {
+ /* delete icmp filter rules */
+ if(m_filtering.DeleteFilteringHdls(ipv6_icmp_flt_rule_hdl, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE) == false)
+ {
+ IPACMERR("Error Deleting ICMPv6 Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, NUM_IPV6_ICMP_FLT_RULE);
+
+ if (dft_v6fl_rule_hdl[0] != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ IPACM_Iface::ipacmcfg->decreaseFltRuleCount(rx_prop->rx[0].src_pipe, IPA_IP_v6, IPV6_DEFAULT_FILTERTING_RULES);
+ IPACMDBG_H("Deleted default v6 filter rules successfully.\n");
+ }
+ }
+ IPACMDBG_H("finished delete filtering rules\n ");
+
+ /* Delete default v4 RT rule */
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG_H("Delete default v4 routing rules\n");
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* Delete default v6 RT rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ IPACMDBG_H("Delete default v6 routing rules\n");
+ /* May have multiple ipv6 iface-RT rules */
+ for (i = 0; i < 2*num_dft_rt_v6; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[MAX_DEFAULT_v4_ROUTE_RULES+i], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+ IPACMDBG_H("finished deleting default RT rules\n ");
+
+ eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_DOWN, IPA_IP_MAX, NULL, NULL, NULL);
+
+ /* free the wlan clients cache */
+ IPACMDBG_H("Free wlan clients cache\n");
+
+ /* Delete private subnet*/
+#ifdef FEATURE_IPA_ANDROID
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG_H("current IPACM private subnet_addr number(%d)\n", IPACM_Iface::ipacmcfg->ipa_num_private_subnet);
+ IPACMDBG_H(" Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+ if(IPACM_Iface::ipacmcfg->DelPrivateSubnet(if_ipv4_subnet, ipa_if_num) == false)
+ {
+ IPACMERR(" can't Delete IPACM private subnet_addr as: 0x%x \n", if_ipv4_subnet);
+ }
+ }
+ /* reset the IPA-client pipe enum */
+#ifdef FEATURE_IPACM_HAL
+ handle_tethering_client(true, IPACM_CLIENT_MAX);
+#else
+ handle_tethering_client(true, IPACM_CLIENT_WLAN);
+#endif
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+fail:
+ /* clean wifi-client header, routing rules */
+ /* clean wifi client rule*/
+ IPACMDBG_H("left %d wifi clients need to be deleted \n ", num_wifi_client);
+ for (i = 0; i < num_wifi_client; i++)
+ {
+ /* First reset nat rules and then route rules */
+ if(get_client_memptr(wlan_client, i)->ipv4_set == true)
+ {
+ IPACMDBG_H("Clean Nat Rules for ipv4:0x%x\n", get_client_memptr(wlan_client, i)->v4_addr);
+ CtList->HandleNeighIpAddrDelEvt(get_client_memptr(wlan_client, i)->v4_addr);
+ }
+
+ if (delete_default_qos_rtrules(i, IPA_IP_v4))
+ {
+ IPACMERR("unbale to delete v4 default qos route rules for index: %d\n", i);
+ res = IPACM_FAILURE;
+ }
+
+ if (delete_default_qos_rtrules(i, IPA_IP_v6))
+ {
+ IPACMERR("unbale to delete v6 default qos route rules for index: %d\n", i);
+ res = IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("Delete %d client header\n", num_wifi_client);
+
+ if(get_client_memptr(wlan_client, i)->ipv4_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, i)->hdr_hdl_v4)
+ == false)
+ {
+ res = IPACM_FAILURE;
+ }
+ }
+
+ if(get_client_memptr(wlan_client, i)->ipv6_header_set == true)
+ {
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, i)->hdr_hdl_v6)
+ == false)
+ {
+ res = IPACM_FAILURE;
+ }
+ }
+ } /* end of for loop */
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true && rx_prop != NULL )
+ {
+ IPACMDBG_H("Delete sw routing filtering rules\n");
+ IPACM_Iface::handle_software_routing_disable();
+ }
+ IPACMDBG_H("finished delete software-routing filtering rules\n ");
+
+ /* Delete corresponding ipa_rm_resource_name of RX-endpoint after delete all IPV4V6 FT-rule */
+ if (rx_prop != NULL)
+ {
+ IPACMDBG_H("dev %s add producer dependency\n", dev_name);
+ IPACMDBG_H("depend Got pipe %d rm index : %d \n", rx_prop->rx[0].src_pipe, IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+ IPACM_Iface::ipacmcfg->DelRmDepend(IPACM_Iface::ipacmcfg->ipa_client_rm_map_tbl[rx_prop->rx[0].src_pipe]);
+ free(rx_prop);
+ }
+
+ for (i = 0; i < num_wifi_client; i++)
+ {
+ if(get_client_memptr(wlan_client, i)->p_hdr_info != NULL)
+ {
+ free(get_client_memptr(wlan_client, i)->p_hdr_info);
+ }
+ }
+ if(wlan_client != NULL)
+ {
+ free(wlan_client);
+ }
+ if (tx_prop != NULL)
+ {
+ free(tx_prop);
+ }
+
+ if (iface_query != NULL)
+ {
+ free(iface_query);
+ }
+
+ is_active = false;
+ post_del_self_evt();
+
+ return res;
+}
+
+/*handle reset wifi-client rt-rules */
+int IPACM_Wlan::handle_wlan_client_reset_rt(ipa_ip_type iptype)
+{
+ uint32_t i;
+ int res = IPACM_SUCCESS;
+
+ /* clean wifi-client routing rules */
+ IPACMDBG_H("left %d wifi clients to reset ip-type(%d) rules \n ", num_wifi_client, iptype);
+
+ for (i = 0; i < num_wifi_client; i++)
+ {
+ /* Reset RT rules */
+ res = delete_default_qos_rtrules(i, iptype);
+ if (res != IPACM_SUCCESS)
+ {
+ IPACMERR("Failed to delete old iptype(%d) rules.\n", iptype);
+ return res;
+ }
+
+ /* Reset ip-address */
+ if(iptype == IPA_IP_v4)
+ {
+ get_client_memptr(wlan_client, i)->ipv4_set = false;
+ }
+ else
+ {
+ get_client_memptr(wlan_client, i)->ipv6_set = 0;
+ }
+ } /* end of for loop */
+ return res;
+}
+
+void IPACM_Wlan::handle_SCC_MCC_switch(ipa_ip_type iptype)
+{
+ struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+ struct ipa_rt_rule_mdfy *rt_rule_entry;
+ uint32_t tx_index;
+ int wlan_index, v6_num;
+ const int NUM = 1;
+ int num_wifi_client_tmp = IPACM_Wlan::num_wifi_client;
+ bool isAdded = false;
+
+ if (tx_prop == NULL)
+ {
+ IPACMDBG_H("No rx properties registered for iface %s\n", dev_name);
+ return;
+ }
+
+ if (rt_rule == NULL)
+ {
+ rt_rule = (struct ipa_ioc_mdfy_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_mdfy_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_mdfy));
+
+ if (rt_rule == NULL)
+ {
+ PERROR("Error Locate ipa_ioc_mdfy_rt_rule memory...\n");
+ return;
+ }
+
+ rt_rule->commit = 0;
+ rt_rule->num_rules = NUM;
+ rt_rule->ip = iptype;
+ }
+ rt_rule_entry = &rt_rule->rules[0];
+
+ /* modify ipv4 routing rule */
+ if (iptype == IPA_IP_v4)
+ {
+ for (wlan_index = 0; wlan_index < num_wifi_client_tmp; wlan_index++)
+ {
+ IPACMDBG_H("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);
+
+ if (get_client_memptr(wlan_client, wlan_index)->power_save_set == true ||
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false)
+ {
+ IPACMDBG_H("client %d route rules not set\n", wlan_index);
+ continue;
+ }
+
+ IPACMDBG_H("Modify client %d route rule\n", wlan_index);
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d ignore\n",
+ tx_index, tx_prop->tx[tx_index].ip, iptype);
+ continue;
+ }
+
+ IPACMDBG_H("client index(%d):ipv4 address: 0x%x\n", wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+ IPACMDBG_H("client(%d): v4 header handle:(0x%x)\n",
+ wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v4);
+
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_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;
+
+ IPACMDBG_H("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);
+
+ rt_rule_entry->rt_rule_hdl =
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+ if (false == m_routing.ModifyRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule modify failed!\n");
+ free(rt_rule);
+ return;
+ }
+ isAdded = true;
+ }
+
+ }
+ }
+
+ /* modify ipv6 routing rule */
+ if (iptype == IPA_IP_v6)
+ {
+ for (wlan_index = 0; wlan_index < num_wifi_client_tmp; wlan_index++)
+ {
+
+ IPACMDBG_H("wlan client index: %d, ip-type: %d, ipv6_set:%d, ipv6_rule_num:%d \n", wlan_index, iptype,
+ get_client_memptr(wlan_client, wlan_index)->ipv6_set,
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6);
+
+ if (get_client_memptr(wlan_client, wlan_index)->power_save_set == true ||
+ (get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 <
+ get_client_memptr(wlan_client, wlan_index)->ipv6_set) )
+ {
+ IPACMDBG_H("client %d route rules not set\n", wlan_index);
+ continue;
+ }
+
+ IPACMDBG_H("Modify client %d route rule\n", wlan_index);
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype != tx_prop->tx[tx_index].ip)
+ {
+ IPACMDBG_H("Tx:%d, ip-type: %d ip-type not matching: %d Ignore\n",
+ tx_index, tx_prop->tx[tx_index].ip, iptype);
+ continue;
+ }
+
+ for (v6_num = get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6;
+ v6_num < get_client_memptr(wlan_client, wlan_index)->ipv6_set;
+ v6_num++)
+ {
+
+ IPACMDBG_H("client(%d): v6 header handle:(0x%x)\n",
+ wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6);
+
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[tx_index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ }
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl_v6;
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[v6_num][3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+
+ rt_rule_entry->rt_rule_hdl =
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6_wan[v6_num];
+
+ if (false == m_routing.ModifyRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule modify failed!\n");
+ free(rt_rule);
+ return;
+ }
+ isAdded = true;
+ }
+ }
+
+ }
+ }
+
+
+ if (isAdded)
+ {
+ if (false == m_routing.Commit(iptype))
+ {
+ IPACMERR("Routing rule modify commit failed!\n");
+ free(rt_rule);
+ return;
+ }
+
+ IPACMDBG("Routing rule modified successfully \n");
+ }
+
+ if(rt_rule)
+ {
+ free(rt_rule);
+ }
+ return;
+}
+
+void IPACM_Wlan::eth_bridge_handle_wlan_mode_switch()
+{
+ uint32_t i;
+
+ /* ====== post events to mimic WLAN interface goes down/up when AP mode is changing ====== */
+
+ /* first post IFACE_DOWN event */
+ eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_DOWN, IPA_IP_MAX, NULL, NULL, NULL);
+
+ /* then post IFACE_UP event */
+ if(ip_type == IPA_IP_v4 || ip_type == IPA_IP_MAX)
+ {
+ eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_UP, IPA_IP_v4, NULL, NULL, NULL);
+ }
+ if(ip_type == IPA_IP_v6 || ip_type == IPA_IP_MAX)
+ {
+ eth_bridge_post_event(IPA_ETH_BRIDGE_IFACE_UP, IPA_IP_v6, NULL, NULL, NULL);
+ }
+
+ /* at last post CLIENT_ADD event */
+ for(i = 0; i < num_wifi_client; i++)
+ {
+ eth_bridge_post_event(IPA_ETH_BRIDGE_CLIENT_ADD, IPA_IP_MAX,
+ get_client_memptr(wlan_client, i)->mac, NULL, NULL);
+ }
+
+ return;
+}
+
+bool IPACM_Wlan::is_guest_ap()
+{
+ return m_is_guest_ap;
+}
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Xml.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Xml.cpp
new file mode 100644
index 0000000..b81856a
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Xml.cpp
@@ -0,0 +1,1173 @@
+/*
+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 = IPACM_SUCCESS;
+
+ /* Invoke the XML parser and obtain the parse tree */
+ doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+ if (doc == NULL) {
+ IPACMDBG_H("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_H("IPACM_xml_parse: ipacm_cfg_xml_parse_tree returned parse error!\n");
+ }
+
+ /* Free up the libxml's parse tree */
+ xmlFreeDoc(doc);
+
+ 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, ODU_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 ||
+ IPACM_util_icmp_string((char*)xml_node->name, IP_PassthroughFlag_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, IP_PassthroughMode_TAG) == 0)
+ {
+ IPACMDBG_H("inside IP Passthrough\n");
+ 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))
+ {
+ config->ip_passthrough_mode = true;
+ IPACMDBG_H("Passthrough enable %d buf(%d)\n", config->ip_passthrough_mode, atoi(content_buf));
+ }
+ else
+ {
+ config->ip_passthrough_mode = false;
+ IPACMDBG_H("Passthrough enable %d buf(%d)\n", config->ip_passthrough_mode, atoi(content_buf));
+ }
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name, ODUMODE_TAG) == 0)
+ {
+ IPACMDBG_H("inside ODU-XML\n");
+ 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, ODU_ROUTER_TAG, str_size))
+ {
+ config->router_mode_enable = true;
+ IPACMDBG_H("router-mode enable %d\n", config->router_mode_enable);
+ }
+ else if (0 == strncasecmp(content_buf, ODU_BRIDGE_TAG, str_size))
+ {
+ config->router_mode_enable = false;
+ IPACMDBG_H("router-mode enable %d\n", config->router_mode_enable);
+ }
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name, ODUEMBMS_OFFLOAD_TAG) == 0)
+ {
+ IPACMDBG_H("inside ODU-XML\n");
+ 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))
+ {
+ config->odu_embms_enable = true;
+ IPACMDBG_H("router-mode enable %d buf(%d)\n", config->odu_embms_enable, atoi(content_buf));
+ }
+ else
+ {
+ config->odu_embms_enable = false;
+ IPACMDBG_H("router-mode enable %d buf(%d)\n", config->odu_embms_enable, atoi(content_buf));
+ }
+ }
+ }
+ 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));
+ strlcpy(content_buf, content, MAX_XML_STR_LEN);
+ strlcpy(config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name, content_buf, IPA_IFACE_NAME_LEN);
+ IPACMDBG_H("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_H("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_H("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_H("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_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, UNKNOWNIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = UNKNOWN_IF;
+ IPACMDBG_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, ETHIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = ETH_IF;
+ IPACMDBG_H("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, ODUIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = ODU_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, MODE_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, IFACE_ROUTER_MODE_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode = ROUTER;
+ IPACMDBG_H("Iface mode %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode);
+ }
+ else if (0 == strncasecmp(content_buf, IFACE_BRIDGE_MODE_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode = BRIDGE;
+ IPACMDBG_H("Iface mode %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_mode);
+ }
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name, WLAN_MODE_TAG) == 0)
+ {
+ IPACMDBG_H("Inside WLAN-XML\n");
+ 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, WLAN_FULL_MODE_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].wlan_mode = FULL;
+ IPACMDBG_H("Wlan-mode full(%d)\n",
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].wlan_mode);
+ }
+ else if (0 == strncasecmp(content_buf, WLAN_INTERNET_MODE_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].wlan_mode = INTERNET;
+ config->num_wlan_guest_ap++;
+ IPACMDBG_H("Wlan-mode internet(%d)\n",
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].wlan_mode);
+ }
+ }
+ }
+ 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);
+ content_buf[MAX_XML_STR_LEN-1] = '\0';
+ config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG_H("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);
+ content_buf[MAX_XML_STR_LEN-1] = '\0';
+ config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG_H("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);
+ content_buf[MAX_XML_STR_LEN-1] = '\0';
+
+ 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_H("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_H("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_H("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_H("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_H("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_H("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) ||
+ 0 == IPACM_util_icmp_string((char*)xml_node->name, FirewallEnabled_TAG) ||
+ 0 == IPACM_util_icmp_string((char*)xml_node->name, FirewallPktsAllowed_TAG))
+ {
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name, Firewall_TAG))
+ {
+ /* increase firewall entry num */
+ config->num_extd_firewall_entries++;
+ }
+
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name, FirewallPktsAllowed_TAG))
+ {
+ /* setup action of matched rules */
+ 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)==1)
+ {
+ config->rule_action_accept = true;
+ }
+ else
+ {
+ config->rule_action_accept = false;
+ }
+ IPACMDBG_H(" Allow traffic which matches rules ?:%d\n",config->rule_action_accept);
+ }
+ }
+
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name, FirewallEnabled_TAG))
+ {
+ /* setup if firewall enable or not */
+ 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)==1)
+ {
+ config->firewall_enable = true;
+ }
+ else
+ {
+ config->firewall_enable = false;
+ }
+ IPACMDBG_H(" Firewall Enable?:%d\n", config->firewall_enable);
+ }
+ }
+ /* 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_H("\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);
+ content_buf[MAX_XML_STR_LEN-1] = '\0';
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG_H("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);
+ content_buf[MAX_XML_STR_LEN-1] = '\0';
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG_H("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);
+ content_buf[MAX_XML_STR_LEN-1] = '\0';
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG_H("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);
+ content_buf[MAX_XML_STR_LEN-1] = '\0';
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG_H("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_H("\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_H("\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_H("\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));
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[0]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[0]);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[1]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[1]);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[2]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[2]);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[3]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[3]);
+
+ IPACMDBG_H("\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_H("\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));
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[0]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[0]);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[1]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[1]);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[2]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[2]);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[3]=ntohl(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[3]);
+ IPACMDBG_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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_H("\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/data-ipa-cfg-mgr/ipacm/src/IPACM_cfg.xml b/data-ipa-cfg-mgr/ipacm/src/IPACM_cfg.xml
new file mode 100644
index 0000000..9bac7a4
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_cfg.xml
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ipacm_cfg.xsd">
+ <ODUCFG>
+ <OduMode>router</OduMode>
+ <eMBMS_offload>0</eMBMS_offload>
+ </ODUCFG>
+ <IPACM>
+ <IPACMIface>
+ <Iface>
+ <Name>rndis0</Name>
+ <Category>LAN</Category>
+ </Iface>
+ <Iface>
+ <Name>ecm0</Name>
+ <Category>LAN</Category>
+ <Mode>ROUTER</Mode>
+ </Iface>
+ <Iface>
+ <Name>rmnet_data0</Name>
+ <Category>WAN</Category>
+ <Mode>ROUTER</Mode>
+ </Iface>
+ <Iface>
+ <Name>rmnet_data1</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>rmnet_data2</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>rmnet_data3</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>rmnet_data4</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>rmnet_data5</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>rmnet_data6</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>rmnet_data7</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>softap0</Name>
+ <Category>UNKNOWN</Category>
+ <WlanMode>full</WlanMode>
+ </Iface>
+ <Iface>
+ <Name>wlan0</Name>
+ <Category>UNKNOWN</Category>
+ <WlanMode>full</WlanMode>
+ </Iface>
+ <Iface>
+ <Name>wlan1</Name>
+ <Category>UNKNOWN</Category>
+ <WlanMode>full</WlanMode>
+ </Iface>
+ <Iface>
+ <Name>wlan2</Name>
+ <Category>UNKNOWN</Category>
+ <WlanMode>full</WlanMode>
+ </Iface>
+ <Iface>
+ <Name>wlan3</Name>
+ <Category>UNKNOWN</Category>
+ <WlanMode>full</WlanMode>
+ </Iface>
+ <Iface>
+ <Name>eth0</Name>
+ <Category>ODU</Category>
+ </Iface>
+ <Iface>
+ <Name>bridge0</Name>
+ <Category>VIRTUAL</Category>
+ </Iface>
+ </IPACMIface>
+ <IPPassthroughFlag>
+ <IPPassthroughMode>0</IPPassthroughMode>
+ </IPPassthroughFlag>
+ <IPACMPrivateSubnet>
+ <Subnet>
+ <SubnetAddress>192.168.225.0</SubnetAddress>
+ <SubnetMask>255.255.255.0</SubnetMask>
+ </Subnet>
+ </IPACMPrivateSubnet>
+ <IPACMALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>21</Port>
+ <Description>FTP</Description>
+ </ALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>554</Port>
+ <Description>RTSP</Description>
+ </ALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>5060</Port>
+ <Description>SIP</Description>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>5060</Port>
+ <Description>SIP</Description>
+ </ALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>1723</Port>
+ <Description>PPTP</Description>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>69</Port>
+ <Description>TFTP</Description>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>53</Port>
+ <Description>DNS</Description>
+ </ALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>53</Port>
+ <Description>DNS</Description>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>10080</Port>
+ <Description>AMANDA</Description>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>1719</Port>
+ <Description>H323</Description>
+ </ALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>1720</Port>
+ <Description>H323</Description>
+ </ALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>6667</Port>
+ <Description>IRC</Description>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>137</Port>
+ <Description>NETBIOS_NS</Description>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>138</Port>
+ <Description>NETBIOS_NS</Description>
+ </ALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>6566</Port>
+ <Description>SANE</Description>
+ </ALG>
+ </IPACMALG>
+ <IPACMNAT>
+ <MaxNatEntries>500</MaxNatEntries>
+ </IPACMNAT>
+ </IPACM>
+</system>
diff --git a/data-ipa-cfg-mgr/ipacm/src/Makefile.am b/data-ipa-cfg-mgr/ipacm/src/Makefile.am
new file mode 100644
index 0000000..92ea904
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/Makefile.am
@@ -0,0 +1,55 @@
+AM_CPPFLAGS = -I./../inc \
+ -I$(top_srcdir)/ipanat/inc \
+ ${LIBXML_CFLAGS}
+AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
+AM_CPPFLAGS += -DDEBUG -g -DFEATURE_ETH_BRIDGE_LE -DFEATURE_L2TP
+AM_CPPFLAGS += -DFEATURE_IPA_V3
+
+ipacm_SOURCES = IPACM_Main.cpp \
+ IPACM_Conntrack_NATApp.cpp\
+ IPACM_ConntrackClient.cpp \
+ IPACM_ConntrackListener.cpp \
+ IPACM_EvtDispatcher.cpp \
+ IPACM_Config.cpp \
+ IPACM_CmdQueue.cpp \
+ IPACM_Log.cpp \
+ IPACM_Filtering.cpp \
+ IPACM_Routing.cpp \
+ IPACM_Header.cpp \
+ IPACM_Lan.cpp \
+ IPACM_Iface.cpp \
+ IPACM_Wlan.cpp \
+ IPACM_Wan.cpp \
+ IPACM_IfaceManager.cpp \
+ IPACM_Neighbor.cpp \
+ IPACM_Netlink.cpp \
+ IPACM_Xml.cpp \
+ IPACM_LanToLan.cpp
+
+bin_PROGRAMS = ipacm
+
+requiredlibs = ${LIBXML_LIB} -lxml2 -lpthread -lnetfilter_conntrack -lnfnetlink\
+ ../../ipanat/src/libipanat.la
+
+AM_CPPFLAGS += "-std=c++0x"
+
+if USE_GLIB
+ipacm_CFLAGS = $(AM_CFLAGS) -DUSE_GLIB @GLIB_CFLAGS@
+ipacm_LDFLAGS = -lpthread @GLIB_LIBS@
+ipacm_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+ipacm_CFLAGS = $(AM_CFLAGS)
+ipacm_LDFLAGS = -lpthread
+ipacm_CPPFLAGS = $(AM_CPPFLAGS)
+endif
+ipacm_LDADD = $(requiredlibs)
+
+LOCAL_MODULE := libipanat
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
+
+etcdir = ${sysconfdir}
+etc_SCRIPTS = IPACM_cfg.xml
+
+init_ddir = ${sysconfdir}/init.d
+init_d_SCRIPTS = start_ipacm_le
diff --git a/data-ipa-cfg-mgr/ipacm/src/mobileap_firewall.xml b/data-ipa-cfg-mgr/ipacm/src/mobileap_firewall.xml
new file mode 100644
index 0000000..84da527
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/mobileap_firewall.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="mobileap_firewall_cfg.xsd">
+ <MobileAPFirewallCfg>
+ <FirewallEnabled>1</FirewallEnabled>
+ <FirewallPktsAllowed>0</FirewallPktsAllowed>
+ </MobileAPFirewallCfg>
+</system>
diff --git a/data-ipa-cfg-mgr/ipacm/src/start_ipacm_le b/data-ipa-cfg-mgr/ipacm/src/start_ipacm_le
new file mode 100644
index 0000000..3541a0b
--- /dev/null
+++ b/data-ipa-cfg-mgr/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