summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--configure.ac31
-rw-r--r--ipacm/inc/IPACM_CmdQueue.h108
-rw-r--r--ipacm/inc/IPACM_Config.h93
-rw-r--r--ipacm/inc/IPACM_ConntrackClient.h98
-rw-r--r--ipacm/inc/IPACM_ConntrackListener.h68
-rw-r--r--ipacm/inc/IPACM_Conntrack_NATApp.h118
-rw-r--r--ipacm/inc/IPACM_Defs.h178
-rw-r--r--ipacm/inc/IPACM_EvtDispatcher.h76
-rw-r--r--ipacm/inc/IPACM_Filtering.h69
-rw-r--r--ipacm/inc/IPACM_Header.h68
-rw-r--r--ipacm/inc/IPACM_Iface.h131
-rw-r--r--ipacm/inc/IPACM_IfaceManager.h91
-rw-r--r--ipacm/inc/IPACM_Lan.h118
-rw-r--r--ipacm/inc/IPACM_Listener.h55
-rw-r--r--ipacm/inc/IPACM_Log.h79
-rw-r--r--ipacm/inc/IPACM_Neighbor.h79
-rw-r--r--ipacm/inc/IPACM_Netlink.h221
-rw-r--r--ipacm/inc/IPACM_Routing.h75
-rw-r--r--ipacm/inc/IPACM_Wan.h110
-rw-r--r--ipacm/inc/IPACM_Wlan.h224
-rw-r--r--ipacm/inc/IPACM_Xml.h277
-rw-r--r--ipacm/src/IPACM_CmdQueue.cpp165
-rw-r--r--ipacm/src/IPACM_Config.cpp190
-rw-r--r--ipacm/src/IPACM_ConntrackClient.cpp699
-rw-r--r--ipacm/src/IPACM_ConntrackListener.cpp429
-rw-r--r--ipacm/src/IPACM_Conntrack_NATApp.cpp504
-rw-r--r--ipacm/src/IPACM_EvtDispatcher.cpp199
-rw-r--r--ipacm/src/IPACM_Filtering.cpp223
-rw-r--r--ipacm/src/IPACM_Header.cpp200
-rw-r--r--ipacm/src/IPACM_Iface.cpp598
-rw-r--r--ipacm/src/IPACM_IfaceManager.cpp242
-rw-r--r--ipacm/src/IPACM_Lan.cpp902
-rw-r--r--ipacm/src/IPACM_Log.cpp68
-rw-r--r--ipacm/src/IPACM_Main.cpp424
-rw-r--r--ipacm/src/IPACM_Neighbor.cpp252
-rw-r--r--ipacm/src/IPACM_Netlink.cpp1823
-rw-r--r--ipacm/src/IPACM_Routing.cpp226
-rw-r--r--ipacm/src/IPACM_Wan.cpp1249
-rw-r--r--ipacm/src/IPACM_Wlan.cpp1421
-rw-r--r--ipacm/src/IPACM_Xml.cpp1090
-rw-r--r--ipacm/src/IPACM_cfg.xml42
-rw-r--r--ipacm/src/Makefile.am41
-rw-r--r--ipacm/src/mobileap_firewall.xml5
-rwxr-xr-xipacm/src/start_ipacm_le57
-rw-r--r--ipanat/inc/ipa_nat_drv.h118
-rw-r--r--ipanat/inc/ipa_nat_drvi.h474
-rw-r--r--ipanat/inc/ipa_nat_logi.h79
-rw-r--r--ipanat/src/Makefile.am20
-rw-r--r--ipanat/src/ipa_nat_drv.c177
-rw-r--r--ipanat/src/ipa_nat_drvi.c2387
-rw-r--r--ipanat/src/ipa_nat_logi.c68
52 files changed, 16742 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..fab2aff
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,3 @@
+ACLOCAL_AMFLAGS = -I m4
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS = ipanat/src ipacm/src/
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..f826305
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,31 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.65])
+AC_INIT(data-ipa, 1.0.0)
+AM_INIT_AUTOMAKE(data-ipa, 1.0.0)
+AC_OUTPUT(Makefile ipanat/src/Makefile ipacm/src/Makefile)
+AC_CONFIG_SRCDIR([ipanat/src/ipa_nat_drv.c])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_CHECK_HEADERS([fcntl.h netinet/in.h sys/ioctl.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_OFF_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_MMAP
+AC_CHECK_FUNCS([memset munmap])
+
+AC_OUTPUT
diff --git a/ipacm/inc/IPACM_CmdQueue.h b/ipacm/inc/IPACM_CmdQueue.h
new file mode 100644
index 0000000..4eb4be7
--- /dev/null
+++ b/ipacm/inc/IPACM_CmdQueue.h
@@ -0,0 +1,108 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_CmdQueue.h
+
+ @brief
+ This file implements the IPAM Comment Queue definitions
+
+ @Author
+
+*/
+#ifndef IPA_CONNTRACK_MESSAGE_H
+#define IPA_CONNTRACK_MESSAGE_H
+
+#include <iostream>
+#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;
+
+ MessageQueue()
+ {
+ Head = NULL;
+ Tail = NULL;
+ }
+
+public:
+
+ ~MessageQueue() { }
+ void enqueue(Message *item);
+
+ static void* Process(void *);
+ static MessageQueue* getInstance();
+
+};
+
+#endif /* IPA_CONNTRACK_MESSAGE_H */
+
diff --git a/ipacm/inc/IPACM_Config.h b/ipacm/inc/IPACM_Config.h
new file mode 100644
index 0000000..f0d356f
--- /dev/null
+++ b/ipacm/inc/IPACM_Config.h
@@ -0,0 +1,93 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Config.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"
+
+/* iface */
+class IPACM_Config
+{
+public:
+
+ /* 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 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;
+
+ /* IPACM routing table name for v4/v6 */
+ struct ipa_ioc_get_rt_tbl rt_tbl_lan_v4, rt_tbl_wan_v4, rt_tbl_v6;
+
+ /* To return the instance */
+ static IPACM_Config* GetInstance();
+
+ inline int GetAlgPortCnt()
+ {
+ return ipa_num_alg_ports;
+ }
+
+ int GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts);
+ int GetNatMaxEntries(void)
+ {
+ return ipa_nat_max_entries;
+ }
+
+private:
+ static IPACM_Config *pInstance;
+ IPACM_Config(void);
+ int Init(void);
+
+};
+
+#endif /* IPACM_CONFIG */
diff --git a/ipacm/inc/IPACM_ConntrackClient.h b/ipacm/inc/IPACM_ConntrackClient.h
new file mode 100644
index 0000000..b125c68
--- /dev/null
+++ b/ipacm/inc/IPACM_ConntrackClient.h
@@ -0,0 +1,98 @@
+/*
+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 <iostream>
+#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>
+}
+
+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);
+ 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 *ptr);
+
+ static void UpdateUDPFilters(void *);
+ static void UpdateTCPFilters(void *);
+
+ static IPACM_ConntrackClient* GetInstance();
+
+#ifdef IPACM_DEBUG
+ static void iptodot(const char *type, uint32_t ipAddr);
+#endif
+
+};
+
+#endif /* IPACM_CONNTRACK_FILTER_H */
diff --git a/ipacm/inc/IPACM_ConntrackListener.h b/ipacm/inc/IPACM_ConntrackListener.h
new file mode 100644
index 0000000..3cea83a
--- /dev/null
+++ b/ipacm/inc/IPACM_ConntrackListener.h
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef IPACM_CONNTRACK_LISTENER
+#define IPACM_CONNTRACK_LISTENER
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.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"
+
+using namespace std;
+
+class IPACM_ConntrackListener : public IPACM_Listener
+{
+
+private:
+ bool isCTReg;
+ bool isWanUp;
+
+ void ProcessCTMessage(void *data);
+ void ProcessTCPorUDPMsg(struct nf_conntrack *ct, enum nf_conntrack_msg_type, u_int8_t);
+ void TriggerWANUp(void *);
+ void TriggerWANDown(uint32_t wan_addr);
+ int CreateNatThreads(void);
+
+public:
+ char wan_ifname[IPA_IFACE_NAME_LEN];
+ uint32_t wan_ipaddr;
+ IPACM_ConntrackListener();
+ void event_callback(ipa_cm_event_id, void *data);
+};
+
+#endif /* IPACM_CONNTRACK_LISTENER */
diff --git a/ipacm/inc/IPACM_Conntrack_NATApp.h b/ipacm/inc/IPACM_Conntrack_NATApp.h
new file mode 100644
index 0000000..3e1f5a6
--- /dev/null
+++ b/ipacm/inc/IPACM_Conntrack_NATApp.h
@@ -0,0 +1,118 @@
+/*
+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_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 IPACM_DEBUG
+
+typedef struct _nat_table_entry
+{
+ uint32_t private_ip;
+ uint16_t private_port;
+
+ uint32_t target_ip;
+ uint16_t target_port;
+
+ uint16_t public_port;
+
+ u_int8_t protocol;
+ uint32_t timestamp;
+
+ bool dst_nat;
+ uint32_t rule_hdl;
+
+}nat_table_entry;
+
+#define CHK_TBL_HDL() if(0 == nat_table_hdl){\
+ int n =0; \
+ n = snprintf(log_buf, sizeof(log_buf), "%s:%d %s() %s", __FILE__, __LINE__, __FUNCTION__, "Error:");\
+ snprintf((log_buf+n), (sizeof(log_buf)-n)-1, "Invalid table handle\n");\
+ logmessage(log_buf);\
+ }
+
+class NatApp
+{
+private:
+
+ static NatApp *pInstance;
+
+ nat_table_entry *cache;
+ uint32_t pub_ip_addr;
+ uint32_t nat_table_hdl;
+
+ int curCnt, max_entries;
+
+ ipacm_alg *pALGPorts;
+ uint16_t nALGPort;
+
+ 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);
+ 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);
+};
+
+
+
+#endif /* IPACM_CONNTRACK_NATAPP_H */
diff --git a/ipacm/inc/IPACM_Defs.h b/ipacm/inc/IPACM_Defs.h
new file mode 100644
index 0000000..19ddbec
--- /dev/null
+++ b/ipacm/inc/IPACM_Defs.h
@@ -0,0 +1,178 @@
+/*
+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_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 <linux/msm_ipa.h>
+#include "IPACM_Log.h"
+
+extern "C"
+{
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
+}
+
+
+#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 12 // dst mac first then src mac
+#define IPA_VIRTUAL_IFACE_NAME "bridge0"
+#define IPA_WLAN_PARTIAL_HDR_NAME "IEEE802_3"
+#define IPA_MAX_IFACE_ENTRIES 15
+#define IPA_MAX_PRIVATE_SUBNET_ENTRIES 3
+#define IPA_MAX_ALG_ENTRIES 10
+
+#define V4_LAN_ROUTE_TABLE_NAME "COMRTBLLANv4"
+#define V4_WAN_ROUTE_TABLE_NAME "WANRTBLv4"
+#define V6_COMMON_ROUTE_TABLE_NAME "COMRTBLv6"
+
+
+
+/*---------------------------------------------------------------------------
+ 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 15
+#define IPA_MAX_NUM_AMPDU_RULE 15
+#define IPA_MAC_ADDR_SIZE 6
+
+/*===========================================================================
+ GLOBAL DEFINITIONS AND DECLARATIONS
+===========================================================================*/
+typedef enum
+{
+ IPA_LINK_UP_EVENT = 1, /* ipacm_event_data_fid */
+ IPA_LINK_DOWN_EVENT, /* 2 ipacm_event_data_fid */
+ IPA_ADDR_ADD_EVENT, /* 3 ipacm_event_data_addr */
+ IPA_ADDR_DEL_EVENT, /* 4 no use */
+ IPA_ROUTE_ADD_EVENT, /* 5 ipacm_event_data_addr */
+ IPA_ROUTE_DEL_EVENT, /* 6 ipacm_event_data_addr */
+ IPA_FIREWALL_CHANGE_EVENT, /* 7 NULL */
+ IPA_WLAN_CLIENT_ADD_EVENT, /* 8 ipacm_event_data_mac */
+ IPA_WLAN_CLIENT_DEL_EVENT, /* 9 ipacm_event_data_mac */
+ IPA_WLAN_CLIENT_POWER_SAVE_EVENT, /* 10 ipacm_event_data_mac */
+ IPA_WLAN_CLIENT_RECOVER_EVENT, /* 11 ipacm_event_data_mac */
+ IPA_NEW_NEIGH_EVENT, /* 12 ipacm_event_data_all */
+ IPA_DEL_NEIGH_EVENT, /* 13 ipacm_event_data_all */
+ IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, /* 14 ipacm_event_data_all */
+ IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, /* 15 ipacm_event_data_all */
+ IPA_SW_ROUTING_ENABLE, /* 16 NULL */
+ IPA_SW_ROUTING_DISABLE, /* 17 NULL */
+ IPA_PROCESS_CT_MESSAGE, /* 18 ipacm_ct_evt_data */
+ IPA_HANDLE_WAN_UP, /* 19 unsigned long */
+ IPA_HANDLE_WAN_DOWN, /* 20 unsigned long */
+ IPA_HANDLE_WLAN_UP, /* 21 unsigned long */
+ IPA_HANDLE_LAN_UP /* 22 unsigned long */
+} ipa_cm_event_id;
+
+typedef enum
+{
+ LAN_IF = 0,
+ WLAN_IF,
+ WAN_IF,
+ VIRTUAL_IF
+} ipacm_iface_type;
+
+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;
+ 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[6];
+} ipacm_event_data_all;
+
+typedef struct _ipacm_event_data_fid
+{
+ int if_index;
+} ipacm_event_data_fid;
+
+typedef struct _ipacm_event_data_addr
+{
+ enum ipa_ip_type iptype;
+ int if_index;
+ uint32_t ipv4_addr;
+ uint32_t ipv4_addr_mask;
+ uint32_t ipv6_addr[4];
+ uint32_t ipv6_addr_mask[4];
+} ipacm_event_data_addr;
+
+typedef struct _ipacm_event_data_mac
+{
+ int if_index;
+ uint8_t mac_addr[6];
+} ipacm_event_data_mac;
+
+typedef struct _ipacm_event_iface_up
+{
+ char ifname[IPA_IFACE_NAME_LEN];
+ uint32_t ipv4_addr;
+ uint32_t addr_mask;
+}ipacm_event_iface_up;
+
+#endif /* IPA_CM_DEFS_H */
diff --git a/ipacm/inc/IPACM_EvtDispatcher.h b/ipacm/inc/IPACM_EvtDispatcher.h
new file mode 100644
index 0000000..550f4d4
--- /dev/null
+++ b/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/ipacm/inc/IPACM_Filtering.h b/ipacm/inc/IPACM_Filtering.h
new file mode 100644
index 0000000..2d49abf
--- /dev/null
+++ b/ipacm/inc/IPACM_Filtering.h
@@ -0,0 +1,69 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*!
+ @file
+ IPACM_Filtering.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>
+
+class IPACM_Filtering
+{
+public:
+ IPACM_Filtering();
+ ~IPACM_Filtering();
+ bool AddFilteringRule(struct ipa_ioc_add_flt_rule 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);
+
+private:
+ static const char *DEVICE_NAME;
+ int fd; /* File descriptor of the IPA device node /dev/ipa */
+};
+
+#endif //IPACM_FILTERING_H
+
diff --git a/ipacm/inc/IPACM_Header.h b/ipacm/inc/IPACM_Header.h
new file mode 100644
index 0000000..b6973cb
--- /dev/null
+++ b/ipacm/inc/IPACM_Header.h
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * 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);
+
+ IPACM_Header();
+ ~IPACM_Header();
+ bool DeviceNodeIsOpened();
+};
+
+
+#endif
+
+
diff --git a/ipacm/inc/IPACM_Iface.h b/ipacm/inc/IPACM_Iface.h
new file mode 100644
index 0000000..9e3cafd
--- /dev/null
+++ b/ipacm/inc/IPACM_Iface.h
@@ -0,0 +1,131 @@
+/*
+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_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_Netlink.h"
+#include "IPACM_Config.h"
+#include "IPACM_Defs.h"
+
+/* current support 2 ipv6-address*/
+#define MAX_DEFAULT_v6_ROUTE_RULES 2
+#define IPV4_DEFAULT_FILTERTING_RULES 3
+#define IPV6_DEFAULT_FILTERTING_RULES 1
+#define IPV6_DEFAULT_LAN_FILTERTING_RULES 1
+#define MAX_SOFTWAREROUTING_FILTERTING_RULES 2
+
+/* 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 name */
+ char dev_name[IF_NAME_LEN];
+
+ /* IPACM interface iptype v4, v6 or both */
+ ipa_ip_type ip_type;
+
+ uint32_t header_hdl;
+
+ uint32_t software_routing_fl_rule_hdl[MAX_SOFTWAREROUTING_FILTERTING_RULES];
+
+ bool softwarerouting_act;
+
+ int num_dft_rt;
+
+ 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];
+ uint32_t dft_rt_rule_hdl[1+MAX_DEFAULT_v6_ROUTE_RULES]; /* 1 for ipv4 */
+
+ 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 the IPA endpoint property */
+ int query_iface_property(void);
+
+ /*Configure the initial filter rules */
+ virtual int init_fl_rule(ipa_ip_type iptype);
+
+ 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/ipacm/inc/IPACM_IfaceManager.h b/ipacm/inc/IPACM_IfaceManager.h
new file mode 100644
index 0000000..b295658
--- /dev/null
+++ b/ipacm/inc/IPACM_IfaceManager.h
@@ -0,0 +1,91 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_IfaceManager.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_MAX_NUM_NEIGHBOR_CLIENTS 17
+#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(int if_index);
+
+ /* 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/ipacm/inc/IPACM_Lan.h b/ipacm/inc/IPACM_Lan.h
new file mode 100644
index 0000000..849e5df
--- /dev/null
+++ b/ipacm/inc/IPACM_Lan.h
@@ -0,0 +1,118 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Lan.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"
+
+#define IPA_MAX_NUM_UNICAST_ROUTE_RULES 6
+#define IPA_WAN_DEFAULT_FILTER_RULE_HANDLES 1
+#define IPA_PRIV_SUBNET_FILTER_RULE_HANDLES 3
+
+/* store each lan-iface unicast routing rule and its handler*/
+struct ipa_lan_rt_rule
+{
+ enum ipa_ip_type ip;
+ ipa_rule_attrib rule;
+ uint32_t rt_rule_hdl[0];
+};
+
+/* 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_PRIV_SUBNET_FILTER_RULE_HANDLES];
+
+ /* LAN-iface's callback function */
+ void event_callback(ipa_cm_event_id event,
+ void *data);
+
+ /* configure filter rule for wan_up event*/
+ virtual int handle_wan_up(void);
+
+ /* delete filter rule for wan_down event*/
+ virtual int handle_wan_down(void);
+
+ /* 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);
+
+private:
+
+ /* dynamically allocate lan iface's unicast routing rule structure */
+ int rt_rule_len;
+ ipa_lan_rt_rule *route_rule;
+
+ /* store the number of lan-iface's unicast routing rule */
+ int num_uni_rt;
+
+ inline ipa_lan_rt_rule* get_rt_ruleptr(ipa_lan_rt_rule *param, int cnt)
+ {
+ return (param + (rt_rule_len * cnt));
+ }
+
+ /* handle unicast routing rule add event */
+ int handle_route_add_evt(ipacm_event_data_addr *data);
+
+ /* handle unicast routing rule del event */
+ int handle_route_del_evt(ipacm_event_data_addr *data);
+
+ /*handle wlan iface down event*/
+ int handle_down_evt();
+
+};
+
+#endif /* IPACM_LAN_H */
diff --git a/ipacm/inc/IPACM_Listener.h b/ipacm/inc/IPACM_Listener.h
new file mode 100644
index 0000000..02a082e
--- /dev/null
+++ b/ipacm/inc/IPACM_Listener.h
@@ -0,0 +1,55 @@
+/*
+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;
+};
+
+#endif /* IPACM_LISTENER_H */
+
diff --git a/ipacm/inc/IPACM_Log.h b/ipacm/inc/IPACM_Log.h
new file mode 100644
index 0000000..785b654
--- /dev/null
+++ b/ipacm/inc/IPACM_Log.h
@@ -0,0 +1,79 @@
+/*
+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>
+
+#define LOG_SIZE 200
+
+#define PERROR(fmt) printf("%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
+ perror(fmt);
+
+#define IPACMDBG(fmt, ...) {\
+ int n =0; \
+ n = snprintf(log_buf, sizeof(log_buf), "%s:%d %s() ", __FILE__, __LINE__, __FUNCTION__);\
+ snprintf((log_buf+n), (sizeof(log_buf)-n-1), fmt, ##__VA_ARGS__);\
+ logmessage(log_buf);\
+ }
+
+
+#define IPACMERR(fmt, ...) {\
+ int n =0; \
+ n = snprintf(log_buf, sizeof(log_buf), "%s:%d %s() %s", __FILE__, __LINE__, __FUNCTION__, "Error:");\
+ snprintf((log_buf+n), (sizeof(log_buf)-n-1), fmt, ##__VA_ARGS__);\
+ logmessage(log_buf);\
+ }
+
+extern void logmessage(char *msg);
+extern char log_buf[LOG_SIZE];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPACM_LOG_H */
diff --git a/ipacm/inc/IPACM_Neighbor.h b/ipacm/inc/IPACM_Neighbor.h
new file mode 100644
index 0000000..af7ab46
--- /dev/null
+++ b/ipacm/inc/IPACM_Neighbor.h
@@ -0,0 +1,79 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Neighbor.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 17
+
+struct ipa_neighbor_client
+{
+ uint8_t mac_addr[6];
+ uint32_t v6_addr[4];
+ int iface_index;
+};
+
+class IPACM_Neighbor : public IPACM_Listener
+{
+
+public:
+
+ IPACM_Neighbor();
+
+ void event_callback(ipa_cm_event_id event,
+ void *data);
+
+private:
+
+ int num_neighbor_client;
+
+ ipa_neighbor_client neighbor_client[IPA_MAX_NUM_NEIGHBOR_CLIENTS];
+
+
+};
+
+#endif /* IPACM_NEIGHBOR_H */
diff --git a/ipacm/inc/IPACM_Netlink.h b/ipacm/inc/IPACM_Netlink.h
new file mode 100644
index 0000000..fe98375
--- /dev/null
+++ b/ipacm/inc/IPACM_Netlink.h
@@ -0,0 +1,221 @@
+/*
+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 (1024)
+#define IF_NAME_LEN 16
+
+
+/*---------------------------------------------------------------------------
+ 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;
+ } 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/ipacm/inc/IPACM_Routing.h b/ipacm/inc/IPACM_Routing.h
new file mode 100644
index 0000000..ca7a5fd
--- /dev/null
+++ b/ipacm/inc/IPACM_Routing.h
@@ -0,0 +1,75 @@
+/*
+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 PutRoutingTable(uint32_t routingTableHandle);
+
+ bool DeviceNodeIsOpened();
+ bool DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip);
+
+private:
+ static const char *DEVICE_NAME;
+ int m_fd; /* File descriptor of the IPA device node /dev/ipa */
+};
+
+#endif //IPACM_ROUTING_H
+
diff --git a/ipacm/inc/IPACM_Wan.h b/ipacm/inc/IPACM_Wan.h
new file mode 100644
index 0000000..5177fe1
--- /dev/null
+++ b/ipacm/inc/IPACM_Wan.h
@@ -0,0 +1,110 @@
+/*
+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 2
+
+/* wan iface */
+class IPACM_Wan : public IPACM_Iface
+{
+
+public:
+
+ static bool wan_up;
+
+ IPACM_Wan(int iface_index);
+ ~IPACM_Wan();
+
+ static bool isWanUP()
+ {
+ return wan_up;
+ }
+
+ void event_callback(ipa_cm_event_id event,
+ void *data);
+
+private:
+ uint32_t *wan_route_rule_v4_hdl;
+ uint32_t *wan_route_rule_v6_hdl;
+ 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];
+ int num_firewall_v4,num_firewall_v6;
+ bool active_v4;
+ bool active_v6;
+ uint32_t wan_v4_addr;
+
+ /* IPACM firewall Configuration file*/
+ IPACM_firewall_conf_t firewall_config;
+
+ /* handle new_address event */
+ int handle_addr_evt(ipacm_event_data_addr *data);
+
+ /* wan default route/filter rule configuration */
+ int handle_route_add_evt(ipacm_event_data_addr *data);
+
+ /* wan default route/filter rule delete */
+ int handle_route_del_evt(ipa_ip_type iptype);
+
+ /* construct complete ethernet header */
+ int handle_header_add_evt(uint8_t mac_addr[6]);
+
+ /* configure the initial firewall filter rules */
+ int config_dft_firewall_rules(ipa_ip_type ip_type);
+
+ /*clean firewall filter rules */
+ int del_dft_firewall_rules(ipa_ip_type ip_type);
+
+ /*handle wan-iface down event */
+ int handle_down_evt();
+
+};
+
+#endif /* IPACM_WAN_H */
diff --git a/ipacm/inc/IPACM_Wlan.h b/ipacm/inc/IPACM_Wlan.h
new file mode 100644
index 0000000..0535584
--- /dev/null
+++ b/ipacm/inc/IPACM_Wlan.h
@@ -0,0 +1,224 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Wlan.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"
+
+typedef struct _wlan_client_rt_hdl
+{
+ uint32_t wifi_rt_rule_hdl_v4;
+ uint32_t wifi_rt_rule_hdl_v6;
+}wlan_client_rt_hdl;
+
+typedef struct _ipa_wlan_client
+{
+ uint8_t mac[IPA_MAC_ADDR_SIZE];
+ uint32_t v4_addr;
+ uint32_t v6_addr[4];
+ uint32_t hdr_hdl;
+ bool route_rule_set_v4;
+ bool route_rule_set_v6;
+ bool ipv4_set;
+ bool ipv6_set;
+ wlan_client_rt_hdl wifi_rt_hdl[0]; /* depends on number of tx properties */
+}ipa_wlan_client;
+
+typedef struct _wlan_ampdu_flt_rules
+{
+ uint32_t hdl[IPA_MAX_NUM_AMPDU_RULE];
+ ipa_ip_type ip[IPA_MAX_NUM_AMPDU_RULE];
+ int num_rules;
+}wlan_ampdu_flt_rules;
+
+
+
+/* wlan iface */
+class IPACM_Wlan : public IPACM_Lan
+{
+
+public:
+
+ IPACM_Wlan(int iface_index);
+ ~IPACM_Wlan(void);
+
+ static int total_num_wifi_clients;
+
+ void event_callback(ipa_cm_event_id event,
+ void *data);
+
+private:
+ int wlan_client_len;
+ ipa_wlan_client *wlan_client;
+
+ int header_name_count;
+ int num_wifi_client;
+ wlan_ampdu_flt_rules wlan_ampdu_flt_rule;
+
+ inline ipa_wlan_client* get_client_memptr(ipa_wlan_client *param, int cnt)
+ {
+ return (param + (wlan_client_len * cnt));
+ }
+
+ inline int get_wlan_client_index(uint8_t *mac_addr)
+ {
+ int cnt;
+ int num_wifi_client_tmp = num_wifi_client;
+
+ IPACMDBG("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("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("Matched client index: %d\n", cnt);
+ return cnt;
+ }
+ }
+
+ return IPACM_INVALID_INDEX;
+ }
+
+ inline int delete_default_qos_rtrules(int clt_indx)
+ {
+ uint32_t tx_index;
+ uint32_t rt_hdl;
+
+ for(tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if((ip_type != IPA_IP_v6) && (get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4==true)) /* for ipv4 */
+ {
+ IPACMDBG("Delete client index %d ipv4 Qos rules \n", clt_indx);
+ 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;
+ }
+ }
+
+ if((ip_type != IPA_IP_v4) && (get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6==true)) /* for ipv6 */
+ {
+ IPACMDBG("Delete client index %d ipv6 Qos rules \n", clt_indx);
+ rt_hdl = get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6;
+
+ if(m_routing.DeleteRoutingHdl(rt_hdl, IPA_IP_v6) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+
+ } /* end of for loop */
+
+ /* clean the 4 Qos ipv4 RT rules for client:clt_indx */
+ if(ip_type != IPA_IP_v6) /* for ipv4 */
+ {
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4=false;
+ }
+
+ /* clean the 4 Qos ipv6 RT rules for client:clt_indx */
+ if(ip_type != IPA_IP_v4) /* for ipv6 */
+ {
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6=false;
+ }
+
+ return IPACM_SUCCESS;
+ }
+
+ /* handle wifi client initial,copy all partial headers (tx property) */
+ int handle_wlan_client_init(uint8_t *mac_addr);
+
+ /*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);
+
+ /*duplicate ampdu filter rules for private subnet configuration*/
+ int handle_private_subnet(ipa_ip_type iptype);
+
+ /*duplicate ampdu filter rules for initial iface configuration*/
+ int init_fl_rule(ipa_ip_type iptype);
+
+ /*duplicate ampdu filter rules for new_address event*/
+ int handle_addr_evt(ipacm_event_data_addr *data);
+
+ /*duplicate ampdu filter rules for wan_up event*/
+ int handle_wan_up(void);
+
+ /*delete ampdu filter rules for wan_down event*/
+ int handle_wan_down(void);
+
+ /*duplicate ampdu filter rules for software_routing event*/
+ int handle_software_routing_enable(void);
+
+ /*delete ampdu filter rules for disabling software_routing event*/
+ int handle_software_routing_disable(void);
+
+ /*handle wlan iface down event*/
+ int handle_down_evt();
+};
+
+
+#endif /* IPACM_WLAN_H */
diff --git a/ipacm/inc/IPACM_Xml.h b/ipacm/inc/IPACM_Xml.h
new file mode 100644
index 0000000..84f6c6f
--- /dev/null
+++ b/ipacm/inc/IPACM_Xml.h
@@ -0,0 +1,277 @@
+/*
+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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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"
+
+#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 IPACMCFG_TAG "IPACM"
+#define IPACMIFACECFG_TAG "IPACMIface"
+#define IFACE_TAG "Iface"
+#define NAME_TAG "Name"
+#define CATEGORY_TAG "Category"
+#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 VIRTUALIF_TAG "VIRTUAL"
+#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 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"
+
+
+/*---------------------------------------------------------------------------
+ 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];
+} 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;
+} 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/ipacm/src/IPACM_CmdQueue.cpp b/ipacm/src/IPACM_CmdQueue.cpp
new file mode 100644
index 0000000..632ae5d
--- /dev/null
+++ b/ipacm/src/IPACM_CmdQueue.cpp
@@ -0,0 +1,165 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_CmdQueue.cpp
+
+ @brief
+ This file implements the IPAM Comment Queue functionality
+
+ @Author
+ Sunil
+
+*/
+#include <string.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Log.h"
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
+
+MessageQueue* MessageQueue::inst = NULL;
+MessageQueue* MessageQueue::getInstance()
+{
+ if(inst == NULL)
+ {
+ inst = new MessageQueue();
+ if(inst == NULL)
+ {
+ IPACMERR("unable to create Message Queue instance\n");
+ return NULL;
+ }
+ }
+
+ return inst;
+}
+
+void MessageQueue::enqueue(Message *item)
+{
+ if(!Head)
+ {
+ Tail = item;
+ Head = item;
+ }
+ else
+ {
+ if(Tail == NULL)
+ {
+ IPACMDBG("Tail is null\n");
+ Head->setnext(item);
+ }
+ else
+ {
+ Tail->setnext(item);
+ }
+ Tail = item;
+ }
+}
+
+
+Message* MessageQueue::dequeue(void)
+{
+ if(Head == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ Message *tmp = Head;
+ Head = Head->getnext();
+
+ return tmp;
+ }
+}
+
+
+void* MessageQueue::Process(void *param)
+{
+ MessageQueue *MsgQueue = NULL;
+ Message *item = NULL;
+ IPACMDBG("MessageQueue::Process()\n");
+
+ MsgQueue = MessageQueue::getInstance();
+ if(MsgQueue == NULL)
+ {
+ IPACMDBG("unable to start cmd queue process\n");
+ return NULL;
+ }
+
+ while(1)
+ {
+ if(pthread_mutex_lock(&mutex) != 0)
+ {
+ IPACMERR("unable to lock the mutex\n");
+ return NULL;
+ }
+
+ item = MsgQueue->dequeue();
+
+ if(item == NULL)
+ {
+ IPACMDBG("Waiting for Message\n");
+
+ if(pthread_cond_wait(&cond_var, &mutex) != 0)
+ {
+ IPACMERR("unable to lock the mutex\n");
+
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return NULL;
+ }
+
+ return NULL;
+ }
+
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return NULL;
+ }
+
+ }
+ else
+ {
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return NULL;
+ }
+
+ IPACMDBG("Processing item %p\n",item);
+ item->evt.callback_ptr(&item->evt.data);
+ delete item;
+ item = NULL;
+ }
+
+ } /* Go forever until a termination indication is received */
+
+}
diff --git a/ipacm/src/IPACM_Config.cpp b/ipacm/src/IPACM_Config.cpp
new file mode 100644
index 0000000..413d1ba
--- /dev/null
+++ b/ipacm/src/IPACM_Config.cpp
@@ -0,0 +1,190 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Config.cpp
+
+ @brief
+ This file implements the IPACM Configuration from XML file
+
+ @Author
+ Skylar Chang
+
+*/
+#include <IPACM_Config.h>
+#include <IPACM_Log.h>
+#include <IPACM_Iface.h>
+
+IPACM_Config *IPACM_Config::pInstance = NULL;
+
+IPACM_Config::IPACM_Config()
+{
+ iface_table = NULL;
+ alg_table = NULL;
+ memset(&private_subnet_table, 0, sizeof(private_subnet_table));
+
+ ipa_num_ipa_interfaces = 0;
+ ipa_num_private_subnet = 0;
+ ipa_num_alg_ports = 0;
+ ipa_nat_max_entries = 0;
+
+ memset(&rt_tbl_lan_v4, 0, sizeof(rt_tbl_lan_v4));
+ memset(&rt_tbl_wan_v4, 0, sizeof(rt_tbl_wan_v4));
+ memset(&rt_tbl_v6, 0, sizeof(rt_tbl_v6));
+
+ IPACMDBG(" create IPACM_Config constructor\n");
+ return;
+}
+
+int IPACM_Config::Init(void)
+{
+ /* Read IPACM Config file */
+ char IPACM_config_file[IPA_MAX_FILE_LEN];
+ IPACM_conf_t *cfg;
+ cfg = (IPACM_conf_t *)malloc(sizeof(IPACM_conf_t));
+ uint32_t subnet_addr;
+ uint32_t subnet_mask;
+ int i, ret = IPACM_SUCCESS;
+
+ strncpy(IPACM_config_file, "/etc/IPACM_cfg.xml", sizeof(IPACM_config_file));
+
+
+ IPACMDBG("\n IPACM XML file is %s \n", IPACM_config_file);
+ if (IPACM_SUCCESS == ipacm_read_cfg_xml(IPACM_config_file, cfg))
+ {
+ IPACMDBG("\n IPACM XML read OK \n");
+ }
+ else
+ {
+ IPACMERR("\n IPACM XML read failed \n");
+ ret = IPACM_FAILURE;
+ goto fail;
+ }
+
+ /* Construct IPACM Iface table */
+ ipa_num_ipa_interfaces = cfg->iface_config.num_iface_entries;
+ iface_table = (ipa_ifi_dev_name_t *)calloc(ipa_num_ipa_interfaces,
+ sizeof(ipa_ifi_dev_name_t));
+
+ for (i = 0; i < cfg->iface_config.num_iface_entries; i++)
+ {
+ strncpy(iface_table[i].iface_name, cfg->iface_config.iface_entries[i].iface_name, sizeof(iface_table[i].iface_name));
+ iface_table[i].if_cat = cfg->iface_config.iface_entries[i].if_cat;
+ IPACMDBG("IPACM_Config::iface_table[%d] = %s, cat=%d\n", i, iface_table[i].iface_name, iface_table[i].if_cat);
+ }
+
+ /* Construct IPACM Private_Subnet table */
+ ipa_num_private_subnet = cfg->private_subnet_config.num_subnet_entries;
+
+ for (i = 0; i < cfg->private_subnet_config.num_subnet_entries; i++)
+ {
+ memcpy(&private_subnet_table[i].subnet_addr,
+ &cfg->private_subnet_config.private_subnet_entries[i].subnet_addr,
+ sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_addr));
+
+ memcpy(&private_subnet_table[i].subnet_mask,
+ &cfg->private_subnet_config.private_subnet_entries[i].subnet_mask,
+ sizeof(cfg->private_subnet_config.private_subnet_entries[i].subnet_mask));
+
+ subnet_addr = htonl(private_subnet_table[i].subnet_addr);
+ IPACMDBG("%dst::private_subnet_table= %s \n ", i,
+ inet_ntoa(*(struct in_addr *)&(subnet_addr)));
+
+ subnet_mask = htonl(private_subnet_table[i].subnet_mask);
+ IPACMDBG("%dst::private_subnet_table= %s \n ", i,
+ inet_ntoa(*(struct in_addr *)&(subnet_mask)));
+ }
+
+ /* Construct IPACM ALG table */
+ ipa_num_alg_ports = cfg->alg_config.num_alg_entries;
+ alg_table = (ipacm_alg *)calloc(ipa_num_alg_ports,
+ sizeof(ipacm_alg));
+
+ for (i = 0; i < cfg->alg_config.num_alg_entries; i++)
+ {
+ //strncpy(alg_table[i].protocol, cfg->alg_config.alg_entries[i].protocol, sizeof(alg_table[i].protocol));
+ alg_table[i].protocol = cfg->alg_config.alg_entries[i].protocol;
+ alg_table[i].port = cfg->alg_config.alg_entries[i].port;
+ IPACMDBG("IPACM_Config::ipacm_alg[%d] = %d, port=%d\n", i, alg_table[i].protocol, alg_table[i].port);
+ }
+
+ ipa_nat_max_entries = cfg->nat_max_entries;
+ IPACMDBG("Nat Maximum Entries %d\n", ipa_nat_max_entries);
+
+ /* Construct the routing table ictol name in iface static member*/
+ rt_tbl_lan_v4.ip = IPA_IP_v4;
+ strncpy(rt_tbl_lan_v4.name, V4_LAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_lan_v4.name));
+
+ rt_tbl_v6.ip = IPA_IP_v6;
+ strncpy(rt_tbl_v6.name, V6_COMMON_ROUTE_TABLE_NAME, sizeof(rt_tbl_v6.name));
+
+ rt_tbl_wan_v4.ip = IPA_IP_v4;
+ strncpy(rt_tbl_wan_v4.name, V4_WAN_ROUTE_TABLE_NAME, sizeof(rt_tbl_wan_v4.name));
+
+fail:
+ free(cfg);
+
+ return ret;
+}
+
+IPACM_Config* IPACM_Config::GetInstance()
+{
+ int res = IPACM_SUCCESS;
+
+ if (pInstance == NULL)
+ {
+ pInstance = new IPACM_Config();
+
+ res = pInstance->Init();
+ if (res != IPACM_SUCCESS)
+ {
+ delete pInstance;
+ return NULL;
+ }
+ }
+
+ return pInstance;
+}
+
+int IPACM_Config::GetAlgPorts(int nPorts, ipacm_alg *pAlgPorts)
+{
+ if (nPorts <= 0 || pAlgPorts == NULL)
+ {
+ IPACMERR("Invalid input\n");
+ return -1;
+ }
+
+ for (int cnt = 0; cnt < nPorts; cnt++)
+ {
+ pAlgPorts[cnt].protocol = alg_table[cnt].protocol;
+ pAlgPorts[cnt].port = alg_table[cnt].port;
+ }
+
+ return 0;
+}
diff --git a/ipacm/src/IPACM_ConntrackClient.cpp b/ipacm/src/IPACM_ConntrackClient.cpp
new file mode 100644
index 0000000..7e48822
--- /dev/null
+++ b/ipacm/src/IPACM_ConntrackClient.cpp
@@ -0,0 +1,699 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <iostream>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_Log.h"
+
+#define LO_NAME "lo"
+
+extern IPACM_EvtDispatcher cm_dis;
+
+IPACM_ConntrackClient *IPACM_ConntrackClient::pInstance = NULL;
+IPACM_ConntrackListener *ct = new IPACM_ConntrackListener();
+
+/* ================================
+ Local Function Definitions
+ =================================
+*/
+#ifdef IPACM_DEBUG
+void IPACM_ConntrackClient::iptodot(const char *type, uint32_t ipAddr)
+{
+ int i;
+ unsigned char octet[4] = { 0 };
+ IPACMDBG("Received IPv4 addr: 0x%x\n", ipAddr);
+
+ for(i = 0; i < 4; i++)
+ {
+ octet[i] = (ipAddr >> (i * 8)) & 0xFF;
+ }
+
+ IPACMDBG("%s:", type);
+ IPACMDBG("%d.%d.%d.%d\n", octet[3], octet[2], octet[1], octet[0]);
+}
+#endif
+
+IPACM_ConntrackClient::IPACM_ConntrackClient()
+{
+ IPACMDBG("%s %d", __FUNCTION__, __LINE__);
+
+ tcp_hdl = NULL;
+ udp_hdl = NULL;
+ tcp_filter = NULL;
+ udp_filter = NULL;
+}
+
+IPACM_ConntrackClient* IPACM_ConntrackClient::GetInstance()
+{
+ if(pInstance == NULL)
+ {
+ pInstance = new IPACM_ConntrackClient();
+ }
+
+ return pInstance;
+}
+
+int IPACM_ConntrackClient::IPAConntrackEventCB
+(
+ enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ void *data
+ )
+{
+ ipacm_cmd_q_data evt_data;
+ ipacm_ct_evt_data *ct_data;
+
+ IPACMDBG("Event callback called with msgtype: %d\n",type);
+
+ ct_data = (ipacm_ct_evt_data *)malloc(sizeof(ipacm_ct_evt_data));
+ if(ct_data == NULL)
+ {
+ IPACMERR("unable to allocate memory \n");
+ return -1;
+ }
+
+ ct_data->ct = ct;
+ ct_data->type = type;
+
+ evt_data.event = IPA_PROCESS_CT_MESSAGE;
+ evt_data.evt_data = (void *)ct_data;
+
+ if(0 != IPACM_EvtDispatcher::PostEvt(&evt_data))
+ {
+ IPACMERR("Error sending Conntrack message to processing thread!\n");
+ free(ct_data);
+ }
+
+#if 0
+ IPACMDBG("Posted message to Cmd Queue\n");
+#endif
+
+ /* NFCT_CB_STOLEN means that the conntrack object is not released after the
+ callback That must be manually done later when the object is no longer needed. */
+ return NFCT_CB_STOLEN;
+}
+
+
+/* Function which sets up filters to ignore
+ connections to and from local interfaces */
+int IPACM_ConntrackClient::IPA_Conntrack_Filters_Ignore_Local_Addrs
+(
+ struct nfct_filter *filter
+)
+{
+ char buf[1024];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ int i, sck, nInterfaces;
+ struct nfct_filter_ipv4 filter_ipv4;
+
+ /* ignore whatever is destined to or originates from broadcast ip address */
+ filter_ipv4.addr = 0xffffffff;
+ filter_ipv4.mask = 0xffffffff;
+
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+
+
+ /* Get a socket handle. */
+ sck = socket(AF_INET, SOCK_DGRAM, 0);
+ if(sck < 0)
+ {
+ PERROR("socket");
+ return -1;
+ }
+
+ /* Query available interfaces. */
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+
+ /* get iface list */
+ if(ioctl(sck, SIOCGIFCONF, &ifc) < 0)
+ {
+ PERROR("ioctl(SIOCGIFCONF)");
+ return -1;
+ }
+
+ /* Iterate through the list of interfaces. */
+ ifr = ifc.ifc_req;
+ nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
+
+#ifdef IPACM_DEBUG
+ IPACMDBG("====Printing Local Interfaces=====\n");
+#endif
+
+ for(i = 0; i < nInterfaces; i++)
+ {
+ /* Interface request structure */
+ struct ifreq *item = &ifr[i];
+
+#ifdef IPACM_DEBUG
+ /* Show the device name and IP address */
+ if(item->ifr_name != NULL)
+ {
+ IPACMDBG("%s: IP %s\n",
+ item->ifr_name,
+ inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr));
+ }
+#endif
+
+ /* Convert data to host-byte order */
+ filter_ipv4.addr =
+ ntohl(inet_addr(inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr)));
+ filter_ipv4.mask = 0xffffffff;
+
+ /* ignore whatever is destined to or originates from local interfaces */
+ if(item->ifr_name != NULL)
+ {
+ if(strncmp(ct->wan_ifname, item->ifr_name, strlen(item->ifr_name)) != 0)
+ {
+ IPACMDBG("ignore connections destinated to interface %s\n", item->ifr_name);
+ IPACM_ConntrackClient::iptodot("with ipv4 address:", filter_ipv4.addr);
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+ }
+ }
+
+ IPACMDBG("ignore connections orignated to interface %s\n", item->ifr_name);
+ IPACM_ConntrackClient::iptodot("with ipv4 address:", filter_ipv4.addr);
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+
+ /* Find broadcast address for non lo interfaces */
+ if(strncmp(LO_NAME, item->ifr_name, 2) != 0)
+ {
+ /* Get the broadcast address */
+ if(ioctl(sck, SIOCGIFBRDADDR, item) < 0)
+ {
+ PERROR("broadcast address error: ioctl(SIOCGIFBRDADDR)");
+ return -1;
+ }
+
+#ifdef IPACM_DEBUG
+ /* Show the device name and IP address */
+ if(item->ifr_name != NULL)
+ {
+ IPACMDBG("%s: BroadCast IP %s\n",
+ item->ifr_name,
+ inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr));
+ }
+#endif
+
+ /* Convert data to host-byte order */
+ filter_ipv4.addr =
+ ntohl(inet_addr(inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr)));
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACMDBG("ignore connections destinated to interface %s broadcast\n", item->ifr_name);
+ IPACM_ConntrackClient::iptodot("with ipv4 address:", filter_ipv4.addr);
+ nfct_filter_set_logic(filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+ }
+
+ }
+
+ close(sck);
+ return 0;
+} /* IPA_Conntrack_Filters_Ignore_Local_Addrs() */
+
+/* Initialize TCP Filter */
+int IPACM_ConntrackClient::IPA_Conntrack_TCP_Filter_Init(void)
+{
+ int ret = 0;
+ IPACM_ConntrackClient *pClient;
+
+ IPACMDBG("\n");
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to get conntrack client instance\n");
+ return -1;
+ }
+
+ ret = IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->tcp_filter);
+ if(ret == -1)
+ {
+ IPACMERR("Unable to set local addr filters\n");
+ return -1;
+ }
+
+ ret = nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ if(ret == -1)
+ {
+ IPACMERR("Unable to set filter logic\n");
+ return -1;
+ }
+
+ /* set protocol filters as tcp and udp */
+ nfct_filter_add_attr_u32(pClient->tcp_filter, NFCT_FILTER_L4PROTO, IPPROTO_TCP);
+
+
+ struct nfct_filter_proto tcp_proto_state;
+ tcp_proto_state.proto = IPPROTO_TCP;
+ tcp_proto_state.state = TCP_CONNTRACK_ESTABLISHED;
+
+ ret = nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO_STATE,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ if(ret == -1)
+ {
+ IPACMERR("unable to set filter logic\n");
+ return -1;
+ }
+ nfct_filter_add_attr(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO_STATE,
+ &tcp_proto_state);
+
+
+ tcp_proto_state.proto = IPPROTO_TCP;
+ tcp_proto_state.state = TCP_CONNTRACK_FIN_WAIT;
+ ret = nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO_STATE,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ if(ret == -1)
+ {
+ IPACMERR("unable to set filter logic\n");
+ return -1;
+ }
+
+ nfct_filter_add_attr(pClient->tcp_filter,
+ NFCT_FILTER_L4PROTO_STATE,
+ &tcp_proto_state);
+ return 0;
+}
+
+
+/* Initialize UDP Filter */
+int IPACM_ConntrackClient::IPA_Conntrack_UDP_Filter_Init(void)
+{
+ int ret = 0;
+ IPACM_ConntrackClient *pClient = IPACM_ConntrackClient::GetInstance();
+
+ ret = IPA_Conntrack_Filters_Ignore_Local_Addrs(pClient->udp_filter);
+ if(ret == -1)
+ {
+ IPACMERR("Unable to set local addr filters\n");
+ return -1;
+ }
+
+ ret = nfct_filter_set_logic(pClient->udp_filter,
+ NFCT_FILTER_L4PROTO,
+ NFCT_FILTER_LOGIC_POSITIVE);
+ if(ret == -1)
+ {
+ IPACMERR("unable to set filter logic\n");
+ }
+ /* set protocol filters as tcp and udp */
+ nfct_filter_add_attr_u32(pClient->udp_filter, NFCT_FILTER_L4PROTO, IPPROTO_UDP);
+
+ return 0;
+}
+
+void* IPACM_ConntrackClient::UDPConnTimeoutUpdate(void *ptr)
+{
+
+#ifdef IPACM_DEBUG
+ IPACMDBG("\n");
+#endif
+
+ while(1)
+ {
+ NatApp::GetInstance()->UpdateUDPTimeStamp();
+ sleep(UDP_TIMEOUT_UPDATE);
+ } /* end of while(1) loop */
+
+#ifdef IPACM_DEBUG
+ IPACMDBG("Returning from %s() %d\n", __FUNCTION__, __LINE__);
+#endif
+
+ return NULL;
+}
+
+/* Thread to initialize TCP Conntrack Filters*/
+void* IPACM_ConntrackClient::TCPRegisterWithConnTrack(void *)
+{
+ int ret;
+ IPACM_ConntrackClient *pClient;
+
+ IPACMDBG("\n");
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to get conntrack client instance\n");
+ return -1;
+ }
+
+ pClient->tcp_hdl = nfct_open(CONNTRACK, NF_NETLINK_CONNTRACK_UPDATE);
+ if(pClient->tcp_hdl == NULL)
+ {
+ PERROR("nfct_open\n");
+ return NULL;
+ }
+
+ /* Allocate new filter */
+ pClient->tcp_filter = nfct_filter_create();
+ if(pClient->tcp_filter == NULL)
+ {
+ IPACMERR("unable to create TCP filter\n");
+ return NULL;
+ }
+
+ /* Initialize the filter */
+ ret = IPA_Conntrack_TCP_Filter_Init();
+ if(ret == -1)
+ {
+ IPACMERR("Unable to initliaze TCP Filter\n");
+ return NULL;
+ }
+
+ /* Attach the filter to net filter handler */
+ ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl),
+ pClient->tcp_filter);
+ if(ret == -1)
+ {
+ IPACMDBG("unable to attach TCP filter\n");
+ return NULL;
+ }
+
+ /* Register callback with netfilter handler */
+ IPACMDBG("tcp handle:%p, fd:%d\n", pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl));
+ nfct_callback_register(pClient->tcp_hdl, NFCT_T_UPDATE, IPAConntrackEventCB, NULL);
+
+ /* Block to catch events from net filter connection track */
+ /* nfct_catch() receives conntrack events from kernel-space, by default it
+ blocks waiting for events. */
+ IPACMDBG("Waiting for events\n");
+
+ ret = nfct_catch(pClient->tcp_hdl);
+ if(ret == -1)
+ {
+ IPACMERR("(%d)(%s)\n", ret, strerror(errno));
+ return NULL;
+ }
+
+ IPACMDBG("Exit from tcp thread\n");
+
+ /* destroy the filter.. this will not detach the filter */
+ nfct_filter_destroy(pClient->tcp_filter);
+ pClient->tcp_filter = NULL;
+
+ /* de-register the callback */
+ nfct_callback_unregister(pClient->tcp_hdl);
+ /* close the handle */
+ nfct_close(pClient->tcp_hdl);
+ pClient->tcp_hdl = NULL;
+
+ pthread_exit(NULL);
+ return NULL;
+}
+
+/* Thread to initialize UDP Conntrack Filters*/
+void* IPACM_ConntrackClient::UDPRegisterWithConnTrack(void *)
+{
+ int ret;
+ IPACM_ConntrackClient *pClient = NULL;
+
+ IPACMDBG("\n");
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to retrieve instance of conntrack client\n");
+ return NULL;
+ }
+
+ pClient->udp_hdl = nfct_open(CONNTRACK,
+ NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
+ if(pClient->udp_hdl == NULL)
+ {
+ PERROR("nfct_open\n");
+ return NULL;
+ }
+
+ /* Add filter */
+ //struct nfct_filter *udp_filter = NULL;
+
+ /* Allocate new filter */
+ pClient->udp_filter = nfct_filter_create();
+ if(pClient->udp_filter == NULL)
+ {
+ IPACMERR("unable to create UDP filter\n");
+ return NULL;
+ }
+
+ /* Initialize Filter */
+ ret = IPA_Conntrack_UDP_Filter_Init();
+ if(-1 == ret)
+ {
+ IPACMDBG("Unable to initalize udp filters\n");
+ return NULL;
+ }
+
+ /* Attach the filter to net filter handler */
+ ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
+ if(ret == -1)
+ {
+ IPACMDBG("unable to attach the filter\n");
+ return NULL;
+ }
+
+ /* Register callback with netfilter handler */
+ IPACMDBG("udp handle:%p, fd:%d\n", pClient->udp_hdl, nfct_fd(pClient->udp_hdl));
+ nfct_callback_register(pClient->udp_hdl,
+ (nf_conntrack_msg_type)(NFCT_T_NEW | NFCT_T_DESTROY),
+ IPAConntrackEventCB,
+ NULL);
+
+ /* Block to catch events from net filter connection track */
+ ret = nfct_catch(pClient->udp_hdl);
+ if(ret == -1)
+ {
+ IPACMDBG("(%d)(%s)\n", ret, strerror(errno));
+ return NULL;
+ }
+
+
+ IPACMDBG("Exit from udp thread\n");
+
+ /* destroy the filter.. this will not detach the filter */
+ nfct_filter_destroy(pClient->udp_filter);
+ pClient->udp_filter = NULL;
+
+ /* de-register the callback */
+ nfct_callback_unregister(pClient->udp_hdl);
+ /* close the handle */
+ nfct_close(pClient->udp_hdl);
+ pClient->udp_hdl = NULL;
+
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void IPACM_ConntrackClient::UpdateUDPFilters(void *param)
+{
+ int ret = 0;
+ struct nfct_filter_ipv4 filter_ipv4;
+ IPACM_ConntrackClient *pClient = NULL;
+
+ /* Intialize with 255.255.255.255 */
+ uint32_t bc_ip_addr = 0xFFFFFFFF;
+
+ uint32_t ipv4_addr = ((ipacm_event_iface_up *)param)->ipv4_addr;
+ uint32_t ipv4_addr_mask = ((ipacm_event_iface_up *)param)->addr_mask;
+
+ IPACM_ConntrackClient::iptodot("Received ipv4 address and", ipv4_addr);
+ IPACM_ConntrackClient::iptodot("ipv4 address mask", ipv4_addr_mask);
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to retrieve conntrack client instance\n");
+ return;
+ }
+
+ /* calculate broadcast address from addr and addr_mask */
+ bc_ip_addr = (bc_ip_addr & (~ipv4_addr_mask));
+ bc_ip_addr = (bc_ip_addr | (ipv4_addr & ipv4_addr_mask));
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = ipv4_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACMDBG("ignoring interface:%s", ((ipacm_event_iface_up *)param)->ifname);
+ IPACM_ConntrackClient::iptodot("with ipv4 address", filter_ipv4.addr);
+ if(pClient->udp_filter != NULL)
+ {
+ nfct_filter_set_logic(pClient->udp_filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ nfct_filter_set_logic(pClient->udp_filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+ }
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = bc_ip_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACM_ConntrackClient::iptodot("with broadcast address", filter_ipv4.addr);
+ if(pClient->udp_filter != NULL)
+ {
+ nfct_filter_set_logic(pClient->udp_filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->udp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+ }
+
+ /* Attach the filter to udp handle */
+ if(pClient->udp_hdl != NULL)
+ {
+ IPACMDBG("attaching the filter to udp handle\n");
+ ret = nfct_filter_attach(nfct_fd(pClient->udp_hdl), pClient->udp_filter);
+ if(ret == -1)
+ {
+ PERROR("unable to attach the filter to udp handle\n");
+ IPACMERR("udp handle:%p, fd:%d Error: %d\n",pClient->udp_hdl, nfct_fd(pClient->udp_hdl), ret);
+ return;
+ }
+ }
+
+ return;
+}
+
+void IPACM_ConntrackClient::UpdateTCPFilters(void *param)
+{
+ int ret = 0;
+ uint32_t ipv4_addr = ((ipacm_event_iface_up *)param)->ipv4_addr;
+ uint32_t ipv4_addr_mask = ((ipacm_event_iface_up *)param)->addr_mask;
+ struct nfct_filter_ipv4 filter_ipv4;
+ IPACM_ConntrackClient *pClient = NULL;
+ /* Intialize with 255.255.255.255 */
+ uint32_t bc_ip_addr = 0xFFFFFFFF;
+
+ pClient = IPACM_ConntrackClient::GetInstance();
+ if(pClient == NULL)
+ {
+ IPACMERR("unable to retrieve conntrack client instance\n");
+ return;
+ }
+
+ /* calculate broadcast address from addr and addr_mask */
+ bc_ip_addr = (bc_ip_addr & (~ipv4_addr_mask));
+ bc_ip_addr = (bc_ip_addr | (ipv4_addr & ipv4_addr_mask));
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = ipv4_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACMDBG("ignoring interface:%s", ((ipacm_event_iface_up *)param)->ifname);
+ IPACM_ConntrackClient::iptodot("with ipv4 address", filter_ipv4.addr);
+
+ if(pClient->tcp_filter != NULL)
+ {
+ nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+
+ nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_SRC_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_SRC_IPV4, &filter_ipv4);
+ }
+
+ /* netfitler expecting in host-byte order */
+ filter_ipv4.addr = bc_ip_addr;
+ filter_ipv4.mask = 0xffffffff;
+
+ IPACM_ConntrackClient::iptodot("with broadcast address", filter_ipv4.addr);
+ if(pClient->tcp_filter != NULL)
+ {
+ nfct_filter_set_logic(pClient->tcp_filter,
+ NFCT_FILTER_DST_IPV4,
+ NFCT_FILTER_LOGIC_NEGATIVE);
+
+ nfct_filter_add_attr(pClient->tcp_filter, NFCT_FILTER_DST_IPV4, &filter_ipv4);
+ }
+
+ /* Attach the filter to tcp handle */
+ if(pClient->tcp_hdl != NULL)
+ {
+ IPACMDBG("attaching the filter to tcp handle\n");
+ ret = nfct_filter_attach(nfct_fd(pClient->tcp_hdl), pClient->tcp_filter);
+ if(ret == -1)
+ {
+ PERROR("unable to attach the filter to tcp handle\n");
+ IPACMERR("tcp handle:%p, fd:%d Error: %d\n",pClient->tcp_hdl, nfct_fd(pClient->tcp_hdl), ret);
+ return;
+ }
+ }
+
+ return;
+}
diff --git a/ipacm/src/IPACM_ConntrackListener.cpp b/ipacm/src/IPACM_ConntrackListener.cpp
new file mode 100644
index 0000000..66a6355
--- /dev/null
+++ b/ipacm/src/IPACM_ConntrackListener.cpp
@@ -0,0 +1,429 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "IPACM_ConntrackListener.h"
+#include "IPACM_ConntrackClient.h"
+#include "IPACM_EvtDispatcher.h"
+
+IPACM_ConntrackListener::IPACM_ConntrackListener()
+{
+ IPACMDBG("%d %s()\n", __LINE__, __FUNCTION__);
+
+ isCTReg = false;
+ isWanUp = false;
+
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, this);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, this);
+ IPACM_EvtDispatcher::registr(IPA_PROCESS_CT_MESSAGE, this);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WLAN_UP, this);
+}
+
+void IPACM_ConntrackListener::event_callback(ipa_cm_event_id evt,
+ void *data)
+{
+ ipacm_ct_evt_data *evt_data = NULL;
+ uint32_t *pub_addr = NULL;
+
+ if(data == NULL)
+ {
+ IPACMERR("Invalid Data\n");
+ return;
+ }
+
+ switch(evt)
+ {
+ case IPA_PROCESS_CT_MESSAGE:
+ IPACMDBG("Received IPA_PROCESS_CT_MESSAGE event\n");
+ evt_data = (ipacm_ct_evt_data *)data;
+ ProcessCTMessage(evt_data);
+ break;
+
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+ TriggerWANUp(data);
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+ pub_addr = (uint32_t *)data;
+ TriggerWANDown(*pub_addr);
+ break;
+
+ /* if wlan or lan comes up after wan interface, modify
+ tcp/udp filters to ignore local wlan or lan connections */
+ case IPA_HANDLE_WLAN_UP:
+ case IPA_HANDLE_LAN_UP:
+ IPACMDBG("Received event: %d\n", evt);
+ if(isWanUp == true)
+ {
+ IPACM_ConntrackClient::UpdateUDPFilters(data);
+ IPACM_ConntrackClient::UpdateTCPFilters(data);
+ }
+ break;
+
+ default:
+ IPACMDBG("Ignore cmd %d\n", evt);
+ break;
+ }
+}
+
+void IPACM_ConntrackListener::TriggerWANUp(void *in_param)
+{
+ ipacm_event_iface_up *wanup_data = (ipacm_event_iface_up *)in_param;
+
+ IPACMDBG("Recevied below informatoin during wanup:\n");
+ IPACMDBG("if_name:%s, ipv4_address:0x%x\n",
+ wanup_data->ifname, wanup_data->ipv4_addr);
+
+ isWanUp = true;
+ wan_ipaddr = wanup_data->ipv4_addr;
+ IPACM_ConntrackClient::iptodot("public ip address", wanup_data->ipv4_addr);
+
+ memcpy(wan_ifname, wanup_data->ifname, sizeof(wan_ifname));
+ NatApp::GetInstance()->AddTable(wanup_data->ipv4_addr);
+
+ IPACMDBG("creating nat threads\n");
+ CreateNatThreads();
+}
+
+int IPACM_ConntrackListener::CreateNatThreads(void)
+{
+ int ret;
+ pthread_t tcp_thread = 0, udp_thread = 0, udpcto_thread = 0;
+
+ if(isCTReg == false)
+ {
+
+ if(!tcp_thread)
+ {
+ ret = pthread_create(&tcp_thread, NULL, IPACM_ConntrackClient::TCPRegisterWithConnTrack, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create TCP conntrack event listner thread\n");
+ return -1;
+ }
+
+ IPACMDBG("created TCP conntrack event listner thread\n");
+ }
+
+ if(!udp_thread)
+ {
+ ret = pthread_create(&udp_thread, NULL, IPACM_ConntrackClient::UDPRegisterWithConnTrack, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create UDP conntrack event listner thread\n");
+ goto error;
+ }
+
+ IPACMDBG("created UDP conntrack event listner thread\n");
+ }
+
+ if(!udpcto_thread)
+ {
+ ret = pthread_create(&udpcto_thread, NULL, IPACM_ConntrackClient::UDPConnTimeoutUpdate, NULL);
+ if(0 != ret)
+ {
+ IPACMERR("unable to create udp conn timeout thread\n");
+ goto error;
+ }
+
+ IPACMDBG("created upd conn timeout thread\n");
+ }
+
+ isCTReg = true;
+ }
+
+ //pthread_join(tcp_thread, NULL);
+ //pthread_join(udp_thread, NULL);
+ //pthread_join(udpcto_thread, NULL);
+
+ return 0;
+
+error:
+ if(tcp_thread)
+ {
+ pthread_cancel(tcp_thread);
+ }
+
+ if(udp_thread)
+ {
+ pthread_cancel(tcp_thread);
+ }
+
+ if(udpcto_thread)
+ {
+ pthread_cancel(udpcto_thread);
+ }
+
+ return -1;
+}
+
+void IPACM_ConntrackListener::TriggerWANDown(uint32_t wan_addr)
+{
+ IPACMDBG("Deleting ipv4 nat table with ");
+ IPACM_ConntrackClient::iptodot("public ip address", wan_addr);
+ isWanUp = false;
+
+ NatApp::GetInstance()->DeleteTable(wan_addr);
+}
+
+
+void ParseCTMessage(struct nf_conntrack *ct)
+{
+ uint32_t status;
+ IPACMDBG("Printing conntrack parameters\n");
+
+ IPACM_ConntrackClient::iptodot("ATTR_IPV4_SRC = ATTR_ORIG_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC));
+ IPACM_ConntrackClient::iptodot("ATTR_IPV4_DST = ATTR_ORIG_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST));
+ IPACMDBG("ATTR_PORT_SRC = ATTR_ORIG_PORT_SRC: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC));
+ IPACMDBG("ATTR_PORT_DST = ATTR_ORIG_PORT_DST: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST));
+
+ IPACM_ConntrackClient::iptodot("ATTR_REPL_IPV4_SRC:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC));
+ IPACM_ConntrackClient::iptodot("ATTR_REPL_IPV4_DST:", nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST));
+ IPACMDBG("ATTR_REPL_PORT_SRC: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC));
+ IPACMDBG("ATTR_REPL_PORT_DST: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST));
+
+ IPACM_ConntrackClient::iptodot("ATTR_SNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_SNAT_IPV4));
+ IPACM_ConntrackClient::iptodot("ATTR_DNAT_IPV4:", nfct_get_attr_u32(ct, ATTR_DNAT_IPV4));
+ IPACMDBG("ATTR_SNAT_PORT: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_SNAT_PORT));
+ IPACMDBG("ATTR_DNAT_PORT: 0x:%x\n", nfct_get_attr_u16(ct, ATTR_DNAT_PORT));
+
+ IPACMDBG("ATTR_MARK: 0x%x\n", nfct_get_attr_u32(ct, ATTR_MARK));
+ IPACMDBG("ATTR_USE: 0x:%x\n", nfct_get_attr_u32(ct, ATTR_USE));
+ IPACMDBG("ATTR_ID: 0x:%x\n", nfct_get_attr_u32(ct, ATTR_ID));
+
+ status = nfct_get_attr_u32(ct, ATTR_STATUS);
+ IPACMDBG("ATTR_STATUS: 0x:%x\n", status);
+
+ if(IPS_SRC_NAT & status)
+ {
+ IPACMDBG("IPS_SRC_NAT set\n");
+ }
+
+ if(IPS_DST_NAT & status)
+ {
+ IPACMDBG("IPS_SRC_NAT set\n");
+ }
+
+ if(IPS_SRC_NAT_DONE & status)
+ {
+ IPACMDBG("IPS_SRC_NAT_DONE set\n");
+ }
+
+ if(IPS_DST_NAT_DONE & status)
+ {
+ IPACMDBG(" IPS_DST_NAT_DONE set\n");
+ }
+
+ IPACMDBG("\n");
+ return;
+}
+
+void IPACM_ConntrackListener::ProcessCTMessage(void *param)
+{
+ ipacm_ct_evt_data *evt_data = (ipacm_ct_evt_data *)param;
+ u_int8_t l4proto = 0;
+
+#ifdef IPACM_DEBUG
+ char buf[1024];
+
+ /* Process message and generate ioctl call to kernel thread */
+ nfct_snprintf(buf, sizeof(buf), evt_data->ct,
+ evt_data->type, NFCT_O_PLAIN, NFCT_OF_TIME);
+ IPACMDBG("%s\n", buf);
+ IPACMDBG("\n");
+
+ ParseCTMessage(evt_data->ct);
+#endif
+
+ l4proto = nfct_get_attr_u8(evt_data->ct, ATTR_ORIG_L4PROTO);
+ if(IPPROTO_UDP != l4proto && IPPROTO_TCP != l4proto)
+ {
+ IPACMDBG("Received unexpected protocl %d conntrack message\n", l4proto);
+ }
+ else
+ {
+ ProcessTCPorUDPMsg(evt_data->ct, evt_data->type, l4proto);
+ }
+
+ /* Cleanup item that was allocated during the original CT callback */
+ nfct_destroy(evt_data->ct);
+ return;
+}
+
+
+/* conntrack send in host order and ipa expects in host order */
+void IPACM_ConntrackListener::ProcessTCPorUDPMsg(
+ struct nf_conntrack *ct,
+ enum nf_conntrack_msg_type type,
+ u_int8_t l4proto)
+{
+ nat_table_entry rule;
+ u_int8_t tcp_state;
+ uint32_t status = 0;
+
+ status = nfct_get_attr_u32(ct, ATTR_STATUS);
+
+ if(IPS_DST_NAT & status)
+ {
+ IPACMDBG("Destination nat flag set\n");
+ rule.dst_nat = true;
+
+ IPACMDBG("Parse reply tuple\n");
+ rule.target_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+ rule.target_ip = ntohl(rule.target_ip);
+
+ /* Retriev target/dst port */
+ rule.target_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
+ rule.target_port = ntohs(rule.target_port);
+ if(0 == rule.target_port)
+ {
+ IPACMDBG("unable to retrieve target port\n");
+ }
+
+ rule.public_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+ rule.public_port = ntohs(rule.public_port);
+
+ /* Retriev src/private ip address */
+ rule.private_ip = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC);
+ rule.private_ip = ntohl(rule.private_ip);
+ if(0 == rule.private_ip)
+ {
+ IPACMDBG("unable to retrieve private ip address\n");
+ }
+
+ /* Retriev src/private port */
+ rule.private_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC);
+ rule.private_port = ntohs(rule.private_port);
+ if(0 == rule.private_port)
+ {
+ IPACMDBG("unable to retrieve private port\n");
+ }
+ }
+ else
+ {
+ IPACMDBG("destination nat flag reset\n");
+ rule.dst_nat = false;
+
+ /* Retriev target/dst ip address */
+ IPACMDBG("Parse source tuple\n");
+ rule.target_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_DST);
+ rule.target_ip = ntohl(rule.target_ip);
+ if(0 == rule.target_ip)
+ {
+ IPACMDBG("unable to retrieve target ip address\n");
+ }
+ /* Retriev target/dst port */
+ rule.target_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+ rule.target_port = ntohs(rule.target_port);
+ if(0 == rule.target_port)
+ {
+ IPACMDBG("unable to retrieve target port\n");
+ }
+
+ /* Retriev public port */
+ rule.public_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST);
+ rule.public_port = ntohs(rule.public_port);
+ if(0 == rule.public_port)
+ {
+ IPACMDBG("unable to retrieve public port\n");
+ }
+
+ /* Retriev src/private ip address */
+ rule.private_ip = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+ rule.private_ip = ntohl(rule.private_ip);
+ if(0 == rule.private_ip)
+ {
+ IPACMDBG("unable to retrieve private ip address\n");
+ }
+
+ /* Retriev src/private port */
+ rule.private_port = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC);
+ rule.private_port = ntohs(rule.private_port);
+ if(0 == rule.private_port)
+ {
+ IPACMDBG("unable to retrieve private port\n");
+ }
+ }
+ /* Retrieve Protocol */
+ rule.protocol = nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO);
+
+
+ IPACMDBG("Nat Entry with below information will be added\n");
+ IPACM_ConntrackClient::iptodot("target ip or dst ip", rule.target_ip);
+ IPACMDBG("target port or dst port: 0x%x Decimal:%d\n", rule.target_port, rule.target_port);
+ IPACM_ConntrackClient::iptodot("private ip or src ip", rule.private_ip);
+ IPACMDBG("private port or src port: 0x%x, Decimal:%d\n", rule.private_port, rule.private_port);
+ IPACMDBG("public port or reply dst port: 0x%x, Decimal:%d\n", rule.public_port, rule.public_port);
+ IPACMDBG("Protocol: %d, destination nat flag: %d\n", rule.protocol, rule.dst_nat);
+
+ if(IPPROTO_TCP == rule.protocol)
+ {
+ tcp_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE);
+ if(TCP_CONNTRACK_ESTABLISHED == tcp_state)
+ {
+ IPACMDBG("TCP state TCP_CONNTRACK_ESTABLISHED(%d)\n", tcp_state);
+ NatApp::GetInstance()->AddEntry(&rule);
+ }
+ else if(TCP_CONNTRACK_FIN_WAIT == tcp_state)
+ {
+ IPACMDBG("TCP state TCP_CONNTRACK_FIN_WAIT(%d)\n", tcp_state);
+ NatApp::GetInstance()->DeleteEntry(&rule);
+ }
+ else
+ {
+ IPACMDBG("Ignore tcp state: %d and type: %d\n", tcp_state, type);
+ }
+
+ }
+ else if(IPPROTO_UDP == rule.protocol)
+ {
+ if(NFCT_T_NEW == type)
+ {
+ IPACMDBG("New UDP connection at time %ld\n", time(NULL));
+ NatApp::GetInstance()->AddEntry(&rule);
+ }
+ else if(NFCT_T_DESTROY == type)
+ {
+ IPACMDBG("UDP connection close at time %ld\n", time(NULL));
+ NatApp::GetInstance()->DeleteEntry(&rule);
+ }
+ }
+ else
+ {
+ IPACMDBG("Ignore protocol: %d and type: %d\n", rule.protocol, type);
+ }
+
+ return;
+}
+
+
+
+
+
+
diff --git a/ipacm/src/IPACM_Conntrack_NATApp.cpp b/ipacm/src/IPACM_Conntrack_NATApp.cpp
new file mode 100644
index 0000000..63b158c
--- /dev/null
+++ b/ipacm/src/IPACM_Conntrack_NATApp.cpp
@@ -0,0 +1,504 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "IPACM_Conntrack_NATApp.h"
+#include "IPACM_ConntrackClient.h"
+
+#define UDP_TIMEOUT_VALUE 30
+
+/* NatApp class Implementation */
+NatApp *NatApp::pInstance = NULL;
+NatApp::NatApp()
+{
+ max_entries = 0;
+ cache = NULL;
+
+ nat_table_hdl = 0;
+ pub_ip_addr = 0;
+
+ curCnt = 0;
+
+ pALGPorts = NULL;
+ nALGPort = 0;
+
+ ct = NULL;
+ ct_hdl = NULL;
+}
+
+int NatApp::Init(void)
+{
+ IPACM_Config *pConfig;
+
+ pConfig = IPACM_Config::GetInstance();
+ if(pConfig == NULL)
+ {
+ IPACMERR("Unable to get Config instance\n");
+ return -1;
+ }
+
+ max_entries = pConfig->GetNatMaxEntries();
+
+ cache = (nat_table_entry *)malloc(sizeof(nat_table_entry) * max_entries);
+ if(cache == NULL)
+ {
+ IPACMERR("Unable to allocate memory for cache\n");
+ goto fail;
+ }
+ memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+
+ nALGPort = pConfig->GetAlgPortCnt();
+ pALGPorts = (ipacm_alg *)malloc(sizeof(ipacm_alg) * nALGPort);
+ if(pALGPorts == NULL)
+ {
+ IPACMERR("Unable to allocate memory for alg prots\n");
+ goto fail;
+ }
+ memset(pALGPorts, 0, sizeof(ipacm_alg) * nALGPort);
+
+ if(pConfig->GetAlgPorts(nALGPort, pALGPorts) != 0)
+ {
+ IPACMERR("Unable to retrieve ALG prots\n");
+ goto fail;
+ }
+
+ IPACMDBG("Printing %d alg ports information\n", nALGPort);
+ for(int cnt=0; cnt<nALGPort; cnt++)
+ {
+ IPACMDBG("%d: Proto[%d], port[%d]\n", cnt, pALGPorts[cnt].protocol, pALGPorts[cnt].port);
+ }
+
+ return 0;
+
+fail:
+ free(cache);
+ free(pALGPorts);
+ return -1;
+}
+
+NatApp* NatApp::GetInstance()
+{
+ if(pInstance == NULL)
+ {
+ pInstance = new NatApp();
+
+ if(pInstance->Init())
+ {
+ delete pInstance;
+ return NULL;
+ }
+ }
+
+ return pInstance;
+}
+
+/* NAT APP related object function definitions */
+
+int NatApp::AddTable(uint32_t pub_ip)
+{
+ int ret;
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ ret = ipa_nat_add_ipv4_tbl(pub_ip, max_entries, &nat_table_hdl);
+ if(ret)
+ {
+ IPACMERR("unable to create nat table Error:%d\n", ret);
+ return ret;
+ }
+
+ pub_ip_addr = pub_ip;
+ return 0;
+}
+
+void NatApp::Reset()
+{
+ memset(cache, 0, sizeof(nat_table_entry) * max_entries);
+
+ nat_table_hdl = 0;
+ pub_ip_addr = 0;
+ curCnt = 0;
+}
+
+int NatApp::DeleteTable(uint32_t pub_ip)
+{
+ int ret;
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ CHK_TBL_HDL();
+
+ if(pub_ip_addr != pub_ip)
+ {
+ IPACMDBG("Public ip address is not matching\n");
+ IPACMERR("unable to delete the nat table\n");
+ return -1;
+ }
+
+ ret = ipa_nat_del_ipv4_tbl(nat_table_hdl);
+ if(ret)
+ {
+ IPACMERR("unable to delete nat table Error: %d\n", ret);;
+ return ret;
+ }
+
+ Reset();
+ return 0;
+}
+
+/* Check for duplicate entries */
+bool NatApp::ChkForDup(const nat_table_entry *rule)
+{
+ int cnt = 0;
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ for(; cnt < curCnt; cnt++)
+ {
+ if(cache[cnt].private_ip == rule->private_ip &&
+ cache[cnt].target_ip == rule->target_ip &&
+ cache[cnt].private_port == rule->private_port &&
+ cache[cnt].target_port == rule->target_port &&
+ cache[cnt].protocol == rule->protocol)
+ {
+ IPACMDBG("Duplicate Rule\n");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Delete the entry from Nat table on connection close */
+int NatApp::DeleteEntry(const nat_table_entry *rule)
+{
+ int cnt = 0;
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ CHK_TBL_HDL();
+
+#ifdef IPACM_DEBUG
+ IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
+ IPACM_ConntrackClient::iptodot("Target IP", rule->target_ip);
+ IPACMDBG("Private Port: %d\t Target Port: %d\t", rule->private_port, rule->target_port);
+ IPACMDBG("protocolcol: %d\n", rule->protocol);
+#endif
+
+ for(; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == rule->private_ip &&
+ cache[cnt].target_ip == rule->target_ip &&
+ cache[cnt].private_port == rule->private_port &&
+ cache[cnt].target_port == rule->target_port &&
+ cache[cnt].protocol == rule->protocol)
+ {
+
+ if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("%s() %d\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ memset(&cache[cnt], 0, sizeof(cache[cnt]));
+ curCnt--;
+ }
+ }
+
+ return 0;
+}
+
+/* Add new entry to the nat table on new connection */
+int NatApp::AddEntry(const nat_table_entry *rule)
+{
+
+ int cnt = 0;
+ ipa_nat_ipv4_rule nat_rule;
+ IPACMDBG("%s() %d\n", __FUNCTION__, __LINE__);
+
+ CHK_TBL_HDL();
+
+ if(isAlgPort(rule->protocol, rule->private_port) ||
+ isAlgPort(rule->protocol, rule->target_port))
+ {
+ IPACMERR("connection using ALG Port. Dont insert into nat table\n");
+ return -1;
+ }
+
+ if(isPwrSaveIf(rule->private_ip) ||
+ isPwrSaveIf(rule->target_ip))
+ {
+ IPACMERR("Device is Power Save mode: Dont insert into nat table\n");
+ return -1;
+ }
+
+ if(!ChkForDup(rule))
+ {
+ for(; cnt < max_entries; cnt++)
+ {
+ if(cache[cnt].private_ip == 0 &&
+ cache[cnt].target_ip == 0 &&
+ cache[cnt].private_port == 0 &&
+ cache[cnt].target_port == 0 &&
+ cache[cnt].protocol == 0)
+ {
+ break;
+ }
+ }
+
+ if(max_entries == cnt)
+ {
+ IPACMERR("Error: Unable to add, reached maximum rules\n");
+ return -1;
+ }
+ else
+ {
+ nat_rule.private_ip = rule->private_ip;
+ nat_rule.target_ip = rule->target_ip;
+ nat_rule.target_port = rule->target_port;
+ nat_rule.private_port = rule->private_port;
+ nat_rule.public_port = rule->public_port;
+ nat_rule.protocol = rule->protocol;
+
+ if(ipa_nat_add_ipv4_rule(nat_table_hdl, &nat_rule, &cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to add the rule\n");
+ return -1;
+ }
+
+ cache[cnt].private_ip = rule->private_ip;
+ cache[cnt].target_ip = rule->target_ip;
+ cache[cnt].target_port = rule->target_port;
+ cache[cnt].private_port = rule->private_port;
+ cache[cnt].protocol = rule->protocol;
+ cache[cnt].timestamp = 0;
+ cache[cnt].public_port = rule->public_port;
+ cache[cnt].dst_nat = rule->dst_nat;
+ curCnt++;
+ }
+
+ }
+ else
+ {
+ IPACMERR("Duplicate rule. Ignore it\n");
+ return -1;
+ }
+
+
+#ifdef IPACM_DEBUG
+ IPACMDBG("Added below rule successfully\n");
+ IPACM_ConntrackClient::iptodot("Private IP", rule->private_ip);
+ IPACM_ConntrackClient::iptodot("Target IP", rule->target_ip);
+ IPACMDBG("Private Port:%d \t Target Port: %d\t", rule->private_port, rule->target_port);
+ IPACMDBG("Public Port:%d\n", rule->public_port);
+ IPACMDBG("protocol: %d\n", rule->protocol);
+#endif
+
+ return 0;
+}
+
+void NatApp::UpdateCTUdpTs(nat_table_entry *rule, uint32_t new_ts)
+{
+ int ret;
+
+#ifdef IPACM_DEBUG
+ IPACM_ConntrackClient::iptodot("Private IP:", rule->private_ip);
+ IPACM_ConntrackClient::iptodot("Target IP:", rule->target_ip);
+ IPACMDBG("Private Port: %d, Target Port: %d\n", rule->private_port, rule->target_port);
+#endif
+
+ if(!ct_hdl)
+ {
+ ct_hdl = nfct_open(CONNTRACK, 0);
+ if(!ct_hdl)
+ {
+ PERROR("nfct_open");
+ return;
+ }
+ }
+
+ if(!ct)
+ {
+ ct = nfct_new();
+ if(!ct)
+ {
+ PERROR("nfct_new");
+ return;
+ }
+ }
+
+ nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
+ nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_UDP);
+ nfct_set_attr_u32(ct, ATTR_TIMEOUT, UDP_TIMEOUT_VALUE);
+
+ if(rule->dst_nat == false)
+ {
+ nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->private_ip));
+ nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->private_port));
+
+ nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(rule->target_ip));
+ nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->target_port));
+
+ IPACMDBG("dst nat is not set\n");
+ }
+ else
+ {
+ nfct_set_attr_u32(ct, ATTR_IPV4_SRC, htonl(rule->target_ip));
+ nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(rule->target_port));
+
+ nfct_set_attr_u32(ct, ATTR_IPV4_DST, htonl(pub_ip_addr));
+ nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(rule->public_port));
+
+ IPACMDBG("dst nat is set\n");
+ }
+
+ IPACM_ConntrackClient::iptodot("Source IP:", nfct_get_attr_u32(ct, ATTR_IPV4_SRC));
+ IPACM_ConntrackClient::iptodot("Destination IP:", nfct_get_attr_u32(ct, ATTR_IPV4_DST));
+ IPACMDBG("Source Port: %d, Destination Port: %d\n",
+ nfct_get_attr_u16(ct, ATTR_PORT_SRC), nfct_get_attr_u16(ct, ATTR_PORT_DST));
+
+ IPACMDBG("updating udp connection with time: %d\n", UDP_TIMEOUT_VALUE);
+ ret = nfct_query(ct_hdl, NFCT_Q_UPDATE, ct);
+ if(ret == -1)
+ {
+ PERROR("unable to update time stamp");
+ }
+ else
+ {
+ rule->timestamp = new_ts;
+ IPACMDBG("Updated time stamp successfully\n");
+ }
+
+ return;
+}
+
+void NatApp::UpdateUDPTimeStamp()
+{
+ int cnt;
+ uint32_t ts;
+
+ for(cnt = 0; cnt < curCnt; cnt++)
+ {
+ ts = 0;
+ if(IPPROTO_UDP == cache[cnt].protocol)
+ {
+ IPACMDBG("\n");
+ if(ipa_nat_query_timestamp(nat_table_hdl, cache[cnt].rule_hdl, &ts) < 0)
+ {
+ IPACMERR("unable to retrieve timeout for rule hanle: %d\n", cache[cnt].rule_hdl);
+ continue;
+ }
+
+ if(ts == cache[cnt].timestamp)
+ {
+ continue;
+ }
+
+ UpdateCTUdpTs(&cache[cnt], ts);
+ } /* end of outer if */
+
+ } /* end of for loop */
+
+}
+
+bool NatApp::isAlgPort(uint8_t proto, uint16_t port)
+{
+ int cnt;
+ for(cnt = 0; cnt < nALGPort; cnt++)
+ {
+ if(proto == pALGPorts[cnt].protocol &&
+ port == pALGPorts[cnt].port)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool NatApp::isPwrSaveIf(uint32_t ip_addr)
+{
+ int cnt;
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(0 != PwrSaveIfs[cnt] &&
+ ip_addr == PwrSaveIfs[cnt])
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int NatApp::UpdatePwrSaveIf(uint32_t client_lan_ip)
+{
+ int cnt;
+
+ CHK_TBL_HDL();
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(PwrSaveIfs[cnt] == 0)
+ {
+ PwrSaveIfs[cnt] = client_lan_ip;
+ }
+ }
+
+ for(cnt = 0; cnt < curCnt; cnt++)
+ {
+ if(cache[cnt].private_ip == client_lan_ip)
+ {
+ if(ipa_nat_del_ipv4_rule(nat_table_hdl, cache[cnt].rule_hdl) < 0)
+ {
+ IPACMERR("unable to delete the rule\n");
+ continue;
+ }
+
+ memset(&cache[cnt], 0, sizeof(cache[cnt]));
+ curCnt--;
+ }
+ }
+
+ return 0;
+}
+
+int NatApp::ResetPwrSaveIf(uint32_t client_lan_ip)
+{
+ int cnt;
+
+ for(cnt = 0; cnt < IPA_MAX_NUM_WIFI_CLIENTS; cnt++)
+ {
+ if(PwrSaveIfs[cnt] == client_lan_ip)
+ {
+ PwrSaveIfs[cnt] = 0;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+
diff --git a/ipacm/src/IPACM_EvtDispatcher.cpp b/ipacm/src/IPACM_EvtDispatcher.cpp
new file mode 100644
index 0000000..2d2909b
--- /dev/null
+++ b/ipacm/src/IPACM_EvtDispatcher.cpp
@@ -0,0 +1,199 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_EvtDispatcher.cpp
+
+ @brief
+ This file implements the IPAM event dispatcher functionality
+
+ @Author
+
+*/
+#include <string.h>
+#include <pthread.h>
+#include <IPACM_EvtDispatcher.h>
+#include <IPACM_Neighbor.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Defs.h"
+
+
+extern pthread_mutex_t mutex;
+extern pthread_cond_t cond_var;
+
+cmd_evts *IPACM_EvtDispatcher::head = NULL;
+
+int IPACM_EvtDispatcher::PostEvt
+(
+ ipacm_cmd_q_data *data
+)
+{
+ Message *item = NULL;
+ MessageQueue *MsgQueue = NULL;
+
+ MsgQueue = MessageQueue::getInstance();
+ if(MsgQueue == NULL)
+ {
+ IPACMERR("unable to retrieve MsgQueue instance\n");
+ return IPACM_FAILURE;
+ }
+
+ item = new Message();
+ if(item == NULL)
+ {
+ IPACMERR("unable to create new message item\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("Populating item to post to queue\n");
+ item->evt.callback_ptr = IPACM_EvtDispatcher::ProcessEvt;
+ memcpy(&item->evt.data, data, sizeof(ipacm_cmd_q_data));
+
+ if(pthread_mutex_lock(&mutex) != 0)
+ {
+ IPACMERR("unable to lock the mutex\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("Enqueing item\n");
+ MsgQueue->enqueue(item);
+ IPACMDBG("Enqueued item %p\n", item);
+
+ if(pthread_cond_signal(&cond_var) != 0)
+ {
+ IPACMDBG("unable to lock the mutex\n");
+ /* Release the mutex before you return failure */
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return IPACM_FAILURE;
+ }
+ return IPACM_FAILURE;
+ }
+
+ if(pthread_mutex_unlock(&mutex) != 0)
+ {
+ IPACMERR("unable to unlock the mutex\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+void IPACM_EvtDispatcher::ProcessEvt(ipacm_cmd_q_data *data)
+{
+
+ cmd_evts *tmp = head;
+
+ if(head == NULL)
+ {
+ IPACMDBG("Queue is empty\n");
+ }
+
+ while(tmp != NULL)
+ {
+ if(data->event == tmp->event)
+ {
+ tmp->obj->event_callback(data->event, data->evt_data);
+ }
+ tmp = tmp->next;
+ }
+
+ if(data->evt_data != NULL)
+ {
+ free(data->evt_data);
+ }
+ return;
+}
+
+int IPACM_EvtDispatcher::registr(ipa_cm_event_id event, IPACM_Listener *obj)
+{
+ cmd_evts *tmp = head,*nw;
+
+ nw = (cmd_evts *)malloc(sizeof(cmd_evts));
+ if(nw != NULL)
+ {
+ nw->event = event;
+ nw->obj = obj;
+ nw->next = NULL;
+ }
+ else
+ {
+ return IPACM_FAILURE;
+ }
+
+ if(head == NULL)
+ {
+ head = nw;
+ }
+ else
+ {
+ while(tmp->next)
+ {
+ tmp = tmp->next;
+ }
+ tmp->next = nw;
+ }
+ return IPACM_SUCCESS;
+}
+
+
+int IPACM_EvtDispatcher::deregistr(IPACM_Listener *param)
+{
+ cmd_evts *tmp = head,*tmp1,*prev = head;
+
+ while(tmp != NULL)
+ {
+ if(tmp->obj == param)
+ {
+ tmp1 = tmp;
+ if(tmp == head)
+ {
+ head = head->next;
+ }
+ else if(tmp->next == NULL)
+ {
+ prev->next = NULL;
+ }
+ else
+ {
+ prev->next = tmp->next;
+ }
+
+ tmp = tmp->next;
+ free(tmp1);
+ }
+ else
+ {
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ }
+ return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Filtering.cpp b/ipacm/src/IPACM_Filtering.cpp
new file mode 100644
index 0000000..4241549
--- /dev/null
+++ b/ipacm/src/IPACM_Filtering.cpp
@@ -0,0 +1,223 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Filtering.cpp
+
+ @brief
+ This file implements the IPACM filtering functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Filtering.h"
+#include <IPACM_Log.h>
+
+const char *IPACM_Filtering::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Filtering::IPACM_Filtering()
+{
+ fd = open(DEVICE_NAME, O_RDWR);
+ if (0 == fd)
+ {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ }
+}
+
+IPACM_Filtering::~IPACM_Filtering()
+{
+ close(fd);
+}
+
+bool IPACM_Filtering::DeviceNodeIsOpened()
+{
+ return fd;
+}
+
+bool IPACM_Filtering::AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable)
+{
+ int retval = 0;
+
+ IPACMDBG("Printing filter add attributes\n");
+ IPACMDBG("ip type: %d\n", ruleTable->ip);
+ IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
+ IPACMDBG("End point: %d and global value: %d\n", ruleTable->ep, ruleTable->global);
+ IPACMDBG("commit value: %d\n", ruleTable->commit);
+ for (int cnt=0; cnt<ruleTable->num_rules; cnt++)
+ {
+ IPACMDBG("Filter rule:%d attrib mask: 0x%x\n",
+ cnt,
+ ruleTable->rules[cnt].rule.attrib.attrib_mask);
+ }
+
+ retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE, ruleTable);
+ if (retval != 0)
+ {
+ IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
+ PERROR("unable to add filter rule:");
+
+ for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
+ {
+ if (ruleTable->rules[cnt].status != 0)
+ {
+ IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+ cnt, ruleTable->rules[cnt].status);
+ }
+ }
+ return false;
+ }
+
+ for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
+ {
+ if(ruleTable->rules[cnt].status != 0)
+ {
+ IPACMERR("Adding Filter rule:%d failed with status:%d\n",
+ cnt, ruleTable->rules[cnt].status);
+ }
+ }
+
+ IPACMDBG("Added Filtering rule %p\n", ruleTable);
+ return true;
+}
+
+bool IPACM_Filtering::DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable)
+{
+ int retval = 0;
+
+ retval = ioctl(fd, IPA_IOC_DEL_FLT_RULE, ruleTable);
+ if (retval != 0)
+ {
+ IPACMERR("Failed deleting Filtering rule %p\n", ruleTable);
+ return false;
+ }
+
+ IPACMDBG("Deleted Filtering rule %p\n", ruleTable);
+ return true;
+}
+
+bool IPACM_Filtering::Commit(enum ipa_ip_type ip)
+{
+ int retval = 0;
+
+ retval = ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+ if (retval != 0)
+ {
+ IPACMERR("failed committing Filtering rules.\n");
+ return false;
+ }
+
+ IPACMDBG("Committed Filtering rules to IPA HW.\n");
+ return true;
+}
+
+bool IPACM_Filtering::Reset(enum ipa_ip_type ip)
+{
+ int retval = 0;
+
+ retval = ioctl(fd, IPA_IOC_RESET_FLT, ip);
+ retval |= ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
+ if (retval)
+ {
+ IPACMERR("failed resetting Filtering block.\n");
+ return false;
+ }
+
+ IPACMDBG("Reset command issued to IPA Filtering block.\n");
+ return true;
+}
+
+bool IPACM_Filtering::DeleteFilteringHdls
+(
+ uint32_t *flt_rule_hdls,
+ ipa_ip_type ip,
+ uint8_t num_rules
+ )
+{
+ struct ipa_ioc_del_flt_rule *flt_rule;
+ bool res = true;
+ int len = 0, cnt = 0;
+
+ len = (sizeof(struct ipa_ioc_del_flt_rule)) + (num_rules * sizeof(struct ipa_flt_rule_del));
+ flt_rule = (struct ipa_ioc_del_flt_rule *)malloc(len);
+ if (flt_rule == NULL)
+ {
+ IPACMERR("unable to allocate memory for del filter rule\n");
+ return false;
+ }
+
+ memset(flt_rule, 0, len);
+ flt_rule->commit = 1;
+ flt_rule->num_hdls = num_rules;
+ flt_rule->ip = ip;
+
+ for (cnt = 0; cnt < flt_rule->num_hdls; cnt++)
+ {
+
+ if (flt_rule_hdls[cnt] == 0)
+ {
+ IPACMERR("invalid filter handle passed, ignoring it: %d\n", cnt)
+ res = false;
+ goto fail;
+ }
+
+ flt_rule->hdl[cnt].status = -1;
+ flt_rule->hdl[cnt].hdl = flt_rule_hdls[cnt];
+ IPACMDBG("Deleting filter hdl:(0x%x) with ip type: %d\n", flt_rule_hdls[cnt], ip);
+ }
+
+ if (DeleteFilteringRule(flt_rule) == false)
+ {
+ PERROR("Filter rule deletion failed!\n");
+ res = false;
+ goto fail;
+ }
+
+ for (cnt = 0; cnt < flt_rule->num_hdls; cnt++)
+ {
+ if (flt_rule->hdl[cnt].status != 0)
+ {
+ IPACMERR("Filter rule hdl 0x%x deletion failed with error:%d\n",
+ flt_rule->hdl[cnt].hdl, flt_rule->hdl[cnt].status);
+ res = false;
+ }
+ }
+
+fail:
+ free(flt_rule);
+
+ return res;
+}
+
diff --git a/ipacm/src/IPACM_Header.cpp b/ipacm/src/IPACM_Header.cpp
new file mode 100644
index 0000000..0ebb83d
--- /dev/null
+++ b/ipacm/src/IPACM_Header.cpp
@@ -0,0 +1,200 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Header.h"
+#include "IPACM_Log.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//All interaction through the driver are made through this inode.
+static const char *DEVICE_NAME = "/dev/ipa";
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+IPACM_Header::IPACM_Header()
+{
+ m_fd = open(DEVICE_NAME, O_RDWR);
+ if (-1 == m_fd)
+ {
+ IPACMDBG("Failed to open %s in IPACM_Header test application constructor.\n", DEVICE_NAME);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+IPACM_Header::~IPACM_Header()
+{
+ if (-1 != m_fd)
+ {
+ close(m_fd);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::DeviceNodeIsOpened()
+{
+ return (-1 != m_fd);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::AddHeader(struct ipa_ioc_add_hdr *pHeaderTableToAdd)
+{
+ int nRetVal = 0;
+ //call the Driver ioctl in order to add header
+ nRetVal = ioctl(m_fd, IPA_IOC_ADD_HDR, pHeaderTableToAdd);
+ IPACMDBG("return value: %d\n", nRetVal);
+ return (-1 != nRetVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::DeleteHeader(struct ipa_ioc_del_hdr *pHeaderTableToDelete)
+{
+ int nRetVal = 0;
+ //call the Driver ioctl in order to remove header
+ nRetVal = ioctl(m_fd, IPA_IOC_DEL_HDR, pHeaderTableToDelete);
+ IPACMDBG("return value: %d\n", nRetVal);
+ return (-1 != nRetVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::Commit()
+{
+ int nRetVal = 0;
+ nRetVal = ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+ IPACMDBG("return value: %d\n", nRetVal);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::Reset()
+{
+ int nRetVal = 0;
+
+ nRetVal = ioctl(m_fd, IPA_IOC_RESET_HDR);
+ nRetVal |= ioctl(m_fd, IPA_IOC_COMMIT_HDR);
+ IPACMDBG("return value: %d\n", nRetVal);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::GetHeaderHandle(struct ipa_ioc_get_hdr *pHeaderStruct)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_GET_HDR, pHeaderStruct);
+ if (retval)
+ {
+ IPACMERR("IPA_IOC_GET_HDR ioctl failed, routingTable =0x%p, retval=0x%x.\n", pHeaderStruct, retval);
+ return false;
+ }
+
+ IPACMDBG("IPA_IOC_GET_HDR ioctl issued to IPA header insertion block.\n");
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool IPACM_Header::CopyHeader(struct ipa_ioc_copy_hdr *pCopyHeaderStruct)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_COPY_HDR, pCopyHeaderStruct);
+ if (retval)
+ {
+ IPACMERR("IPA_IOC_COPY_HDR ioctl failed, retval=0x%x.\n", retval);
+ return false;
+ }
+
+ IPACMDBG("IPA_IOC_COPY_HDR ioctl issued to IPA header insertion block.\n");
+ return true;
+}
+
+bool IPACM_Header::DeleteHeaderHdl(uint32_t hdr_hdl)
+{
+ const uint8_t NUM_HDLS = 1;
+ struct ipa_ioc_del_hdr *pHeaderDescriptor = NULL;
+ struct ipa_hdr_del *hd_rule_entry;
+ int len = 0;
+ bool res = true;
+
+ if (hdr_hdl == 0)
+ {
+ IPACMERR("Invalid header handle passed. Ignoring it\n");
+ return false;
+ }
+
+ len = (sizeof(struct ipa_ioc_del_hdr)) + (NUM_HDLS * sizeof(struct ipa_hdr_del));
+ pHeaderDescriptor = (struct ipa_ioc_del_hdr *)malloc(len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("Unable to allocate memory for del header\n");
+ return false;
+ }
+
+ memset(pHeaderDescriptor, 0, len);
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdls = NUM_HDLS;
+ hd_rule_entry = &pHeaderDescriptor->hdl[0];
+
+ hd_rule_entry->hdl = hdr_hdl;
+ hd_rule_entry->status = -1;
+
+ IPACMDBG("Deleting Header hdl:(%x)\n", hd_rule_entry->hdl);
+ if ((false == DeleteHeader(pHeaderDescriptor)) ||
+ (hd_rule_entry->status))
+ {
+ PERROR("Header deletion failed!\n");
+ res = false;
+ goto fail;
+ }
+
+ IPACMDBG("Deleted Header hdl:(%x) successfully\n", hd_rule_entry->hdl);
+
+fail:
+ free(pHeaderDescriptor);
+
+ return res;
+
+}
+
diff --git a/ipacm/src/IPACM_Iface.cpp b/ipacm/src/IPACM_Iface.cpp
new file mode 100644
index 0000000..cc6ce13
--- /dev/null
+++ b/ipacm/src/IPACM_Iface.cpp
@@ -0,0 +1,598 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+* Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.Z
+*/
+/*!
+ @file
+ IPACM_Iface.cpp
+
+ @brief
+ This file implements the basis Iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <ifaddrs.h>
+
+#include <IPACM_Netlink.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Wlan.h>
+
+const char *IPACM_Iface::DEVICE_NAME = "/dev/ipa";
+IPACM_Routing IPACM_Iface::m_routing;
+IPACM_Filtering IPACM_Iface::m_filtering;
+IPACM_Header IPACM_Iface::m_header;
+
+IPACM_Config *IPACM_Iface::ipacmcfg = IPACM_Config::GetInstance();
+
+IPACM_Iface::IPACM_Iface(int iface_index)
+{
+ ip_type = IPACM_IP_NULL; /* initially set invalid */
+ num_dft_rt = 0;
+ softwarerouting_act = false;
+ ipa_if_num = iface_index;
+
+ memcpy(dev_name,
+ IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name,
+ sizeof(IPACM_Iface::ipacmcfg->iface_table[iface_index].iface_name));
+
+ memset(dft_v4fl_rule_hdl, 0, sizeof(dft_v4fl_rule_hdl));
+ memset(dft_v6fl_rule_hdl, 0, sizeof(dft_v6fl_rule_hdl));
+
+ memset(dft_rt_rule_hdl, 0, sizeof(dft_rt_rule_hdl));
+ memset(software_routing_fl_rule_hdl, 0, sizeof(software_routing_fl_rule_hdl));
+
+ query_iface_property();
+ IPACMDBG(" create iface-index(%d) constructor\n", ipa_if_num);
+ return;
+}
+
+/* software routing enable */
+int IPACM_Iface::handle_software_routing_enable(void)
+{
+
+ int res = IPACM_SUCCESS;
+ struct ipa_flt_rule_add flt_rule_entry;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("\n");
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+ /* Configuring Software-Routing Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = false;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* check iface is v4 or v6 or both*/
+ if (ip_type == IPA_IP_MAX)
+ {
+ /* handle v4 */
+ m_pFilteringTable->ip = IPA_IP_v4;
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+
+ /* handle v6*/
+ m_pFilteringTable->ip = IPA_IP_v6;
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ softwarerouting_act = true;
+ }
+ else
+ {
+ if (ip_type == IPA_IP_v4)
+ {
+ m_pFilteringTable->ip = IPA_IP_v4;
+ }
+ else
+ {
+ m_pFilteringTable->ip = IPA_IP_v6;
+ }
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMERR("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ if (ip_type == IPA_IP_v4)
+ {
+ software_routing_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+ else
+ {
+ software_routing_fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+ softwarerouting_act = true;
+ }
+
+fail:
+ free(m_pFilteringTable);
+
+ return res;
+}
+
+/* software routing disable */
+int IPACM_Iface::handle_software_routing_disable(void)
+{
+ int res = IPACM_SUCCESS;
+ ipa_ip_type ip;
+ uint32_t flt_hdl;
+
+ IPACMDBG("ip-type: %d\n", ip_type);
+
+ if (ip_type == IPA_IP_MAX)
+ {
+ /* ipv4 case */
+ if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[0],
+ IPA_IP_v4, 1) == false)
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ /* ipv6 case */
+ if (m_filtering.DeleteFilteringHdls(&software_routing_fl_rule_hdl[1],
+ IPA_IP_v6, 1) == false)
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ softwarerouting_act = false;
+ }
+ else
+ {
+ if (ip_type == IPA_IP_v4)
+ {
+ ip = IPA_IP_v4;
+ }
+ else
+ {
+ ip = IPA_IP_v6;
+ }
+
+
+ if (ip_type == IPA_IP_v4)
+ {
+ flt_hdl = software_routing_fl_rule_hdl[0];
+ }
+ else
+ {
+ flt_hdl = software_routing_fl_rule_hdl[1];
+ }
+
+ if (m_filtering.DeleteFilteringHdls(&flt_hdl, ip, 1) == false)
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ softwarerouting_act = false;
+ }
+
+fail:
+ return res;
+}
+
+/* Query ipa_interface_index by given linux interface_index */
+int IPACM_Iface::iface_ipa_index_query
+(
+ int interface_index
+)
+{
+ int fd;
+ int link = -1;
+ int i = 0;
+ struct ifreq ifr;
+
+
+ /* Search known linux interface-index and map to IPA interface-index*/
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
+ {
+ if (interface_index == IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index)
+ {
+ link = i;
+ IPACMDBG("Interface (%s) found: linux(%d) ipa(%d) \n",
+ IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
+ IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index,
+ link);
+ return link;
+ break;
+ }
+ }
+
+ /* Search/Configure linux interface-index and map it to IPA interface-index */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ PERROR("get interface name socket create failed");
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ ifr.ifr_ifindex = interface_index;
+ IPACMDBG("Interface index %d\n", interface_index);
+
+ if (ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+ {
+ PERROR("call_ioctl_on_dev: ioctl failed:");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+ close(fd);
+
+ IPACMDBG("Received interface name %s\n", ifr.ifr_name);
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_ipa_interfaces; i++)
+ {
+ if (strncmp(ifr.ifr_name,
+ IPACM_Iface::ipacmcfg->iface_table[i].iface_name,
+ sizeof(IPACM_Iface::ipacmcfg->iface_table[i].iface_name)) == 0)
+ {
+ IPACMDBG("Interface (%s) linux(%d) mapped to ipa(%d) \n", ifr.ifr_name,
+ IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index, i);
+
+ link = i;
+ IPACM_Iface::ipacmcfg->iface_table[i].netlink_interface_index = interface_index;
+ break;
+ }
+ }
+
+ return link;
+}
+
+/*Query the IPA endpoint property */
+int IPACM_Iface::query_iface_property(void)
+{
+ int res = IPACM_SUCCESS, fd = 0;
+
+ fd = open(DEVICE_NAME, O_RDWR);
+ IPACMDBG("iface query-property \n");
+ if (0 == fd)
+ {
+ IPACMERR("Failed opening %s.\n", DEVICE_NAME);
+ return IPACM_FAILURE;
+ }
+
+ iface_query = (struct ipa_ioc_query_intf *)
+ calloc(1, sizeof(struct ipa_ioc_query_intf));
+
+ IPACMDBG("iface name %s\n", dev_name);
+ memcpy(iface_query->name, dev_name, sizeof(dev_name));
+
+ if (ioctl(fd, IPA_IOC_QUERY_INTF, iface_query) < 0)
+ {
+ PERROR("ioctl IPA_IOC_QUERY_INTF failed\n");
+ /* iface_query memory will free when iface-down*/
+ res = IPACM_FAILURE;
+ }
+
+ tx_prop = (struct ipa_ioc_query_intf_tx_props *)
+ calloc(1, sizeof(struct ipa_ioc_query_intf_tx_props) +
+ iface_query->num_tx_props * sizeof(struct ipa_ioc_tx_intf_prop));
+
+ memcpy(tx_prop->name, dev_name, sizeof(tx_prop->name));
+ tx_prop->num_tx_props = iface_query->num_tx_props;
+
+ if (ioctl(fd, IPA_IOC_QUERY_INTF_TX_PROPS, tx_prop) < 0)
+ {
+ PERROR("ioctl IPA_IOC_QUERY_INTF_TX_PROPS failed\n");
+ /* tx_prop memory will free when iface-down*/
+ res = IPACM_FAILURE;
+ }
+
+ rx_prop = (struct ipa_ioc_query_intf_rx_props *)
+ calloc(1, sizeof(struct ipa_ioc_query_intf_rx_props) +
+ iface_query->num_rx_props * sizeof(struct ipa_ioc_rx_intf_prop));
+
+ memcpy(rx_prop->name, dev_name,
+ sizeof(rx_prop->name));
+ rx_prop->num_rx_props = iface_query->num_rx_props;
+
+ if (ioctl(fd, IPA_IOC_QUERY_INTF_RX_PROPS, rx_prop) < 0)
+ {
+ PERROR("ioctl IPA_IOC_QUERY_INTF_RX_PROPS failed\n");
+ /* rx_prop memory will free when iface-down*/
+ res = IPACM_FAILURE;
+ }
+
+ if (res != IPACM_FAILURE)
+ {
+ IPACMDBG("Rx property attribute mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+ for(uint32_t cnt=0; cnt<tx_prop->num_tx_props; cnt++)
+ {
+ IPACMDBG("Tx property:%d attribute mask:0x%x, ip-type: %d\n",
+ cnt, tx_prop->tx[0].attrib.attrib_mask,tx_prop->tx[0].ip);
+ }
+ }
+
+ close(fd);
+ return res;
+}
+
+/*Configure the initial filter rules */
+int IPACM_Iface::init_fl_rule(ipa_ip_type iptype)
+{
+
+ int res = IPACM_SUCCESS, len = 0;
+ struct ipa_flt_rule_add flt_rule_entry;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ /* update the iface ip-type to be IPA_IP_v4, IPA_IP_v6 or both*/
+ if (iptype == IPA_IP_v4)
+ {
+
+ if ((ip_type == IPA_IP_v4) || (ip_type == IPA_IP_MAX))
+ {
+ IPACMDBG(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+ return res;
+ }
+
+ if (ip_type == IPA_IP_v6)
+ {
+ ip_type = IPA_IP_MAX;
+ }
+ else
+ {
+ ip_type = IPA_IP_v4;
+ }
+
+ IPACMDBG(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+ }
+ else
+ {
+
+ if ((ip_type == IPA_IP_v6) || (ip_type == IPA_IP_MAX))
+ {
+ IPACMDBG(" interface(%s:%d) already in ip-type %d\n", dev_name, ipa_if_num, ip_type);
+ return res;
+ }
+
+ if (ip_type == IPA_IP_v4)
+ {
+ ip_type = IPA_IP_MAX;
+ }
+ else
+ {
+ ip_type = IPA_IP_v6;
+ }
+
+ IPACMDBG(" interface(%s:%d) now ip-type is %d\n", dev_name, ipa_if_num, ip_type);
+ }
+
+
+ /* construct ipa_ioc_add_flt_rule with default filter rules */
+ if (iptype == IPA_IP_v4)
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV4_DEFAULT_FILTERTING_RULES;
+
+ /* Configuring Fragment Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ IPACMDBG("rx property attrib mask:0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring Multicast Filtering Rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xF0000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000;
+ memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring Broadcast Filtering Rule */
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF;
+ memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ /* copy filter hdls */
+ for (int i = 0; i < IPV4_DEFAULT_FILTERTING_RULES; i++)
+ {
+ if (m_pFilteringTable->rules[i].status == 0)
+ {
+ dft_v4fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ IPACMDBG("Default v4 filter Rule %d HDL:0x%x\n", i, dft_v4fl_rule_hdl[i]);
+ }
+ else
+ {
+ IPACMDBG("Failed adding default v4 Filtering rule %d\n", i);
+ }
+ }
+ }
+ }
+ else
+ {
+ len = sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add));
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
+
+ /* Configuring Fragment Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+
+ /* Configuring Multicast Filtering Rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFF000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0XFF000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ /* copy filter hdls */
+ for (int i = 0;
+ i < IPV6_DEFAULT_FILTERTING_RULES;
+ i++)
+ {
+ if (m_pFilteringTable->rules[i].status == 0)
+ {
+ dft_v6fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ IPACMDBG("Default v6 Filter Rule %d HDL:0x%x\n", i, dft_v6fl_rule_hdl[i]);
+ }
+ else
+ {
+ IPACMERR("Failing adding v6 default IPV6 rule %d\n", i);
+ }
+ }
+ }
+ }
+
+
+fail:
+ free(m_pFilteringTable);
+
+ return res;
+}
diff --git a/ipacm/src/IPACM_IfaceManager.cpp b/ipacm/src/IPACM_IfaceManager.cpp
new file mode 100644
index 0000000..747cbfe
--- /dev/null
+++ b/ipacm/src/IPACM_IfaceManager.cpp
@@ -0,0 +1,242 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_IfaceManager.cpp
+
+ @brief
+ This file implements the IPAM iface_manager functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <IPACM_IfaceManager.h>
+#include <IPACM_EvtDispatcher.h>
+#include <IPACM_Defs.h>
+#include <IPACM_Wlan.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Iface.h>
+#include <IPACM_Log.h>
+
+iface_instances *IPACM_IfaceManager::head = NULL;
+
+IPACM_IfaceManager::IPACM_IfaceManager()
+{
+ IPACM_EvtDispatcher::registr(IPA_LINK_UP_EVENT, this); // skylar fix register name, class name
+ return; //skylar no interface_id
+}
+
+void IPACM_IfaceManager::event_callback(ipa_cm_event_id event, void *param) //skylar rename:event_callback
+{
+ ipacm_event_data_fid *evt_data = (ipacm_event_data_fid *)param;
+ IPACMDBG("\n");
+ switch(event)
+ {
+
+ case IPA_LINK_UP_EVENT:
+ IPACMDBG("link up %d: \n", evt_data->if_index);
+ create_iface_instance(evt_data->if_index);
+ break;
+
+ default:
+ break;
+ }
+ return;
+}
+
+int IPACM_IfaceManager::create_iface_instance(int if_index)
+{
+ int ipa_interface_index;
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(if_index);
+
+ /* check if duplicate instance*/
+ if(SearchInstance(ipa_interface_index) == IPA_INSTANCE_NOT_FOUND)
+ {
+ /* IPA_INSTANCE_NOT_FOUND */
+ switch(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat)
+ {
+
+ case LAN_IF:
+ {
+ IPACMDBG("Creating Lan interface\n");
+ IPACM_Lan *lan = new IPACM_Lan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, lan);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, lan);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, lan);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, lan);
+ IPACMDBG("ipa_LAN (%s):ipa_index (%d) instance open/registr ok\n", lan->dev_name, lan->ipa_if_num);
+ registr(ipa_interface_index, lan);
+ }
+ break;
+
+ case WLAN_IF:
+ {
+ IPACMDBG("Creating WLan interface\n");
+ IPACM_Wlan *wl = new IPACM_Wlan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_ADD_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_DEL_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_POWER_SAVE_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_WLAN_CLIENT_RECOVER_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, wl);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, wl);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_UP, wl);
+ IPACM_EvtDispatcher::registr(IPA_HANDLE_WAN_DOWN, wl);
+ IPACMDBG("ipa_WLAN (%s):ipa_index (%d) instance open/registr ok\n", wl->dev_name, wl->ipa_if_num);
+ registr(ipa_interface_index, wl);
+ }
+ break;
+
+ case WAN_IF:
+ {
+ IPACMDBG("Creating Wan interface\n");
+ IPACM_Wan *w = new IPACM_Wan(ipa_interface_index);
+ IPACM_EvtDispatcher::registr(IPA_ADDR_ADD_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_ADD_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_ROUTE_DEL_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_FIREWALL_CHANGE_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT, w);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_ENABLE, w);
+ IPACM_EvtDispatcher::registr(IPA_SW_ROUTING_DISABLE, w);
+ IPACM_EvtDispatcher::registr(IPA_LINK_DOWN_EVENT, w);
+ IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance open/registr ok\n", w->dev_name, w->ipa_if_num);
+ registr(ipa_interface_index, w);
+ }
+ break;
+
+ default:
+ IPACMERR("Unhandled interface received\n");
+ return IPACM_SUCCESS;
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+
+int IPACM_IfaceManager::registr(int ipa_if_index, IPACM_Listener *obj)
+{
+ iface_instances *tmp = head,*nw;
+
+ nw = (iface_instances *)malloc(sizeof(iface_instances));
+ if(nw != NULL)
+ {
+ nw->ipa_if_index = ipa_if_index;
+ nw->obj = obj;
+ nw->next = NULL;
+ }
+ else
+ {
+ return IPACM_FAILURE;
+ }
+
+ if(head == NULL)
+ {
+ head = nw;
+ }
+ else
+ {
+ while(tmp->next)
+ {
+ tmp = tmp->next;
+ }
+ tmp->next = nw;
+ }
+ return IPACM_SUCCESS;
+}
+
+int IPACM_IfaceManager::deregistr(IPACM_Listener *param)
+{
+ iface_instances *tmp = head,*tmp1,*prev = head;
+
+ while(tmp != NULL)
+ {
+ if(tmp->obj == param)
+ {
+ tmp1 = tmp;
+ if(tmp == head)
+ {
+ head = head->next;
+ }
+ else if(tmp->next == NULL)
+ {
+ prev->next = NULL;
+ }
+ else
+ {
+ prev->next = tmp->next;
+ }
+
+ tmp = tmp->next;
+ free(tmp1);
+ }
+ else
+ {
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+
+int IPACM_IfaceManager::SearchInstance(int ipa_if_index)
+{
+
+ iface_instances *tmp = head;
+
+ while(tmp != NULL)
+ {
+ if(ipa_if_index == tmp->ipa_if_index)
+ {
+ IPACMDBG("Find existed iface-instance name: %s\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+ return IPA_INSTANCE_FOUND;
+ }
+ tmp = tmp->next;
+ }
+
+ IPACMDBG("No existed iface-instance name: %s,\n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
+
+ return IPA_INSTANCE_NOT_FOUND;
+}
diff --git a/ipacm/src/IPACM_Lan.cpp b/ipacm/src/IPACM_Lan.cpp
new file mode 100644
index 0000000..8b47985
--- /dev/null
+++ b/ipacm/src/IPACM_Lan.cpp
@@ -0,0 +1,902 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials provided
+with the distribution.
+
+* Neither the name of The Linux Foundation nor the names of its
+contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Lan.cpp
+
+ @brief
+ This file implements the LAN iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+#include <IPACM_Netlink.h>
+#include <IPACM_Lan.h>
+#include <IPACM_Wan.h>
+#include <IPACM_IfaceManager.h>
+
+IPACM_Lan::IPACM_Lan(int iface_index) : IPACM_Iface(iface_index)
+{
+ num_uni_rt = 0;
+ num_dft_rt = 0;
+
+ rt_rule_len = sizeof(struct ipa_lan_rt_rule) + (iface_query->num_tx_props * sizeof(uint32_t));
+ route_rule = (struct ipa_lan_rt_rule *)calloc(IPA_MAX_NUM_UNICAST_ROUTE_RULES, rt_rule_len);
+ if (route_rule == NULL)
+ {
+ IPACMERR("unable to allocate memory\n");
+ return;
+ }
+
+ IPACMDBG(" IPACM->IPACM_Lan(%d) constructor: Tx:%d Rx:%d\n", ipa_if_num,
+ iface_query->num_tx_props, iface_query->num_rx_props);
+
+ return;
+}
+
+IPACM_Lan::~IPACM_Lan()
+{
+ IPACM_EvtDispatcher::deregistr(this);
+ IPACM_IfaceManager::deregistr(this);
+ return;
+}
+
+
+/* LAN-iface's callback function */
+void IPACM_Lan::event_callback(ipa_cm_event_id event, void *param)
+{
+ int ipa_interface_index;
+
+ switch (event)
+ {
+ case IPA_LINK_DOWN_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ IPACMDBG("ipa_LAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ delete this;
+ return;
+ }
+ }
+ break;
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ADDR_ADD_EVENT\n");
+
+ if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+ {
+ handle_addr_evt(data);
+ handle_private_subnet(data->iptype);
+ if (IPACM_Wan::isWanUP() && (data->iptype == IPA_IP_v4))
+ {
+ handle_wan_up();
+ }
+
+ /* Post event to NAT */
+ if (data->iptype == IPA_IP_v4)
+ {
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_iface_up *info;
+
+ info = (ipacm_event_iface_up *)
+ malloc(sizeof(ipacm_event_iface_up));
+ if (info == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+
+ memcpy(info->ifname, dev_name, IF_NAME_LEN);
+ info->ipv4_addr = data->ipv4_addr;
+ info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+ evt_data.event = IPA_HANDLE_LAN_UP;
+ evt_data.evt_data = (void *)info;
+
+ /* Insert IPA_HANDLE_LAN_UP to command queue */
+ IPACMDBG("posting IPA_HANDLE_LAN_UP for IPv4 with below information\n");
+ IPACMDBG("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+ info->ipv4_addr, info->addr_mask);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ }
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+ handle_wan_up();
+ break;
+
+ case IPA_ROUTE_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ /* unicast routing rule add */
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ROUTE_ADD_EVENT\n");
+ handle_route_add_evt(data);
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+ handle_wan_down();
+ break;
+
+ case IPA_ROUTE_DEL_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ /* unicast routing rule del */
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ROUTE_DEL_EVENT\n");
+ handle_route_del_evt(data);
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+ ipacm_event_data_addr *data_addr;
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if (data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return;
+ }
+
+ data_addr->if_index = data->if_index;
+ data_addr->iptype = data->iptype;
+ if (data->iptype == IPA_IP_v4)
+ {
+ data_addr->ipv4_addr = data->ipv4_addr;
+ data_addr->ipv4_addr_mask = 0xFFFFFFFF;
+ }
+ else
+ {
+ memcpy(data_addr->ipv6_addr,
+ data->ipv6_addr,
+ sizeof(data_addr->ipv6_addr));
+ data_addr->ipv6_addr_mask[0] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[1] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[2] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[3] = 0xFFFFFFFF;
+ }
+ handle_route_add_evt(data_addr);
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT\n");
+ ipacm_event_data_addr *data_addr;
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if (data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return;
+ }
+
+ data_addr->if_index = data->if_index;
+ data_addr->iptype = data->iptype;
+ if (data->iptype == IPA_IP_v4)
+ {
+ data_addr->ipv4_addr = data->ipv4_addr;
+ data_addr->ipv4_addr_mask = 0xFFFFFFFF;
+ }
+ else
+ {
+ memcpy(data_addr->ipv6_addr,
+ data->ipv6_addr,
+ sizeof(data_addr->ipv6_addr));
+ data_addr->ipv6_addr_mask[0] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[1] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[2] = 0xFFFFFFFF;
+ data_addr->ipv6_addr_mask[3] = 0xFFFFFFFF;
+ }
+ handle_route_del_evt(data_addr);
+ }
+ }
+ break;
+
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+ /* handle software routing enable event*/
+ handle_software_routing_enable();
+ break;
+
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+ /* handle software routing disable event*/
+ handle_software_routing_disable();
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+/* handle unicast routing rule add event */
+int IPACM_Lan::handle_route_add_evt(ipacm_event_data_addr *data)
+{
+ /* add unicate route for LAN */
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ struct ipa_ioc_get_hdr sRetHeader;
+ uint32_t tx_index;
+
+ IPACMDBG("LAN callback: unicast IPA_ROUTE_ADD_EVENT\n");
+
+ if (num_uni_rt < IPA_MAX_NUM_UNICAST_ROUTE_RULES)
+ {
+ /* unicast RT rule add start */
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ 1 * sizeof(struct ipa_rt_rule_add));
+ if (!rt_rule)
+ {
+ IPACMERR("fail\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)1;
+ rt_rule->ip = data->iptype;
+
+ if (data->iptype == IPA_IP_v4) strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ else strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 1;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (tx_prop->tx[tx_index].hdr_name)
+ {
+ memset(&sRetHeader, 0, sizeof(sRetHeader));
+ strncpy(sRetHeader.name,
+ tx_prop->tx[tx_index].hdr_name,
+ sizeof(tx_prop->tx[tx_index].hdr_name));
+
+ if (false == m_header.GetHeaderHandle(&sRetHeader))
+ {
+ IPACMDBG(" ioctl failed\n");
+ }
+
+ rt_rule_entry->rule.hdr_hdl = sRetHeader.hdl;
+ }
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ if (data->iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = data->ipv4_addr_mask;
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = data->ipv6_addr_mask[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = data->ipv6_addr_mask[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = data->ipv6_addr_mask[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = data->ipv6_addr_mask[3];
+ }
+ IPACMDBG("m_routing = %p\n", &m_routing);
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("rt rule hdl1=%x\n", rt_rule_entry->rt_rule_hdl);
+ get_rt_ruleptr(route_rule, num_uni_rt)->rt_rule_hdl[tx_index]
+ = rt_rule_entry->rt_rule_hdl;
+ }
+ memcpy(&get_rt_ruleptr(route_rule, num_uni_rt)->rule,
+ &rt_rule_entry->rule.attrib,
+ sizeof(get_rt_ruleptr(route_rule, num_uni_rt)->rule));
+
+ get_rt_ruleptr(route_rule, num_uni_rt)->ip = data->iptype;
+ free(rt_rule);
+ num_uni_rt++;
+ }
+ else
+ {
+ IPACMDBG("unicast rule oversize\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* handle unicast routing rule del event */
+int IPACM_Lan::handle_route_del_evt(ipacm_event_data_addr *data)
+{
+ int i;
+ uint32_t tx_index;
+
+ /* delete 1 unicast RT rule */
+ for (i = 0; i <= num_uni_rt; i++)
+ {
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ if ((data->ipv4_addr == get_rt_ruleptr(route_rule, i)->rule.u.v4.dst_addr) &&
+ (data->ipv4_addr_mask == get_rt_ruleptr(route_rule, i)->rule.u.v4.dst_addr_mask))
+ {
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+ IPA_IP_v4) == false)
+ {
+ IPACMDBG("Routing rule deletion failed!\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ /* remove that delted route rule entry*/
+ for (; i <= num_uni_rt; i++)
+ {
+ get_rt_ruleptr(route_rule, i)->rule = get_rt_ruleptr(route_rule, (i + 1))->rule;
+ get_rt_ruleptr(route_rule, i)->ip = get_rt_ruleptr(route_rule, (i + 1))->ip;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index] = get_rt_ruleptr(route_rule, (i + 1))->rt_rule_hdl[tx_index];
+ }
+ }
+
+ num_uni_rt -= 1;
+ return IPACM_SUCCESS;
+ }
+ }
+ else
+ {
+ if ((data->ipv6_addr[0] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[0]) &&
+ (data->ipv6_addr[1] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[1]) &&
+ (data->ipv6_addr[2] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[2]) &&
+ (data->ipv6_addr[3] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr[3]) &&
+ (data->ipv6_addr_mask[0] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[0]) &&
+ (data->ipv6_addr_mask[1] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[1]) &&
+ (data->ipv6_addr_mask[2] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[2]) &&
+ (data->ipv6_addr_mask[3] == get_rt_ruleptr(route_rule, i)->rule.u.v6.dst_addr_mask[3]))
+ {
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+ IPA_IP_v6) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ /* remove that delted route rule entry*/
+ for (; i <= num_uni_rt; i++)
+ {
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index] = get_rt_ruleptr(route_rule, (i + 1))->rt_rule_hdl[tx_index];
+ }
+ get_rt_ruleptr(route_rule, i)->rule = get_rt_ruleptr(route_rule, (i + 1))->rule;
+ get_rt_ruleptr(route_rule, i)->ip = get_rt_ruleptr(route_rule, (i + 1))->ip;
+ }
+
+ num_uni_rt -= 1;
+ return IPACM_SUCCESS;
+ }
+ }
+ }
+
+ return IPACM_FAILURE;
+}
+
+
+
+
+/* configure filter rule for wan_up event*/
+int IPACM_Lan::handle_wan_up(void)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int len = 0;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("set WAN interface as default filter rule\n");
+
+ len = sizeof(struct ipa_ioc_add_flt_rule) + (1 * sizeof(struct ipa_flt_rule_add));
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)calloc(1, len);
+ if (m_pFilteringTable == NULL)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ IPACMDBG("Retrieving routing hanle for table: %s\n",
+ IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n",
+ &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Routing hanle for table: %d\n", IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl);
+
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add)); // Zero All Fields
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x0;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x0;
+
+ memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMDBG("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ perror("Lan: Unable to add filter rule");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[0].flt_rule_hdl,
+ m_pFilteringTable->rules[0].status);
+ }
+
+
+ /* copy filter hdls */
+ lan_wan_fl_rule_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+
+ return IPACM_SUCCESS;
+}
+
+
+/* delete filter rule for wan_down event*/
+int IPACM_Lan::handle_wan_down(void)
+{
+
+ if (m_filtering.DeleteFilteringHdls(&lan_wan_fl_rule_hdl[0],
+ IPA_IP_v4, 1) == false)
+ {
+ IPACMDBG("Error Adding RuleTable(1) to Filtering, aborting...\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* handle new_address event*/
+int IPACM_Lan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ struct ipa_flt_rule_add flt_rule_entry;
+ const int NUM_RULES = 1;
+ int res = IPACM_SUCCESS;
+
+ /* construct ipa_ioc_add_flt_rule with 1 rules */
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("set route/filter rule ip-type: %d \n", data->iptype);
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+ if (rt_rule == NULL)
+ {
+ IPACMERR("fail to allocate ipa_ioc_add_rt_rule \n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = data->iptype;
+
+ if (data->iptype == IPA_IP_v4) strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ else strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 1;
+ rt_rule_entry->rule.dst = IPA_CLIENT_A5_LAN_WAN_CONS; //go to A5
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ }
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ IPACMDBG("rt rule hdl=%x with ip-type: %d\n", rt_rule_entry->rt_rule_hdl, data->iptype);
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+
+ /* initial multicast/broadcast/fragment filter rule */
+ IPACM_Iface::init_fl_rule(data->iptype);
+ }
+ else
+ {
+ if (num_dft_rt == 0)
+ {
+ /* initial multicast/broadcast/fragment filter rule */
+ IPACM_Iface::init_fl_rule(data->iptype);
+
+ /* add default v6 filter rule */
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ IPACMDBG("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_v6);
+ free(m_pFilteringTable);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rule, aborting...\n");
+ free(m_pFilteringTable);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_v6fl_rule_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+
+ dft_rt_rule_hdl[1 + num_dft_rt] = rt_rule_entry->rt_rule_hdl;
+ num_dft_rt++;
+ }
+
+ IPACMDBG("number of default route rules %d\n", num_dft_rt);
+
+fail:
+ free(rt_rule);
+
+ return res;
+}
+
+/* configure private subnet filter rules*/
+int IPACM_Lan::handle_private_subnet(ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i;
+
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("lan->handle_private_subnet(); set route/filter rule \n");
+
+ if (iptype == IPA_IP_v4)
+ {
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
+ );
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ IPACMERR("LAN m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+ memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ IPACMDBG("Loop %d 5\n", i);
+ }
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMDBG("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ /* copy filter rule hdls */
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
+ {
+
+ private_fl_rule_hdl[i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ }
+ free(m_pFilteringTable);
+ }
+ return IPACM_SUCCESS;
+}
+
+
+
+/*handle wlan iface down event*/
+int IPACM_Lan::handle_down_evt()
+{
+ int i;
+ uint32_t tx_index;
+ int res = IPACM_SUCCESS;
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ goto fail;
+ }
+
+ IPACMDBG("lan handle_down_evt\n ");
+
+ if (ip_type != IPA_IP_v6)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* delete default v6 routing rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ /* may have multiple ipv6 iface-RT rules*/
+ for (i = 0; i < num_dft_rt; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[1 + i], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+
+
+ /* free unicast routing rule */
+ for (i = 0; i < num_uni_rt; i++)
+ {
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (m_routing.DeleteRoutingHdl(get_rt_ruleptr(route_rule, i)->rt_rule_hdl[tx_index],
+ get_rt_ruleptr(route_rule, i)->ip) == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ }
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true)
+ {
+ IPACM_Iface::handle_software_routing_disable();
+ }
+
+
+ /* delete default filter rules */
+ if (ip_type != IPA_IP_v6)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+ IPA_IP_v4,
+ IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Adding Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ /* free private-subnet ipv4 filter rules */
+ if (m_filtering.DeleteFilteringHdls(
+ private_fl_rule_hdl,
+ IPA_IP_v4,
+ IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
+ {
+ IPACMERR("Error Deleting RuleTable(1) to Filtering, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+
+ if (ip_type != IPA_IP_v4)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+ IPA_IP_v6,
+ (IPV6_DEFAULT_FILTERTING_RULES + IPV6_DEFAULT_LAN_FILTERTING_RULES)) == false)
+ {
+ IPACMERR("Error Adding RuleTable(1) to Filtering, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* delete wan filter rule */
+ if (IPACM_Wan::isWanUP())
+ {
+ handle_wan_down();
+ }
+
+fail:
+ free(tx_prop);
+ free(rx_prop);
+ free(iface_query);
+
+ return res;
+}
diff --git a/ipacm/src/IPACM_Log.cpp b/ipacm/src/IPACM_Log.cpp
new file mode 100644
index 0000000..3333358
--- /dev/null
+++ b/ipacm/src/IPACM_Log.cpp
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_log.cpp
+
+ @brief
+ This file implements the IPAM log functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include "IPACM_Log.h"
+#include <stdlib.h>
+
+#define FILE_NAME "/usr/ipacm_log.txt"
+
+static FILE *fp = NULL;
+char log_buf[LOG_SIZE];
+
+void logmessage(char *msg)
+{
+ printf("%s\n", msg);
+#if 0
+ if(fp == NULL)
+ {
+ fp = fopen(FILE_NAME, "wb+");
+ if(fp == NULL)
+ {
+ printf("unable to open file\n");
+ return;
+ }
+ }
+
+ fprintf(fp, msg);
+ fflush(fp);
+#endif
+ return;
+}
+
+
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
new file mode 100644
index 0000000..6369e10
--- /dev/null
+++ b/ipacm/src/IPACM_Main.cpp
@@ -0,0 +1,424 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission. from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Main.cpp
+
+ @brief
+ This file implements the IPAM functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+/******************************************************************************
+
+ IP_MAIN.C
+
+******************************************************************************/
+
+#include <sys/socket.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <stdlib.h>
+
+#include "IPACM_CmdQueue.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Neighbor.h"
+#include "IPACM_IfaceManager.h"
+#include "IPACM_Log.h"
+
+#include "IPACM_ConntrackListener.h"
+
+#define IPA_DRIVER "/dev/ipa"
+
+#define IPACM_DIR_NAME "/etc"
+#define IPACM_FILE_NAME "mobileap_firewall.xml"
+
+#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event))
+#define INOTIFY_BUF_LEN (INOTIFY_EVENT_SIZE + 2*sizeof(IPACM_FILE_NAME))
+
+#define IPA_DRIVER_WLAN_EVENT_SIZE (sizeof(struct ipa_wlan_msg))
+#define IPA_DRIVER_WLAN_META_MSG (sizeof(struct ipa_msg_meta))
+#define IPA_DRIVER_WLAN_BUF_LEN (IPA_DRIVER_WLAN_EVENT_SIZE + IPA_DRIVER_WLAN_META_MSG)
+
+//char *log_buf = (char *)malloc(LOG_SIZE);
+int ipa_get_if_index(char *if_name, int *if_index);
+
+/* start netlink socket monitor*/
+void* netlink_start(void *param)
+{
+ ipa_nl_sk_fd_set_info_t sk_fdset;
+ int ret_val = 0;
+
+ memset(&sk_fdset, 0, sizeof(ipa_nl_sk_fd_set_info_t));
+ IPACMDBG("netlink starter memset sk_fdset succeeds\n");
+ ret_val = ipa_nl_listener_init(NETLINK_ROUTE, (RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK |
+ RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH |
+ RTNLGRP_IPV6_PREFIX),
+ &sk_fdset, ipa_nl_recv_msg);
+
+ if (ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Failed to initialize IPA netlink event listener\n");
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/* start firewall-rule monitor*/
+void* firewall_monitor(void *param)
+{
+ int length;
+ int wd;
+ char buffer[INOTIFY_BUF_LEN];
+ int inotify_fd;
+ ipacm_cmd_q_data evt_data;
+ uint32_t mask = IN_MODIFY;
+
+ inotify_fd = inotify_init();
+ if (inotify_fd < 0)
+ {
+ PERROR("inotify_init");
+ }
+
+ IPACMDBG("Waiting for nofications in dir %s with mask: 0x%x\n", IPACM_DIR_NAME, mask);
+
+ wd = inotify_add_watch(inotify_fd,
+ IPACM_DIR_NAME,
+ mask);
+
+ while (1)
+ {
+ length = read(inotify_fd, buffer, INOTIFY_BUF_LEN);
+ struct inotify_event *event = (struct inotify_event *)buffer;
+
+ if (length < 0)
+ {
+ IPACMDBG("inotify read() error return length: %d and mask: 0x%x 0x%x\n", length, event->mask, mask);
+ return NULL;
+ }
+
+ if (event->len > 0)
+ {
+ if (event->mask & IN_MODIFY)
+ {
+ if (event->mask & IN_ISDIR)
+ {
+ IPACMDBG("The directory %s was 0x%x\n", event->name, event->mask);
+ }
+ else if (!strncmp(event->name, IPACM_FILE_NAME, event->len))
+ {
+ IPACMDBG("File \"%s\" was 0x%x\n", event->name, event->mask);
+ IPACMDBG("The interested file %s .\n", IPACM_FILE_NAME);
+
+ evt_data.event = IPA_FIREWALL_CHANGE_EVENT;
+ evt_data.evt_data = NULL;
+
+ /* Insert IPA_FIREWALL_CHANGE_EVENT to command queue */
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ }
+ IPACMDBG("Received monitoring event %s.\n", event->name);
+ }
+ }
+
+ (void)inotify_rm_watch(inotify_fd, wd);
+ (void)close(inotify_fd);
+ return NULL;
+}
+
+
+/* start IPACM WLAN-driver notifier */
+void* ipa_driver_wlan_notifier(void *param)
+{
+ int length, fd;
+ char buffer[IPA_DRIVER_WLAN_BUF_LEN];
+ struct ipa_msg_meta *event_hdr = NULL;
+ struct ipa_wlan_msg *event = NULL;
+
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_mac *data;
+
+ fd = open(IPA_DRIVER, O_RDWR);
+ if (fd == 0)
+ {
+ IPACMERR("Failed opening %s.\n", IPA_DRIVER);
+ }
+
+ while (1)
+ {
+ IPACMDBG("Waiting for nofications from IPA driver \n");
+ memset(buffer, 0, sizeof(buffer));
+
+ length = read(fd, buffer, IPA_DRIVER_WLAN_BUF_LEN);
+ if (length < 0)
+ {
+ PERROR("didn't read IPA_driver correctly");
+ return NULL;
+ }
+
+ event_hdr = (struct ipa_msg_meta *)buffer;
+ IPACMDBG("Message type: %d\n", event_hdr->msg_type);
+ IPACMDBG("Event header length received: %d\n",event_hdr->msg_len);
+
+ if (event_hdr->msg_len > 0)
+ {
+ event = (struct ipa_wlan_msg *)(buffer + sizeof(struct ipa_msg_meta));
+ }
+
+ /* Insert WLAN_DRIVER_EVENT to command queue */
+ data = (ipacm_event_data_mac *)malloc(sizeof(ipacm_event_data_mac));
+ if (data == NULL)
+ {
+ PERROR("unable to allocate memory for event data\n");
+ return NULL;
+ }
+
+ switch (event_hdr->msg_type)
+ {
+
+ case SW_ROUTING_ENABLE:
+ IPACMDBG("Received SW_ROUTING_ENABLE\n");
+ evt_data.event = IPA_SW_ROUTING_ENABLE;
+ evt_data.evt_data = NULL;
+ break;
+
+ case SW_ROUTING_DISABLE:
+ IPACMDBG("Received SW_ROUTING_DISABLE\n");
+ evt_data.event = IPA_SW_ROUTING_DISABLE;
+ evt_data.evt_data = NULL;
+ break;
+
+ case WLAN_CLIENT_CONNECT:
+ IPACMDBG("Received WLAN_CLIENT_CONNECT\n");
+ IPACMDBG("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+ event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
+
+ evt_data.event = IPA_WLAN_CLIENT_ADD_EVENT;
+ evt_data.evt_data = data;
+ ipa_get_if_index(event->name, &(data->if_index));
+ memcpy(data->mac_addr,
+ event->mac_addr,
+ sizeof(event->mac_addr));
+ break;
+
+ case WLAN_CLIENT_DISCONNECT:
+ IPACMDBG("Received WLAN_CLIENT_DISCONNECT\n");
+ IPACMDBG("Mac Address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+ event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
+
+ memcpy(data->mac_addr,
+ event->mac_addr,
+ sizeof(event->mac_addr));
+ ipa_get_if_index(event->name, &(data->if_index));
+
+ evt_data.event = IPA_WLAN_CLIENT_DEL_EVENT;
+ evt_data.evt_data = data;
+
+ break;
+
+ case WLAN_CLIENT_POWER_SAVE_MODE:
+ IPACMDBG("Received WLAN_CLIENT_POWER_SAVE_MODE\n");
+ IPACMDBG("Mac Address [0]:%2d [1]:%2d [2]:%2d [3]:%2d [4]:%2d [5]%2d\n",
+ event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+ event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
+
+ ipa_get_if_index(event->name, &(data->if_index));
+
+ evt_data.event = IPA_WLAN_CLIENT_POWER_SAVE_EVENT;
+ evt_data.evt_data = data;
+ memcpy(data->mac_addr,
+ event->mac_addr,
+ sizeof(event->mac_addr));
+
+ break;
+
+ case WLAN_CLIENT_NORMAL_MODE:
+ IPACMDBG("Received WLAN_CLIENT_NORMAL_MODE\n");
+ IPACMDBG("Mac Address [0]:%2d [1]:%2d [2]:%2d [3]:%2d [4]:%2d [5]%2d\n",
+ event->mac_addr[0], event->mac_addr[1], event->mac_addr[2],
+ event->mac_addr[3], event->mac_addr[4], event->mac_addr[5]);
+
+ memcpy(data->mac_addr,
+ event->mac_addr,
+ sizeof(event->mac_addr));
+ ipa_get_if_index(event->name, &(data->if_index));
+ evt_data.evt_data = data;
+ evt_data.event = IPA_WLAN_CLIENT_RECOVER_EVENT;
+ break;
+
+ default:
+ IPACMDBG("Invalid message\n");
+ free(data);
+ continue;
+
+ }
+
+ /* finish command queue */
+ if (evt_data.evt_data == NULL)
+ {
+ free(data);
+ }
+
+ IPACMDBG("Posting event:%d\n", evt_data.event);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ (void)close(fd);
+ return NULL;
+}
+
+
+int main(int argc, char **argv)
+{
+ int ret;
+ pthread_t netlink_thread = 0, monitor_thread = 0, ipa_driver_thread = 0;
+ pthread_t cmd_queue_thread = 0;
+
+ IPACM_Neighbor *neigh = new IPACM_Neighbor();
+ IPACM_IfaceManager *ifacemgr = new IPACM_IfaceManager();
+
+ IPACMDBG("Staring IPA main\n");
+ IPACMDBG("ipa_cmdq_successful\n");
+
+
+ if (IPACM_SUCCESS == cmd_queue_thread)
+ {
+ ret = pthread_create(&cmd_queue_thread, NULL, MessageQueue::Process, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to command queue thread\n");
+ return ret;
+ }
+ IPACMDBG("created command queue thread\n");
+ }
+
+ if (IPACM_SUCCESS == netlink_thread)
+ {
+ ret = pthread_create(&netlink_thread, NULL, netlink_start, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to create netlink thread\n");
+ return ret;
+ }
+ IPACMDBG("created netlink thread\n");
+ }
+
+
+ if (IPACM_SUCCESS == monitor_thread)
+ {
+ ret = pthread_create(&monitor_thread, NULL, firewall_monitor, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to create monitor thread\n");
+ return ret;
+ }
+ IPACMDBG("created firewall monitor thread\n");
+ }
+
+ if (IPACM_SUCCESS == ipa_driver_thread)
+ {
+ ret = pthread_create(&ipa_driver_thread, NULL, ipa_driver_wlan_notifier, NULL);
+ if (IPACM_SUCCESS != ret)
+ {
+ IPACMERR("unable to create ipa_driver_wlan thread\n");
+ return ret;
+ }
+ IPACMDBG("created ipa_driver_wlan thread\n");
+ }
+
+ pthread_join(cmd_queue_thread, NULL);
+ pthread_join(netlink_thread, NULL);
+ pthread_join(monitor_thread, NULL);
+ pthread_join(ipa_driver_thread, NULL);
+ return IPACM_SUCCESS;
+}
+
+
+/*===========================================================================
+ FUNCTION ipa_get_if_index
+===========================================================================*/
+/*!
+@brief
+ get ipa interface index by given the interface name
+
+@return
+ IPACM_SUCCESS or IPA_FALUIRE
+
+@note
+
+- Dependencies
+ - None
+
+- Side Effects
+ - None
+*/
+/*=========================================================================*/
+int ipa_get_if_index
+(
+ char *if_name,
+ int *if_index
+ )
+{
+ int fd;
+ struct ifreq ifr;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ PERROR("get interface index socket create failed");
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ (void)strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
+
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
+ {
+ PERROR("call_ioctl_on_dev: ioctl failed:");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ *if_index = ifr.ifr_ifindex;
+ close(fd);
+ return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Neighbor.cpp b/ipacm/src/IPACM_Neighbor.cpp
new file mode 100644
index 0000000..327b681
--- /dev/null
+++ b/ipacm/src/IPACM_Neighbor.cpp
@@ -0,0 +1,252 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Neighbor.cpp
+
+ @brief
+ This file implements the functionality of handling IPACM Neighbor events.
+
+ @Author
+ Skylar Chang
+
+*/
+
+#include <sys/ioctl.h>
+#include <IPACM_Neighbor.h>
+#include <IPACM_EvtDispatcher.h>
+#include "IPACM_Defs.h"
+#include "IPACM_Log.h"
+
+
+IPACM_Neighbor::IPACM_Neighbor()
+{
+ num_neighbor_client = 0;
+ IPACM_EvtDispatcher::registr(IPA_NEW_NEIGH_EVENT, this);
+ IPACM_EvtDispatcher::registr(IPA_DEL_NEIGH_EVENT, this);
+ return;
+}
+
+void IPACM_Neighbor::event_callback(ipa_cm_event_id event, void *param)
+{
+ ipacm_event_data_all *data = NULL;
+ int i, ipa_interface_index;
+ ipacm_cmd_q_data evt_data;
+ int num_neighbor_client_temp = num_neighbor_client;
+
+ IPACMDBG("Recieved event %d\n", event);
+
+ data = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ memcpy(data, param, sizeof(ipacm_event_data_all));
+
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+ /*No that interface existed in ipa list*/
+ if(ipa_interface_index==-1)
+ return;
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue*/
+ if (event == IPA_NEW_NEIGH_EVENT)
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ else
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+
+ memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG("Posted event %d with %s\n", evt_data.event,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+ }
+ else
+ {
+ if ((data->ipv6_addr[0]) || (data->ipv6_addr[1]) || (data->ipv6_addr[2]) || (data->ipv6_addr[3]))
+ {
+ /* check if iface is not bridge0*/
+ if (strcmp(IPA_VIRTUAL_IFACE_NAME, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
+ {
+ /* searh if seen this client or not*/
+ for (i = 0; i < num_neighbor_client_temp; i++)
+ {
+ if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+ {
+ data->if_index = neighbor_client[i].iface_index;
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+ if (event == IPA_NEW_NEIGH_EVENT) evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ else evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+ //evt_data.evt_data=data;
+ memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* ask for replaced iface name*/
+ ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data->if_index);
+ /*No that interface existed in ipa list*/
+ if(ipa_interface_index==-1)
+ return;
+
+ IPACMDBG("Posted event %d, with %s\n",
+ evt_data.event,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+ /* delete that entry*/
+ for (; i < num_neighbor_client_temp - 1; i++)
+ {
+ memcpy(neighbor_client[i].mac_addr, neighbor_client[i + 1].mac_addr, sizeof(neighbor_client[i].mac_addr));
+ neighbor_client[i].v6_addr[0] = neighbor_client[i + 1].v6_addr[0];
+ neighbor_client[i].v6_addr[1] = neighbor_client[i + 1].v6_addr[1];
+ neighbor_client[i].v6_addr[2] = neighbor_client[i + 1].v6_addr[2];
+ neighbor_client[i].v6_addr[3] = neighbor_client[i + 1].v6_addr[3];
+ neighbor_client[i].iface_index = neighbor_client[i + 1].iface_index;
+ }
+ num_neighbor_client -= 1;
+ break;
+
+ };
+ }
+
+ /* cannot find neighbor client*/
+ if (i == num_neighbor_client_temp)
+ {
+ IPACMDBG("ipv6 with bridge0 with mac, not seen before\n");
+ if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
+ {
+ memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
+ data->mac_addr,
+ sizeof(data->mac_addr));
+ neighbor_client[num_neighbor_client_temp].v6_addr[0] = data->ipv6_addr[0];
+ neighbor_client[num_neighbor_client_temp].v6_addr[1] = data->ipv6_addr[1];
+ neighbor_client[num_neighbor_client_temp].v6_addr[2] = data->ipv6_addr[2];
+ neighbor_client[num_neighbor_client_temp].v6_addr[3] = data->ipv6_addr[3];
+ IPACMDBG("Copy bridge0 MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+ neighbor_client[num_neighbor_client_temp].mac_addr[0],
+ neighbor_client[num_neighbor_client_temp].mac_addr[1],
+ neighbor_client[num_neighbor_client_temp].mac_addr[2],
+ neighbor_client[num_neighbor_client_temp].mac_addr[3],
+ neighbor_client[num_neighbor_client_temp].mac_addr[4],
+ neighbor_client[num_neighbor_client_temp].mac_addr[5],
+ num_neighbor_client_temp);
+ num_neighbor_client++;
+ return;
+ }
+ else
+ {
+ IPACMERR("error: neighbor client oversize!");
+ return;
+ }
+ }
+ }
+ else
+ {
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+ if (event == IPA_NEW_NEIGH_EVENT)
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ else
+ evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+
+ memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+ //evt_data.evt_data=data;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG("Posted event %d with %s\n",
+ evt_data.event,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+
+ }
+ }
+ else
+ {
+ /*no ipv6 in data searh if seen this client or not*/
+ for (i = 0; i < num_neighbor_client_temp; i++)
+ {
+ if (memcmp(neighbor_client[i].mac_addr, data->mac_addr, sizeof(neighbor_client[i].mac_addr)) == 0)
+ {
+ data->ipv6_addr[0] = neighbor_client[i].v6_addr[0];
+ data->ipv6_addr[1] = neighbor_client[i].v6_addr[1];
+ data->ipv6_addr[2] = neighbor_client[i].v6_addr[2];
+ data->ipv6_addr[3] = neighbor_client[i].v6_addr[3];
+
+ /* check if iface is not bridge0*/
+ if (strcmp(IPA_VIRTUAL_IFACE_NAME, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) != 0)
+ {
+ /* construct IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT command and insert to command-queue */
+ if (event == IPA_NEW_NEIGH_EVENT) evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT;
+ else evt_data.event = IPA_NEIGH_CLIENT_IP_ADDR_DEL_EVENT;
+ memcpy(&evt_data.evt_data, &data, sizeof(evt_data.evt_data));
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG("Posted event %d with %s\n",
+ evt_data.event,
+ IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name);
+
+
+ /* delete that entry*/
+ for (; i <= num_neighbor_client_temp; i++)
+ {
+ memcpy(neighbor_client[i].mac_addr, neighbor_client[i + 1].mac_addr, sizeof(neighbor_client[i].mac_addr));
+ neighbor_client[i].v6_addr[0] = neighbor_client[i + 1].v6_addr[0];
+ neighbor_client[i].v6_addr[1] = neighbor_client[i + 1].v6_addr[1];
+ neighbor_client[i].v6_addr[2] = neighbor_client[i + 1].v6_addr[2];
+ neighbor_client[i].v6_addr[3] = neighbor_client[i + 1].v6_addr[3];
+ neighbor_client[i].iface_index = neighbor_client[i + 1].iface_index;
+ }
+ num_neighbor_client -= 1;
+ };
+ break;
+ };
+ }
+ /* not find client */
+ if (i == num_neighbor_client_temp)
+ {
+ IPACMDBG("ipv6 with bridge0 with mac, not seen before\n");
+ if (num_neighbor_client_temp < IPA_MAX_NUM_NEIGHBOR_CLIENTS)
+ {
+ memcpy(neighbor_client[num_neighbor_client_temp].mac_addr,
+ data->mac_addr,
+ sizeof(data->mac_addr));
+ neighbor_client[num_neighbor_client_temp].iface_index = data->if_index;
+ IPACMDBG("Copy wlan-iface client MAC %02x:%02x:%02x:%02x:%02x:%02x\n, total client: %d\n",
+ neighbor_client[num_neighbor_client_temp].mac_addr[0],
+ neighbor_client[num_neighbor_client_temp].mac_addr[1],
+ neighbor_client[num_neighbor_client_temp].mac_addr[2],
+ neighbor_client[num_neighbor_client_temp].mac_addr[3],
+ neighbor_client[num_neighbor_client_temp].mac_addr[4],
+ neighbor_client[num_neighbor_client_temp].mac_addr[5],
+ num_neighbor_client);
+ num_neighbor_client++;
+ return;
+ }
+ else
+ {
+ IPACMDBG("error: neighbor client oversize!");
+ return;
+ }
+ };
+ }
+ }
+
+ return;
+}
+
diff --git a/ipacm/src/IPACM_Netlink.cpp b/ipacm/src/IPACM_Netlink.cpp
new file mode 100644
index 0000000..eea98ea
--- /dev/null
+++ b/ipacm/src/IPACM_Netlink.cpp
@@ -0,0 +1,1823 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+* Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Netlink.cpp
+
+ @brief
+ This file implements the IPAM Netlink Socket Parer functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include "IPACM_CmdQueue.h"
+#include "IPACM_Defs.h"
+#include "IPACM_Netlink.h"
+#include "IPACM_EvtDispatcher.h"
+#include "IPACM_Log.h"
+
+char dev_pre_name[IF_NAME_LEN];
+struct sockaddr_storage dst_pre_addr;
+
+int ipa_get_if_name(char *if_name, int if_index);
+int find_mask(int ip_v4_last, int *mask_value);
+
+#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+
+/* Opens a netlink socket*/
+static int ipa_nl_open_socket
+(
+ ipa_nl_sk_info_t *sk_info,
+ int protocol,
+ unsigned int grps
+ )
+{
+ int *p_sk_fd;
+ struct sockaddr_nl *p_sk_addr_loc;
+
+ p_sk_fd = &(sk_info->sk_fd);
+ p_sk_addr_loc = &(sk_info->sk_addr_loc);
+
+ /* Open netlink socket for specified protocol */
+ if((*p_sk_fd = socket(AF_NETLINK, SOCK_RAW, protocol)) < 0)
+ {
+ IPACMERR("cannot open netlink socket\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Initialize socket addresses to null */
+ memset(p_sk_addr_loc, 0, sizeof(struct sockaddr_nl));
+
+ /* Populate local socket address using specified groups */
+ p_sk_addr_loc->nl_family = AF_NETLINK;
+ p_sk_addr_loc->nl_pid = getpid();
+ p_sk_addr_loc->nl_groups = grps;
+
+ /* Bind socket to the local address, i.e. specified groups. This ensures
+ that multicast messages for these groups are delivered over this
+ socket. */
+
+ if(bind(*p_sk_fd,
+ (struct sockaddr *)p_sk_addr_loc,
+ sizeof(struct sockaddr_nl)) < 0)
+ {
+ IPACMDBG("Socket bind failed\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Add fd to fdmap array and store read handler function ptr (up to MAX_NUM_OF_FD).*/
+static int ipa_nl_addfd_map
+(
+ ipa_nl_sk_fd_set_info_t *fd_set,
+ int fd,
+ ipa_sock_thrd_fd_read_f read_f
+ )
+{
+ if(fd_set->num_fd < MAX_NUM_OF_FD)
+ {
+ FD_SET(fd, &(fd_set->fdset));
+
+ /* Add fd to fdmap array and store read handler function ptr */
+ fd_set->sk_fds[fd_set->num_fd].sk_fd = fd;
+ fd_set->sk_fds[fd_set->num_fd].read_func = read_f;
+
+ /* Increment number of fds stored in fdmap */
+ fd_set->num_fd++;
+ if(fd_set->max_fd < fd)
+ {
+ fd_set->max_fd = fd;
+ }
+ }
+ else
+ {
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* start socket listener */
+static int ipa_nl_sock_listener_start
+(
+ ipa_nl_sk_fd_set_info_t *sk_fd_set
+ )
+{
+ int i, ret;
+
+ while(true)
+ {
+ if((ret = select(sk_fd_set->max_fd + 1, &(sk_fd_set->fdset), NULL, NULL, NULL)) < 0)
+ {
+ IPACMERR("ipa_nl select failed\n");
+ }
+ else
+ {
+ for(i = 0; i < sk_fd_set->num_fd; i++)
+ {
+
+ if(FD_ISSET(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset)))
+ {
+
+ if(sk_fd_set->sk_fds[i].read_func)
+ {
+ if(IPACM_SUCCESS != ((sk_fd_set->sk_fds[i].read_func)(sk_fd_set->sk_fds[i].sk_fd)))
+ {
+ IPACMERR("Error on read callback[%d] fd=%d\n",
+ i,
+ sk_fd_set->sk_fds[i].sk_fd);
+ }
+ }
+ else
+ {
+ IPACMDBG("No read function\n");
+ }
+ }
+
+ } /* end of for loop*/
+ } /* end of else */
+ } /* end of while */
+
+ return IPACM_SUCCESS;
+}
+
+/* allocate memory for ipa_nl__msg */
+static struct msghdr* ipa_nl_alloc_msg
+(
+ uint32_t msglen
+ )
+{
+ unsigned char *buf = NULL;
+ struct sockaddr_nl *nladdr = NULL;
+ struct iovec *iov = NULL;
+ struct msghdr *msgh = NULL;
+
+ if(IPA_NL_MSG_MAX_LEN < msglen)
+ {
+ IPACMERR("Netlink message exceeds maximum length\n");
+ return NULL;
+ }
+
+ msgh = (struct msghdr *)malloc(sizeof(struct msghdr));
+ if(msgh == NULL)
+ {
+ IPACMERR("Failed malloc for msghdr\n");
+ free(msgh);
+ return NULL;
+ }
+
+ nladdr = (struct sockaddr_nl *)malloc(sizeof(struct sockaddr_nl));
+ if(nladdr == NULL)
+ {
+ IPACMERR("Failed malloc for sockaddr\n");
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ iov = (struct iovec *)malloc(sizeof(struct iovec));
+ if(iov == NULL)
+ {
+ PERROR("Failed malloc for iovec");
+ free(iov);
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ buf = (unsigned char *)malloc(msglen);
+ if(buf == NULL)
+ {
+ IPACMERR("Failed malloc for mglen\n");
+ free(buf);
+ free(iov);
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ memset(nladdr, 0, sizeof(struct sockaddr_nl));
+ nladdr->nl_family = AF_NETLINK;
+
+ memset(msgh, 0x0, sizeof(struct msghdr));
+ msgh->msg_name = nladdr;
+ msgh->msg_namelen = sizeof(struct sockaddr_nl);
+ msgh->msg_iov = iov;
+ msgh->msg_iovlen = 1;
+
+ memset(iov, 0x0, sizeof(struct iovec));
+ iov->iov_base = buf;
+ iov->iov_len = msglen;
+
+ return msgh;
+}
+
+/* release IPA message */
+static void ipa_nl_release_msg
+(
+ struct msghdr *msgh
+ )
+{
+ unsigned char *buf = NULL;
+ struct sockaddr_nl *nladdr = NULL;
+ struct iovec *iov = NULL;
+
+ if(NULL == msgh)
+ {
+ return;
+ }
+
+ nladdr = (struct sockaddr_nl *)msgh->msg_name;
+ iov = msgh->msg_iov;
+ if(msgh->msg_iov)
+ {
+ buf = (unsigned char *)msgh->msg_iov->iov_base;
+ }
+
+ free(buf);
+ free(iov);
+ free(nladdr);
+ free(msgh);
+
+ return;
+}
+
+/* receive and process nl message */
+static int ipa_nl_recv
+(
+ int fd,
+ struct msghdr **msg_pptr,
+ unsigned int *msglen_ptr
+ )
+{
+ struct msghdr *msgh = NULL;
+ int rmsgl;
+
+ msgh = ipa_nl_alloc_msg(IPA_NL_MSG_MAX_LEN);
+ if(NULL == msgh)
+ {
+ IPACMERR("Failed to allocate NL message\n");
+ goto error;
+ }
+
+
+ /* Receive message over the socket */
+ rmsgl = recvmsg(fd, msgh, 0);
+
+ /* Verify that something was read */
+ if(rmsgl <= 0)
+ {
+ PERROR("NL recv error");
+ goto error;
+ }
+
+ /* Verify that NL address length in the received message is expected value */
+ if(sizeof(struct sockaddr_nl) != msgh->msg_namelen)
+ {
+ IPACMERR("rcvd msg with namelen != sizeof sockaddr_nl\n");
+ goto error;
+ }
+
+ /* Verify that message was not truncated. This should not occur */
+ if(msgh->msg_flags & MSG_TRUNC)
+ {
+ IPACMERR("Rcvd msg truncated!\n");
+ goto error;
+ }
+
+ *msg_pptr = msgh;
+ *msglen_ptr = rmsgl;
+
+ return IPACM_SUCCESS;
+
+/* An error occurred while receiving the message. Free all memory before
+ returning. */
+error:
+ ipa_nl_release_msg(msgh);
+ *msg_pptr = NULL;
+ *msglen_ptr = 0;
+
+ return IPACM_FAILURE;
+}
+
+/* decode the rtm netlink message */
+static int ipa_nl_decode_rtm_link
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_link_info_t *link_info
+)
+{
+ struct rtattr *rtah = NULL;
+ /* NL message header */
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+ /* Extract the header data */
+ link_info->metainfo = *(struct ifinfomsg *)NLMSG_DATA(nlh);
+ buflen -= sizeof(struct nlmsghdr);
+ rtah = IFA_RTA(NLMSG_DATA(nlh));
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel address message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_addr
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_addr_info_t *addr_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ addr_info->metainfo = *((struct ifaddrmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ /* Extract the available attributes */
+ addr_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+ rtah = IFA_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case IFA_ADDRESS:
+ addr_info->attr_info.prefix_addr.ss_family = addr_info->metainfo.ifa_family;
+ memcpy(&addr_info->attr_info.prefix_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(addr_info->attr_info.prefix_addr.__ss_padding));
+ addr_info->attr_info.param_mask |= IPA_NLA_PARAM_PREFIXADDR;
+ break;
+
+ default:
+ break;
+
+ }
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel neighbor message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_neigh
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_neigh_info_t *neigh_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ neigh_info->metainfo = *((struct ndmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ /* Extract the available attributes */
+ neigh_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+ rtah = NDA_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case NDA_DST:
+ neigh_info->attr_info.local_addr.ss_family = neigh_info->metainfo.ndm_family;
+ memcpy(&neigh_info->attr_info.local_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(neigh_info->attr_info.local_addr.__ss_padding));
+ break;
+
+ case NDA_LLADDR:
+ memcpy(neigh_info->attr_info.lladdr_hwaddr.sa_data,
+ RTA_DATA(rtah),
+ sizeof(neigh_info->attr_info.lladdr_hwaddr.sa_data));
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel route message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_route
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_route_info_t *route_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ route_info->metainfo = *((struct rtmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ route_info->attr_info.param_mask = IPA_RTA_PARAM_NONE;
+ rtah = RTM_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case RTA_DST:
+ if((route_info->metainfo.rtm_type == RTN_UNICAST) &&
+ (route_info->metainfo.rtm_protocol == RTPROT_BOOT) &&
+ (route_info->metainfo.rtm_scope == RT_SCOPE_LINK) &&
+ (route_info->metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ route_info->metainfo.rtm_type = RTN_BROADCAST;
+ memcpy(&route_info->attr_info.dst_addr.__ss_padding,
+ dst_pre_addr.__ss_padding,
+ sizeof(route_info->attr_info.dst_addr.__ss_padding));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_DST;
+ }
+ else
+ {
+ route_info->attr_info.dst_addr.ss_family = route_info->metainfo.rtm_family;
+ memcpy(&route_info->attr_info.dst_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.dst_addr.__ss_padding));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_DST;
+ }
+ break;
+
+ case RTA_SRC:
+ route_info->attr_info.src_addr.ss_family = route_info->metainfo.rtm_family;
+ memcpy(&route_info->attr_info.src_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.src_addr.__ss_padding));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_SRC;
+ break;
+
+ case RTA_GATEWAY:
+ route_info->attr_info.gateway_addr.ss_family = route_info->metainfo.rtm_family;
+ memcpy(&route_info->attr_info.gateway_addr.__ss_padding,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.gateway_addr.__ss_padding));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_GATEWAY;
+ break;
+
+ case RTA_IIF:
+ memcpy(&route_info->attr_info.iif_index,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.iif_index));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_IIF;
+ break;
+
+ case RTA_OIF:
+ memcpy(&route_info->attr_info.oif_index,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.oif_index));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_OIF;
+ break;
+
+ case RTA_PRIORITY:
+ memcpy(&route_info->attr_info.priority,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.priority));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_PRIORITY;
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* decode the ipa nl-message */
+static int ipa_nl_decode_nlmsg
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_msg_t *msg_ptr
+ )
+{
+ char dev_name[IF_NAME_LEN];
+ int ret_val, mask_value, mask_index, mask_value_v6;
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+ uint32_t if_ipv4_addr =0, if_ipipv4_addr_mask =0, temp =0;
+
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_all *data_all;
+ ipacm_event_data_fid *data_fid;
+ ipacm_event_data_addr *data_addr;
+
+
+ while(NLMSG_OK(nlh, buflen))
+ {
+ IPACMDBG("Received msg:%d from netlink\n", nlh->nlmsg_type)
+ switch(nlh->nlmsg_type)
+ {
+ case RTM_NEWLINK:
+ msg_ptr->type = nlh->nlmsg_type;
+ msg_ptr->link_event = true;
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+ {
+ IPACMERR("Failed to decode rtm link message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("Got RTM_NEWLINK with below values\n");
+ IPACMDBG("RTM_NEWLINK, ifi_change:%d\n", msg_ptr->nl_link_info.metainfo.ifi_change);
+ IPACMDBG("RTM_NEWLINK, ifi_flags:%d\n", msg_ptr->nl_link_info.metainfo.ifi_flags);
+ IPACMDBG("RTM_NEWLINK, ifi_index:%d\n", msg_ptr->nl_link_info.metainfo.ifi_index);
+ IPACMDBG("RTM_NEWLINK, family:%d\n", msg_ptr->nl_link_info.metainfo.ifi_family);
+
+ if(IFF_UP & msg_ptr->nl_link_info.metainfo.ifi_change)
+ {
+ IPACMDBG("\n GOT useful newlink event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+ if(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_UP)
+ {
+ IPACMDBG("Interface %s bring up with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* post link up to command queue */
+ evt_data.event = IPA_LINK_UP_EVENT;
+ IPACMDBG("Posting IPA_LINK_UP_EVENT with if index: %d\n",
+ data_fid->if_index);
+ }
+ else
+ {
+ IPACMDBG("Interface %s bring down with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* post link down to command queue */
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ IPACMDBG("Posting IPA_LINK_DOWN_EVENT with if index: %d\n",
+ data_fid->if_index);
+ }
+
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+
+ }
+ }
+ break;
+
+ case RTM_DELLINK:
+ IPACMDBG("\n GOT dellink event\n");
+ msg_ptr->type = nlh->nlmsg_type;
+ msg_ptr->link_event = true;
+ IPACMDBG("entering rtm decode\n");
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+ {
+ IPACMERR("Failed to decode rtm link message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("Interface %s bring down \n", dev_name);
+
+ /* post link down to command queue */
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ IPACMDBG("posting IPA_LINK_DOWN_EVENT with if idnex:%d\n",
+ data_fid->if_index);
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ break;
+
+ case RTM_NEWADDR:
+ IPACMDBG("\n GOT RTM_NEWADDR event\n");
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_addr(buffer, buflen, &(msg_ptr->nl_addr_info)))
+ {
+ IPACMERR("Failed to decode rtm addr message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_addr_info.metainfo.ifa_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("Interface %s \n", dev_name);
+
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_addr_info.attr_info.prefix_addr.ss_family)
+ {
+ data_addr->iptype = IPA_IP_v6;
+ IPACMDBG("IFA_ADDRESS:IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding)[1] >> 48)));
+
+ memcpy(data_addr->ipv6_addr,
+ msg_ptr->nl_addr_info.attr_info.prefix_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+ }
+ else
+ {
+ data_addr->iptype = IPA_IP_v4;
+ IPACMDBG("IFA_ADDRESS:IPV4 %d.%d.%d.%d\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_addr_info.attr_info.prefix_addr).__ss_padding >> 24));
+
+ memcpy(&data_addr->ipv4_addr,
+ msg_ptr->nl_addr_info.attr_info.prefix_addr.__ss_padding,
+ sizeof(data_addr->ipv4_addr));
+ data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+ }
+
+ evt_data.event = IPA_ADDR_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_addr_info.metainfo.ifa_index;
+
+ IPACMDBG("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv4 addr:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ break;
+
+ case RTM_NEWROUTE:
+
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+ {
+ IPACMERR("Failed to decode rtm route message\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("In case RTM_NEWROUTE\n");
+ IPACMDBG("rtm_type: %d\n", msg_ptr->nl_route_info.metainfo.rtm_type);
+ IPACMDBG("ss_padding: %d\n", ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)));
+ IPACMDBG("rtm_type: %d\n", msg_ptr->nl_route_info.metainfo.rtm_type);
+ IPACMDBG("protocol: %d\n", msg_ptr->nl_route_info.metainfo.rtm_protocol);
+ IPACMDBG("rtm_scope: %d\n", msg_ptr->nl_route_info.metainfo.rtm_scope);
+ IPACMDBG("rtm_table: %d\n", msg_ptr->nl_route_info.metainfo.rtm_table);
+ IPACMDBG("rtm_family: %d\n", msg_ptr->nl_route_info.metainfo.rtm_family);
+ IPACMDBG("param_mask: 0x%x\n", msg_ptr->nl_route_info.attr_info.param_mask);
+
+ /* ipv4 interface route and its subnet mask */
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_BROADCAST) &&
+ ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)) != 0)
+ {
+ if(IPACM_SUCCESS !=
+ find_mask((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24), &mask_value))
+ {
+ IPACMERR("Failed to decode rtm_addroute message\n");
+ }
+ else
+ {
+ IPACMDBG("\n GOT useful RTM_NEWROUTE event\n");
+
+ /* take care of subnet mask */
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACMDBG("DST_ADDRESS:IPV4 %d.%d.%d.0\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16));
+ IPACMDBG("MASK:IPV4 255.255.255.%d\n", mask_value);
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name");
+ }
+ IPACMDBG("RTA_OIF, output Interface %s \n", dev_name);
+ memcpy(&dst_pre_addr.__ss_padding,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(dst_pre_addr.__ss_padding));
+ memcpy(&dev_pre_name,
+ dev_name,
+ sizeof(dev_pre_name));
+ IPACMDBG("save pre_DST_ADDRESS:IPV4 %d.%d.%d.%d %s\n",
+ (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(dst_pre_addr).__ss_padding >> 24), dev_pre_name);
+ }
+
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("route add -net %d.%d.%d.0 netmask 255.255.255.%d dev %s metric %d \n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ mask_value,
+ dev_pre_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG("route add -net %d.%d.%d.0 netmask 255.255.255.%d dev %s \n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ mask_value,
+ dev_name);
+ }
+
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ if_ipv4_addr = (if_ipv4_addr << 8) >> 8;
+ temp = (-1) << 8;
+ temp = temp | mask_value;
+
+ /* insert to command queue */
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 address 0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+
+
+ /* take care of route add default route & uniroute */
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_scope == RT_SCOPE_UNIVERSE) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT RTM_NEWROUTE event\n");
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+
+ IPACMDBG("route add -host %d.%d.%d.%d gw %d.%d.%d.%d dev %s\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+ dev_name
+ );
+
+ /* insert to command queue */
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ temp = (-1);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+
+ if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+ {
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("ip -6 route add default dev %s metric %d\n",
+ dev_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG("ip -6 route add default dev %s\n", dev_name);
+ }
+
+ memcpy(data_addr->ipv6_addr,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+
+ memcpy(data_addr->ipv6_addr_mask,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr_mask));
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ }
+ else
+ {
+ IPACMDBG("route add default gw %d.%d.%d.%d dev %s dstIP: %d.%d.%d.%d\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+ dev_name,
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)
+ );
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ memcpy(&if_ipipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipipv4_addr_mask));
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 addr:0x%x and maxk: 0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+ }
+
+ /* ipv6 routing table */
+ if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT valid v6-RTM_NEWROUTE event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACMDBG("Route ADD IPV6 DST: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%d, metric %d, dev %s\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 48)),
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMDBG("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(data_addr->ipv6_addr,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+
+ mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+ for(mask_index = 0; mask_index < 4; mask_index++)
+ {
+ if(mask_value_v6 >= 32)
+ {
+ mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 -= 32;
+ }
+ else
+ {
+ mask_v6(mask_value_v6, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 = 0;
+ }
+ }
+
+ IPACMDBG("ADD IPV6 MASK %d: %08x:%08x:%08x:%08x \n",
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ data_addr->ipv6_addr_mask[0],
+ data_addr->ipv6_addr_mask[1],
+ data_addr->ipv6_addr_mask[2],
+ data_addr->ipv6_addr_mask[3]);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 addr\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_GATEWAY)
+ {
+ IPACMDBG("Route ADD ::/0 Next Hop: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, metric %d, dev %s\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 48)),
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+ memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr_mask));
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+
+ }
+ break;
+
+ case RTM_DELROUTE:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+ {
+ IPACMDBG("Failed to decode rtm route message\n");
+ return IPACM_FAILURE;
+ }
+
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_BROADCAST) &&
+ ((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24)) != 0)
+ {
+ if(IPACM_SUCCESS != find_mask((unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24), &mask_value))
+ {
+ IPACMERR("Failed to decode rtm_delroute message\n");
+ }
+ else
+ {
+ IPACMDBG("\n GOT useful RTM_DELROUTE event\n");
+
+ /* take care of subnet mask */
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACMDBG("DST_ADDRESS:IPV4 %d.%d.%d.0\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16));
+ IPACMDBG("MASK:IPV4 255.255.255.%d\n", mask_value);
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("RTA_OIF, output Interface %s \n", dev_name);
+ }
+ IPACMDBG("route del -net %d.%d.%d.0 netmask 255.255.255.%d dev %s \n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ mask_value,
+ dev_name);
+
+ /* post event to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("Priority %d \n",
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else;
+
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ if_ipv4_addr = (if_ipv4_addr << 8) >> 8;
+ temp = (-1) << 8;
+ temp = temp | mask_value;
+ if_ipipv4_addr_mask = ntohl(temp);
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with ifindex:%d, ipv4 address 0x%x, mask:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+
+ /* take care of route delete of default route & uniroute */
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_scope == 0) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("route del -host %d.%d.%d.%d gw %d.%d.%d.%d dev %s\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding >> 24),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+ dev_name
+ );
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(&if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(if_ipv4_addr));
+ temp = (-1);
+ if_ipipv4_addr_mask = ntohl(temp);
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+ {
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("ip -6 route del default dev %s metric %d\n",
+ dev_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG("ip -6 route del default dev %s\n", dev_name);
+ }
+ memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+ memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr_mask));
+ data_addr->iptype = IPA_IP_v6;
+ }
+ else
+ {
+ IPACMDBG("route del default gw %d.%d.%d.%d dev %s\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding >> 24),
+ dev_name);
+
+ memcpy(&data_addr->ipv4_addr,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv4_addr));
+ data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+ memcpy(&data_addr->ipv4_addr_mask,
+ msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv4_addr_mask));
+ data_addr->ipv4_addr_mask = ntohl(data_addr->ipv4_addr_mask);
+
+ data_addr->iptype = IPA_IP_v4;
+ }
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+
+ IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with if index:%d\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+
+ /* ipv6 routing table */
+ if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT valid v6-RTM_DELROUTE event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name");
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACMDBG("DEL IPV6 DST: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%d, metric %d, dev %s\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.dst_addr).__ss_padding)[1] >> 48)),
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+
+ mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+ for(mask_index = 0; mask_index < 4; mask_index++)
+ {
+ IPACMDBG("%dst %d \n",
+ mask_index,
+ mask_value_v6);
+ if(mask_value_v6 >= 32)
+ {
+ mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 -= 32;
+ IPACMDBG("%dst: %08x \n",
+ mask_index,
+ data_addr->ipv6_addr_mask[mask_index]);
+ }
+ else
+ {
+ mask_v6(mask_value_v6, data_addr->ipv6_addr_mask);
+ mask_value_v6 = 0;
+ IPACMDBG("%dst: %08x \n",
+ mask_index,
+ data_addr->ipv6_addr_mask[mask_index]);
+ }
+ }
+
+ IPACMDBG("DEL IPV6 MASK 0st: %08x ",
+ data_addr->ipv6_addr_mask[0]);
+ IPACMDBG("1st: %08x ",
+ data_addr->ipv6_addr_mask[1]);
+ IPACMDBG("2st: %08x ",
+ data_addr->ipv6_addr_mask[2]);
+ IPACMDBG("3st: %08x \n",
+ data_addr->ipv6_addr_mask[3]);
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_GATEWAY)
+ {
+ IPACMDBG("DEL ::/0 Next Hop: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x, metric %d, dev %s\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_route_info.attr_info.gateway_addr).__ss_padding)[1] >> 48)),
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+ memcpy(data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr));
+ memcpy(data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr.__ss_padding,
+ sizeof(data_addr->ipv6_addr_mask));
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("Posting IPA_ROUTE_DEL_EVENT with if index: %d, ipv6 addr\n",
+ data_addr->if_index)
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+
+ }
+ break;
+
+ case RTM_NEWNEIGH:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+ {
+ IPACMERR("Failed to decode rtm neighbor message\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("RTM_NEWNEIGH, ndm_state:0x%x", msg_ptr->nl_neigh_info.metainfo.ndm_state)
+ if((NUD_PERMANENT | NUD_STALE) & (msg_ptr->nl_neigh_info.metainfo.ndm_state))
+ {
+ IPACMDBG("\n GOT RTM_NEWNEIGH event\n");
+ /* insert to command queue */
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if(data_all == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_all\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family)
+ {
+ IPACMDBG("IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 48)));
+
+ memcpy(data_all->ipv6_addr,
+ msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+ sizeof(data_all->ipv6_addr));
+ data_all->iptype = IPA_IP_v6;
+ }
+ else
+ {
+ IPACMDBG("IPV4 %d.%d.%d.%d\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 24));
+
+
+ memcpy(&data_all->ipv4_addr,
+ msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+ sizeof(data_all->ipv4_addr));
+ data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+ data_all->iptype = IPA_IP_v4;
+ }
+
+ memcpy(data_all->mac_addr,
+ msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+ sizeof(data_all->mac_addr));
+ evt_data.event = IPA_NEW_NEIGH_EVENT;
+ data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+
+ IPACMDBG("posting IPA_NEW_NEIGH_EVENT with if index:%d\n",
+ data_all->if_index);
+ evt_data.evt_data = data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface index\n");
+ }
+ else
+ {
+ IPACMDBG("Interface %s \n", dev_name);
+ }
+ }
+ break;
+
+ case RTM_DELNEIGH:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+ {
+ IPACMERR("Failed to decode rtm neighbor message\n");
+ return IPACM_FAILURE;
+ }
+
+ if((NUD_PERMANENT | NUD_STALE) & (msg_ptr->nl_neigh_info.metainfo.ndm_state))
+ {
+ IPACMDBG("\n GOT RTM_DELNEIGH event\n");
+ /* insert to command queue */
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if(data_all == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_all\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family)
+ {
+ IPACMDBG("IPV6 %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[0] >> 48)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1])),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 16)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 32)),
+ (uint16_t)(ntohs(((uint64_t *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding)[1] >> 48)));
+
+ memcpy(data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+ sizeof(data_all->ipv6_addr));
+ data_all->iptype = IPA_IP_v6;
+ }
+ else
+ {
+ IPACMDBG("IPV4 %d.%d.%d.%d\n",
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 8),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 16),
+ (unsigned char)(*(unsigned int *)&(msg_ptr->nl_neigh_info.attr_info.local_addr).__ss_padding >> 24));
+
+
+ memcpy(&data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr.__ss_padding,
+ sizeof(data_all->ipv4_addr));
+ data_all->iptype = IPA_IP_v4;
+ }
+
+ memcpy(data_all->mac_addr,
+ msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+ sizeof(data_all->mac_addr));
+ evt_data.event = IPA_DEL_NEIGH_EVENT;
+ data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+
+ IPACMDBG("posting IPA_DEL_NEIGH_EVENT with if index:%d\n",
+ data_all->if_index);
+ evt_data.evt_data = data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ //IPACM_LOG_MSG("Error while getting interface index");
+ }
+ else
+ {
+ IPACMDBG("Interface %s \n", dev_name);
+ }
+ }
+ break;
+
+ default:
+ IPACMDBG(" ignore NL event %d!!!\n ", nlh->nlmsg_type);
+ break;
+
+ }
+ nlh = NLMSG_NEXT(nlh, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+
+/* Virtual function registered to receive incoming messages over the NETLINK routing socket*/
+int ipa_nl_recv_msg(int fd)
+{
+ struct msghdr *msghdr = NULL;
+ //struct sockaddr_nl *nladdr = NULL;
+ struct iovec *iov = NULL;
+ unsigned int msglen = 0;
+ ipa_nl_msg_t *nlmsg = NULL;
+
+ nlmsg = (ipa_nl_msg_t *)malloc(sizeof(ipa_nl_msg_t));
+ if(NULL == nlmsg)
+ {
+ IPACMERR("Failed alloc of nlmsg \n");
+ goto error;
+ }
+ else
+ {
+ if(IPACM_SUCCESS != ipa_nl_recv(fd, &msghdr, &msglen))
+ {
+ IPACMERR("Failed to receive nl message \n");
+ goto error;
+ }
+
+ //nladdr = (struct sockaddr_nl *)msghdr->msg_name;
+ iov = msghdr->msg_iov;
+
+ memset(nlmsg, 0, sizeof(ipa_nl_msg_t));
+ if(IPACM_SUCCESS != ipa_nl_decode_nlmsg((char *)iov->iov_base, msglen, nlmsg))
+ {
+ IPACMERR("Failed to decode nl message \n");
+ goto error;
+ }
+
+ ipa_nl_release_msg(msghdr);
+ free(nlmsg);
+ }
+
+ return IPACM_SUCCESS;
+
+error:
+ if(msghdr)
+ {
+ ipa_nl_release_msg(msghdr);
+ }
+ if(nlmsg)
+ {
+ free(nlmsg);
+ }
+
+ return IPACM_FAILURE;
+}
+
+/* get ipa interface name */
+int ipa_get_if_name
+(
+ char *if_name,
+ int if_index
+ )
+{
+ int fd;
+ struct ifreq ifr;
+
+ if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ IPACMERR("get interface name socket create failed \n");
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ ifr.ifr_ifindex = if_index;
+ IPACMDBG("Interface index %d\n", if_index);
+
+ if(ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+ {
+ IPACMERR("call_ioctl_on_dev: ioctl failed:\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ (void)strncpy(if_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+ IPACMDBG("interface name %s\n", ifr.ifr_name);
+ close(fd);
+
+ return IPACM_SUCCESS;
+}
+
+/* Initialization routine for listener on NetLink sockets interface */
+int ipa_nl_listener_init
+(
+ unsigned int nl_type,
+ unsigned int nl_groups,
+ ipa_nl_sk_fd_set_info_t *sk_fdset,
+ ipa_sock_thrd_fd_read_f read_f
+ )
+{
+ ipa_nl_sk_info_t sk_info, sk_info2;
+ int ret_val;
+
+ memset(&sk_info, 0, sizeof(ipa_nl_sk_info_t));
+ IPACMDBG("Entering IPA NL listener init\n");
+
+ if(ipa_nl_open_socket(&sk_info, nl_type, nl_groups) == IPACM_SUCCESS)
+ {
+ IPACMDBG("IPA Open netlink socket succeeds\n");
+ }
+ else
+ {
+ IPACMERR("Netlink socket open failed\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Add NETLINK socket to the list of sockets that the listener
+ thread should listen on. */
+
+ if(ipa_nl_addfd_map(sk_fdset, sk_info.sk_fd, read_f) != IPACM_SUCCESS)
+ {
+ IPACMERR("cannot add nl routing sock for reading\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Start the socket listener thread */
+ ret_val = ipa_nl_sock_listener_start(sk_fdset);
+
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Failed to start NL listener\n");
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* find the newroute subnet mask */
+int find_mask(int ip_v4_last, int *mask_value)
+{
+
+ switch(ip_v4_last)
+ {
+
+ case 3:
+ *mask_value = 252;
+ return IPACM_SUCCESS;
+ break;
+
+ case 7:
+ *mask_value = 248;
+ return IPACM_SUCCESS;
+ break;
+
+ case 15:
+ *mask_value = 240;
+ return IPACM_SUCCESS;
+ break;
+
+ case 31:
+ *mask_value = 224;
+ return IPACM_SUCCESS;
+ break;
+
+ case 63:
+ *mask_value = 192;
+ return IPACM_SUCCESS;
+ break;
+
+ case 127:
+ *mask_value = 128;
+ return IPACM_SUCCESS;
+ break;
+
+ case 255:
+ *mask_value = 0;
+ return IPACM_SUCCESS;
+ break;
+
+ default:
+ return IPACM_FAILURE;
+ break;
+
+ }
+}
+
+/* map mask value for ipv6 */
+int mask_v6(int index, uint32_t *mask)
+{
+ switch(index)
+ {
+
+ case 0:
+ *mask = 0x00000000;
+ return IPACM_SUCCESS;
+ break;
+ case 4:
+ *mask = 0xf0000000;
+ return IPACM_SUCCESS;
+ break;
+ case 8:
+ *mask = 0xff000000;
+ return IPACM_SUCCESS;
+ break;
+ case 12:
+ *mask = 0xfff00000;
+ return IPACM_SUCCESS;
+ break;
+ case 16:
+ *mask = 0xffff0000;
+ return IPACM_SUCCESS;
+ break;
+ case 20:
+ *mask = 0xfffff000;
+ return IPACM_SUCCESS;
+ break;
+ case 24:
+ *mask = 0xffffff00;
+ return IPACM_SUCCESS;
+ break;
+ case 28:
+ *mask = 0xfffffff0;
+ return IPACM_SUCCESS;
+ break;
+ case 32:
+ *mask = 0xffffffff;
+ return IPACM_SUCCESS;
+ break;
+ default:
+ return IPACM_FAILURE;
+ break;
+
+ }
+}
+
+
diff --git a/ipacm/src/IPACM_Routing.cpp b/ipacm/src/IPACM_Routing.cpp
new file mode 100644
index 0000000..1351fbe
--- /dev/null
+++ b/ipacm/src/IPACM_Routing.cpp
@@ -0,0 +1,226 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Routing.cpp
+
+ @brief
+ This file implements the IPACM routing functionality.
+
+ @Author
+
+*/
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "IPACM_Routing.h"
+#include <IPACM_Log.h>
+
+const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa";
+
+IPACM_Routing::IPACM_Routing()
+{
+ m_fd = open(DEVICE_NAME, O_RDWR);
+ if (0 == m_fd)
+ {
+ IPACMDBG("Failed opening %s.\n", DEVICE_NAME);
+ }
+}
+
+IPACM_Routing::~IPACM_Routing()
+{
+ close(m_fd);
+}
+
+bool IPACM_Routing::DeviceNodeIsOpened()
+{
+ int res = fcntl(m_fd, F_GETFL);
+
+ if (m_fd > 0 && res >= 0) return true;
+ else return false;
+
+}
+
+bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened())
+ {
+ IPACMDBG("Device is not opened\n");
+ return false;
+ }
+
+ retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
+ if (retval)
+ {
+ IPACMERR("Failed adding routing rule %p\n", ruleTable);
+ return false;
+ }
+
+ IPACMDBG("Added routing rule %p\n", ruleTable);
+ return true;
+}
+
+bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
+ if (retval)
+ {
+ IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
+ return false;
+ }
+
+ IPACMDBG("Deleted routing rule %p\n", ruleTable);
+ return true;
+}
+
+bool IPACM_Routing::Commit(enum ipa_ip_type ip)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+ if (retval)
+ {
+ IPACMERR("Failed commiting routing rules.\n");
+ return false;
+ }
+
+ IPACMDBG("Commited routing rules to IPA HW.\n");
+ return true;
+}
+
+bool IPACM_Routing::Reset(enum ipa_ip_type ip)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
+ retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
+ if (retval)
+ {
+ IPACMERR("Failed resetting routing block.\n");
+ return false;
+ }
+
+ IPACMDBG("Reset command issued to IPA routing block.\n");
+ return true;
+}
+
+bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
+ if (retval)
+ {
+ IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
+ return false;
+ }
+
+ IPACMDBG("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
+ return true;
+}
+
+bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
+{
+ int retval = 0;
+
+ if (!DeviceNodeIsOpened()) return false;
+
+ retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
+ if (retval)
+ {
+ IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
+ return false;
+ }
+
+ IPACMDBG("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
+ return true;
+}
+
+bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
+{
+ const uint8_t NUM_RULES = 1;
+ struct ipa_ioc_del_rt_rule *rt_rule;
+ struct ipa_rt_rule_del *rt_rule_entry;
+ bool res = true;
+ int len = 0;
+
+ if (rt_rule_hdl == 0)
+ {
+ IPACMERR("Invalid route handle passed. Ignoring it\n");
+ return false;
+ }
+
+ len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
+ rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
+ if (rt_rule == NULL)
+ {
+ IPACMERR("unable to allocate memory for del route rule\n");
+ return false;
+ }
+
+ memset(rt_rule, 0, len);
+ rt_rule->commit = 1;
+ rt_rule->num_hdls = NUM_RULES;
+ rt_rule->ip = ip;
+
+ rt_rule_entry = &rt_rule->hdl[0];
+ rt_rule_entry->status = -1;
+ rt_rule_entry->hdl = rt_rule_hdl;
+
+ IPACMDBG("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
+ if ((false == DeleteRoutingRule(rt_rule)) ||
+ (rt_rule_entry->status))
+ {
+ PERROR("Routing rule deletion failed!\n");
+ goto fail;
+ res = false;
+ }
+
+fail:
+ free(rt_rule);
+
+ return res;
+}
+
diff --git a/ipacm/src/IPACM_Wan.cpp b/ipacm/src/IPACM_Wan.cpp
new file mode 100644
index 0000000..1a45dc5
--- /dev/null
+++ b/ipacm/src/IPACM_Wan.cpp
@@ -0,0 +1,1249 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Wan.cpp
+
+ @brief
+ This file implements the WAN iface functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include <string.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Xml.h>
+#include <IPACM_Log.h>
+#include "IPACM_EvtDispatcher.h"
+#include <IPACM_IfaceManager.h>
+
+bool IPACM_Wan::wan_up = false;
+
+IPACM_Wan::IPACM_Wan(int iface_index) : IPACM_Iface(iface_index)
+{
+ num_firewall_v4 = 0;
+ num_firewall_v6 = 0;
+ num_dft_rt = 0;
+
+ wan_route_rule_v4_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+ wan_route_rule_v6_hdl = (uint32_t *)calloc(iface_query->num_tx_props, sizeof(uint32_t));
+
+ active_v4 = false;
+ active_v6 = false;
+
+ IPACMDBG(" IPACM->IPACM_Wan(%d) constructor: Tx:%d\n", ipa_if_num, iface_query->num_tx_props);
+ return;
+}
+
+IPACM_Wan::~IPACM_Wan()
+{
+ IPACM_EvtDispatcher::deregistr(this);
+ IPACM_IfaceManager::deregistr(this);
+ return;
+}
+
+/* handle new_address event */
+int IPACM_Wan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ const int NUM_RULES = 1;
+ int res = IPACM_SUCCESS;
+
+ /* initial multicast/broadcast/fragment filter rule */
+ init_fl_rule(data->iptype);
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM_RULES * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = NUM_RULES;
+ rt_rule->ip = data->iptype;
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ }
+ else
+ {
+ strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+ }
+
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 1;
+ rt_rule_entry->rule.dst = IPA_CLIENT_A5_LAN_WAN_CONS; //go to A5
+ rt_rule_entry->rule.attrib.attrib_mask = IPA_FLT_DST_ADDR;
+
+
+ if (data->iptype == IPA_IP_v6)
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ }
+ else
+ {
+ /* still need setup v4 default routing rule to A5*/
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+
+ wan_v4_addr = data->ipv4_addr;
+ IPACMDBG("Receved wan address:0x%x\n", wan_v4_addr);
+ }
+
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (rt_rule_entry->status)
+ {
+ IPACMERR("rt rule adding failed. Result=%d\n", rt_rule_entry->status);
+ res = rt_rule_entry->status;
+ goto fail;
+ }
+ IPACMDBG("rt rule hdl=%x with ip-type: %d\n", rt_rule_entry->rt_rule_hdl, data->iptype);
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ dft_rt_rule_hdl[0] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG("ipv4 wan rt rule hdl1=0x%x\n", dft_rt_rule_hdl[0]);
+ }
+ else
+ {
+ dft_rt_rule_hdl[1 + num_dft_rt] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG("ipv6 wan rt rule hdl1=0x%x\n", dft_rt_rule_hdl[1 + num_dft_rt]);
+ num_dft_rt++;
+ }
+
+
+fail:
+ free(rt_rule);
+
+ return res;
+}
+
+void IPACM_Wan::event_callback(ipa_cm_event_id event, void *param)
+{
+ int ipa_interface_index;
+
+ switch (event)
+ {
+
+ case IPA_LINK_DOWN_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ IPACMDBG("ipa_WAN (%s):ipa_index (%d) instance close \n", IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ delete this;
+ return;
+ }
+ }
+ break;
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+ {
+ IPACMDBG("Received IPA_ADDR_ADD_EVENT\n");
+ handle_addr_evt(data);
+ }
+ }
+ }
+ break;
+
+ case IPA_ROUTE_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ROUTE_ADD_EVENT\n");
+ IPACMDBG("ipv4 addr 0x%x\n", data->ipv4_addr);
+ IPACMDBG("ipv4 addr mask 0x%x\n", data->ipv4_addr_mask);
+
+ /* The special below condition is to handle default gateway */
+ if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask))
+ {
+ IPACMDBG("adding routing table\n");
+ handle_route_add_evt(data);
+ IPACM_Wan::wan_up = true;
+ active_v4 = true;
+ config_dft_firewall_rules(IPA_IP_v4);
+ }
+ else if ((data->iptype == IPA_IP_v6) &&
+ (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]))
+ {
+ IPACMDBG("\n get default v6 route (dst:00.00.00.00)\n");
+ IPACMDBG(" IPV6 value: %08x:%08x:%08x:%08x \n",
+ data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);
+ handle_route_add_evt(data);
+ active_v6 = true;
+ config_dft_firewall_rules(IPA_IP_v6);
+ }
+ }
+ }
+ break;
+
+ case IPA_ROUTE_DEL_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_ROUTE_DEL_EVENT\n");
+ if ((data->iptype == IPA_IP_v4) && (!data->ipv4_addr) && (!data->ipv4_addr_mask))
+ {
+ IPACMDBG("get del default v4 route (dst:0.0.0.0)\n");
+ del_dft_firewall_rules(IPA_IP_v4);
+ handle_route_del_evt(data->iptype);
+ IPACM_Wan::wan_up = false;
+ }
+ else if ((data->iptype == IPA_IP_v6) && (!data->ipv6_addr[0]) && (!data->ipv6_addr[1]) && (!data->ipv6_addr[2]) && (!data->ipv6_addr[3]))
+ {
+ IPACMDBG("get del default v6 route (dst:00.00.00.00)\n");
+ del_dft_firewall_rules(IPA_IP_v6);
+ handle_route_del_evt(data->iptype);
+ }
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+ IPACMDBG("I'm in the WAN\n");
+ handle_header_add_evt(data->mac_addr);
+ }
+ }
+ break;
+
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+ /* handle software routing enable event */
+ handle_software_routing_enable();
+ break;
+
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+ /* handle software routing disable event */
+ handle_software_routing_disable();
+ break;
+
+ case IPA_FIREWALL_CHANGE_EVENT:
+ IPACMDBG("Received IPA_FIREWALL_CHANGE_EVENT\n");
+ /* handle software routing enable event */
+ if (active_v4)
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ config_dft_firewall_rules(IPA_IP_v4);
+ }
+
+ if (active_v6)
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ config_dft_firewall_rules(IPA_IP_v6);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+/* wan default route/filter rule configuration */
+int IPACM_Wan::handle_route_add_evt(ipacm_event_data_addr *data)
+{
+
+ /* add default WAN route */
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ struct ipa_ioc_get_hdr sRetHeader;
+ uint32_t tx_index;
+ const int NUM = 1;
+ ipacm_cmd_q_data evt_data;
+
+ IPACMDBG(" ip-type:%d\n", data->iptype);
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ NUM * sizeof(struct ipa_rt_rule_add));
+
+ if (!rt_rule)
+ {
+ IPACMERR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = (uint8_t)NUM;
+ rt_rule->ip = data->iptype;
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.name);
+ }
+ else
+ {
+ strcpy(rt_rule->rt_tbl_name, IPACM_Iface::ipacmcfg->rt_tbl_v6.name);
+ }
+
+ IPACMDBG(" WAN table created %s \n", rt_rule->rt_tbl_name);
+ rt_rule_entry = &rt_rule->rules[0];
+ rt_rule_entry->at_rear = 1;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (data->iptype != tx_prop->tx[tx_index].ip)
+ {
+ continue;
+ }
+
+ if (tx_prop->tx[tx_index].hdr_name != NULL)
+ {
+ IPACMDBG(" TX- header hdl %s \n", tx_prop->tx[tx_index].hdr_name);
+ memset(&sRetHeader, 0, sizeof(sRetHeader));
+ strncpy(sRetHeader.name,
+ tx_prop->tx[tx_index].hdr_name,
+ sizeof(tx_prop->tx[tx_index].hdr_name));
+ if (false == m_header.GetHeaderHandle(&sRetHeader))
+
+ {
+ IPACMERR("\n ioctl failed\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ rt_rule_entry->rule.hdr_hdl = sRetHeader.hdl;
+ }
+
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ if (data->iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = data->ipv4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = data->ipv4_addr_mask;
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = data->ipv6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = data->ipv6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = data->ipv6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = data->ipv6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = data->ipv6_addr_mask[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = data->ipv6_addr_mask[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = data->ipv6_addr_mask[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = data->ipv6_addr_mask[3];
+ }
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ wan_route_rule_v4_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG("Got ipv4 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+ wan_route_rule_v4_hdl[tx_index],
+ tx_index,
+ data->iptype);
+ }
+ else
+ {
+ wan_route_rule_v6_hdl[tx_index] = rt_rule_entry->rt_rule_hdl;
+ IPACMDBG("Got ipv6 wan-route rule hdl:0x%x,tx:%d,ip-type: %d \n",
+ wan_route_rule_v6_hdl[tx_index],
+ tx_index,
+ data->iptype);
+ }
+ }
+ free(rt_rule);
+
+ if (data->iptype == IPA_IP_v4)
+ {
+ ipacm_event_iface_up *wanup_data;
+
+ wanup_data =
+ (ipacm_event_iface_up *)malloc(sizeof(ipacm_event_iface_up));
+ if (wanup_data == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return IPACM_FAILURE;
+ }
+
+ memcpy(wanup_data->ifname, dev_name, sizeof(wanup_data->ifname));
+ wanup_data->ipv4_addr = wan_v4_addr;
+ IPACMDBG("Posting IPA_HANDLE_WAN_UP with below information:\n");
+ IPACMDBG("if_name:%s, ipv4_address:0x%x\n",
+ wanup_data->ifname, wanup_data->ipv4_addr);
+
+ evt_data.event = IPA_HANDLE_WAN_UP;
+ evt_data.evt_data = (void *)wanup_data;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* wan default route/filter rule delete */
+int IPACM_Wan::handle_route_del_evt(ipa_ip_type iptype)
+{
+ uint32_t tx_index;
+ ipacm_cmd_q_data evt_data;
+
+ IPACMDBG("got handle_route_del_evt with ip-family:%d \n", iptype);
+
+ if (((iptype == IPA_IP_v4) && (active_v4 == true)) ||
+ ((iptype == IPA_IP_v6) && (active_v6 == true)))
+ {
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype == IPA_IP_v4)
+ {
+
+ if (m_routing.DeleteRoutingHdl(wan_route_rule_v4_hdl[tx_index], IPA_IP_v4)
+ == false)
+ {
+ IPACMDBG("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v4, wan_route_rule_v4_hdl[tx_index], tx_index);
+ return IPACM_FAILURE;
+ }
+
+ }
+ else
+ {
+ if (m_routing.DeleteRoutingHdl(wan_route_rule_v6_hdl[tx_index], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("IP-family:%d, Routing rule(hdl:0x%x) deletion failed with tx_index %d!\n", IPA_IP_v6, wan_route_rule_v6_hdl[tx_index], tx_index);
+ return IPACM_FAILURE;
+ }
+ }
+
+ }
+
+ if (iptype == IPA_IP_v4)
+ {
+
+ uint32_t *wan_ip_addr = (uint32_t *)malloc(sizeof(uint32_t));
+ if (wan_ip_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory\n");
+ return IPACM_FAILURE;
+ }
+
+ *wan_ip_addr = wan_v4_addr;
+ evt_data.event = IPA_HANDLE_WAN_DOWN;
+ evt_data.evt_data = (void *)wan_ip_addr;
+ /* Insert IPA_HANDLE_WAN_DOWN to command queue */
+ IPACMDBG("posting IPA_HANDLE_WAN_DOWN for IPv4 \n");
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACM_Wan::wan_up = false;
+ active_v4 = false;
+ }
+ else
+ {
+ active_v6 = false;
+ }
+ }
+ else
+ {
+ IPACMDBG(" The default WAN routing rules are deleted already \n");
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* construct complete ethernet header */
+int IPACM_Wan::handle_header_add_evt(uint8_t mac_addr[6])
+{
+ char index[2];
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+ uint32_t tx_index;
+ int len = 0;
+
+ IPACMDBG("construct header\n");
+
+ /* start of add header */
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ /* add header to IPA */
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (!pHeaderDescriptor)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+
+ /* copy partial header */
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name, tx_prop->tx[tx_index].hdr_name,
+ sizeof(tx_prop->tx[tx_index].hdr_name));
+
+ IPACMDBG("header name: %s\n", sCopyHeader.name);
+ if (false == m_header.CopyHeader(&sCopyHeader))
+ {
+ IPACMERR("ioctl copy header failed\n");
+ free(pHeaderDescriptor);
+ return IPACM_FAILURE;
+ };
+
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ free(pHeaderDescriptor);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr, sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[IPA_WLAN_PARTIAL_HDR_OFFSET], mac_addr,
+ IPA_MAC_ADDR_SIZE); /* only copy 6 bytes mac-address */
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+ sprintf(index, "%d", ipa_if_num);
+ strncpy(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+ strncat(pHeaderDescriptor->hdr[0].name, IPA_WLAN_PARTIAL_HDR_NAME, sizeof(IPA_WLAN_PARTIAL_HDR_NAME));
+ strncat(pHeaderDescriptor->hdr[0].name, "tx", sizeof("tx"));
+ sprintf(index, "%d", tx_index);
+ strncat(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+ pHeaderDescriptor->hdr[0].hdr_len = sizeof(sCopyHeader.hdr_len);
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = false;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (false == m_header.AddHeader(pHeaderDescriptor))
+ {
+ IPACMERR("ioctl add header failed\n");
+ free(pHeaderDescriptor);
+ return IPACM_FAILURE;
+ }
+
+ memcpy(tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].name,
+ sizeof(tx_prop->tx[tx_index].hdr_name));
+ IPACMDBG("add full header name: %s (%x)\n", tx_prop->tx[tx_index].hdr_name, pHeaderDescriptor->hdr[0].hdr_hdl);
+
+
+ free(pHeaderDescriptor);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* configure the initial firewall filter rules */
+int IPACM_Wan::config_dft_firewall_rules(ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i, rule_v4 = 0, rule_v6 = 0;
+
+ IPACMDBG("ip-family: %d; \n", iptype);
+ memset(&firewall_config, 0, sizeof(firewall_config));
+ strncpy(firewall_config.firewall_config_file, "/etc/mobileap_firewall.xml", sizeof(firewall_config.firewall_config_file));
+
+ if (firewall_config.firewall_config_file)
+ {
+ IPACMDBG("Firewall XML file is %s \n", firewall_config.firewall_config_file);
+ if (IPACM_SUCCESS == IPACM_read_firewall_xml(firewall_config.firewall_config_file, &firewall_config))
+ {
+ IPACMDBG("QCMAP Firewall XML read OK \n");
+ }
+ else
+ {
+ IPACMERR("QCMAP Firewall XML read failed \n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMERR("No firewall xml mentioned \n");
+ return IPACM_FAILURE;
+ }
+
+ /* find the number of v4/v6 firewall rules */
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+ {
+ rule_v4++;
+ }
+ else
+ {
+ rule_v6++;
+ }
+ }
+
+ IPACMDBG("firewall rule v4:%d v6:%d total:%d\n", rule_v4, rule_v6, firewall_config.num_extd_firewall_entries);
+
+ /* construct ipa_ioc_add_flt_rule with N firewall rules */
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ if (iptype == IPA_IP_v4)
+ {
+ if (rule_v4 == 0)
+ {
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add));
+
+ if (!m_pFilteringTable)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_lan_v4) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+ else
+ {
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (m_pFilteringTable == NULL)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ IPACMDBG("Retreiving Routing handle for routing table name:%s\n",
+ IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name);
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ IPACMERR("m_routing.GetRoutingTable(&rt_tbl_lan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_lan_v4);
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Routing handle for wan routing table:0x%x\n", IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl);
+
+ rule_v4 = 0;
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 4)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION; //Matched the firewall rule, go exception
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+
+ memcpy(&flt_rule_entry.rule.attrib,
+ &firewall_config.extd_firewall_entries[i].attrib,
+ sizeof(struct ipa_rule_attrib));
+
+ IPACMDBG("rx property attrib mask: 0x%x\n", rx_prop->rx[0].attrib.attrib_mask);
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ /* check if the rule is define as TCP_UDP, split into 2 rules, 1 for TCP and 1 UDP */
+ if (firewall_config.extd_firewall_entries[i].attrib.u.v4.protocol
+ == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+ {
+ /* insert TCP rule*/
+ flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_TCP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v4 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+
+ /* insert UDP rule*/
+ flt_rule_entry.rule.attrib.u.v4.protocol = IPACM_FIREWALL_IPPROTO_UDP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v4 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+ }
+ else
+ {
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v4 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n",
+ m_pFilteringTable->rules[rule_v4].flt_rule_hdl,
+ m_pFilteringTable->rules[rule_v4].status);
+ firewall_hdl_v4[rule_v4] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v4++;
+ rule_v4++;
+ }
+ }
+ }
+ } /* end of firewall ipv4 filter rule add for loop*/
+
+ /* configure default filter rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ IPACMDBG("Filter rule attrib mask: 0x%x\n",
+ m_pFilteringTable->rules[0].rule.attrib.attrib_mask);
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+
+ }
+ else
+ {
+ if (rule_v6 == 0)
+ {
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add));
+
+
+ if (!m_pFilteringTable)
+ {
+ IPACMERR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_v6) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+ else
+ {
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ IPACMDBG("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = rx_prop->rx[0].src_pipe;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ IPACMERR("m_routing.GetRoutingTable(rt_tbl_v6) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ rule_v6 = 0;
+ for (i = 0; i < firewall_config.num_extd_firewall_entries; i++)
+ {
+ if (firewall_config.extd_firewall_entries[i].ip_vsn == 6)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+
+ flt_rule_entry.rule.action = IPA_PASS_TO_DST_NAT;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &firewall_config.extd_firewall_entries[i].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= rx_prop->rx[0].attrib.attrib_mask;
+ flt_rule_entry.rule.attrib.meta_data_mask = rx_prop->rx[0].attrib.meta_data_mask;
+ flt_rule_entry.rule.attrib.meta_data = rx_prop->rx[0].attrib.meta_data;
+
+ /* check if the rule is define as TCP/UDP */
+ if (firewall_config.extd_firewall_entries[i].attrib.u.v6.next_hdr == IPACM_FIREWALL_IPPROTO_TCP_UDP)
+ {
+ /* insert TCP rule*/
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_TCP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v4 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+
+ /* insert UDP rule*/
+ flt_rule_entry.rule.attrib.u.v6.next_hdr = IPACM_FIREWALL_IPPROTO_UDP;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v6 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+ }
+ else
+ {
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ /* save v6 firewall filter rule handler */
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ firewall_hdl_v6[rule_v6] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ num_firewall_v6++;
+ rule_v6++;
+ }
+ }
+ }
+ } /* end of firewall ipv6 filter rule add for loop*/
+
+ /* setup default wan filter rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(struct ipa_rule_attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ IPACMERR("Error Adding Filtering rules, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+ /* copy filter hdls*/
+ dft_wan_fl_hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+ }
+ }
+ return IPACM_SUCCESS;
+}
+
+
+
+/*handle wan-iface down event */
+int IPACM_Wan::handle_down_evt()
+{
+ int res = IPACM_SUCCESS;
+ int i;
+
+ IPACMDBG(" wan handle_down_evt \n");
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ goto fail;
+ }
+
+ /* make sure default routing rules and firewall rules are deleted*/
+ if (ip_type != IPA_IP_v6)
+ {
+ del_dft_firewall_rules(IPA_IP_v4);
+ handle_route_del_evt(IPA_IP_v4);
+ }
+
+ if (ip_type != IPA_IP_v4)
+ {
+ del_dft_firewall_rules(IPA_IP_v6);
+ handle_route_del_evt(IPA_IP_v6);
+ }
+
+ /* Delete default v4 RT rule */
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG("Delete default v4 routing rules\n");
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+ == false)
+ {
+ IPACMDBG("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* delete default v6 RT rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ IPACMDBG("Delete default v6 routing rules\n");
+ /* May have multiple ipv6 iface-routing rules*/
+ for (i = 0; i < num_dft_rt; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[1 + i], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ IPACMDBG("finished delete default v6 RT rules\n ");
+ }
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true)
+ {
+ IPACM_Iface::handle_software_routing_disable();
+ handle_software_routing_disable();
+ }
+
+ /* free filter rule handlers */
+ if (ip_type != IPA_IP_v6)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+ IPA_IP_v4,
+ IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("Error Delete Filtering rules, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("finished delete default v4 filtering rules\n ");
+ }
+
+
+ if (ip_type != IPA_IP_v4)
+ {
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+ IPA_IP_v6,
+ IPV6_DEFAULT_FILTERTING_RULES) == false)
+ {
+ IPACMERR("ErrorDeleting Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("finished delete default v6 filtering rules\n ");
+ }
+
+fail:
+ free(tx_prop);
+ free(rx_prop);
+ free(iface_query);
+
+ return res;
+}
+
+/*clean firewall filter rules */
+int IPACM_Wan::del_dft_firewall_rules(ipa_ip_type iptype)
+{
+ /* free v4 firewall filter rule */
+ if ((iptype == IPA_IP_v4) && (active_v4 == true))
+ {
+ if (num_firewall_v4 != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(firewall_hdl_v4,
+ IPA_IP_v4, num_firewall_v4) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMDBG("No ipv4 firewall rules, no need deleted\n");
+ }
+
+ if (m_filtering.DeleteFilteringHdls(dft_wan_fl_hdl,
+ IPA_IP_v4, 1) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+
+ num_firewall_v4 = 0;
+ }
+
+ /* free v6 firewall filter rule */
+ if ((iptype == IPA_IP_v6) && (active_v6 == true))
+ {
+ if (num_firewall_v6 != 0)
+ {
+ if (m_filtering.DeleteFilteringHdls(firewall_hdl_v6,
+ IPA_IP_v6, num_firewall_v6) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ IPACMDBG("No ipv6 firewall rules, no need deleted\n");
+ }
+
+ if (m_filtering.DeleteFilteringHdls(&dft_wan_fl_hdl[1],
+ IPA_IP_v6, 1) == false)
+ {
+ IPACMERR("Error Deleting Filtering rules, aborting...\n");
+ return IPACM_FAILURE;
+ }
+ num_firewall_v6 = 0;
+ }
+
+ return IPACM_SUCCESS;
+}
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
new file mode 100644
index 0000000..0160406
--- /dev/null
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -0,0 +1,1421 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+* Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+@file
+IPACM_Wlan.cpp
+
+@brief
+This file implements the WLAN iface functionality.
+
+@Author
+Skylar Chang
+
+*/
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <IPACM_Wlan.h>
+#include <IPACM_Netlink.h>
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <IPACM_Wan.h>
+#include <IPACM_Lan.h>
+#include <IPACM_IfaceManager.h>
+
+/* static member to store the number of total wifi clients within all APs*/
+int IPACM_Wlan::total_num_wifi_clients = 0;
+
+IPACM_Wlan::IPACM_Wlan(int iface_index) : IPACM_Lan(iface_index)
+{
+#define WLAN_AMPDU_DEFAULT_FILTER_RULES 3
+
+ num_wifi_client = 0;
+ header_name_count = 0;
+
+ /* one for WAN and two for Soft-routing */
+ wlan_ampdu_flt_rule.num_rules = WLAN_AMPDU_DEFAULT_FILTER_RULES;
+
+ wlan_ampdu_flt_rule.hdl[0] = 0; /* for WAN */
+ wlan_ampdu_flt_rule.ip[0] = IPA_IP_v4; /* for WAN */
+
+ wlan_ampdu_flt_rule.hdl[1] = 0; /* for Soft-routing */
+ wlan_ampdu_flt_rule.ip[1] = IPA_IP_v4; /* for Soft-routing */
+
+ wlan_ampdu_flt_rule.hdl[2] = 0; /* for Soft-routing */
+ wlan_ampdu_flt_rule.ip[2] = IPA_IP_v6; /* for Soft-routing */
+
+ wlan_client_len = (sizeof(ipa_wlan_client)) + (iface_query->num_tx_props * sizeof(wlan_client_rt_hdl));
+ wlan_client = (ipa_wlan_client *)calloc(IPA_MAX_NUM_WIFI_CLIENTS, wlan_client_len);
+ if (wlan_client == NULL)
+ {
+ IPACMERR("unable to allocate memory\n");
+ return;
+ }
+
+ IPACMDBG("index:%d constructor: Tx properties:%d\n", iface_index, iface_query->num_tx_props);
+ return;
+}
+
+
+IPACM_Wlan::~IPACM_Wlan()
+{
+ IPACM_EvtDispatcher::deregistr(this);
+ IPACM_IfaceManager::deregistr(this);
+ return;
+}
+
+void IPACM_Wlan::event_callback(ipa_cm_event_id event, void *param)
+{
+ int ipa_interface_index;
+
+ switch (event)
+ {
+
+ case IPA_LINK_DOWN_EVENT:
+ {
+ ipacm_event_data_fid *data = (ipacm_event_data_fid *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_LINK_DOWN_EVENT\n");
+ handle_down_evt();
+ IPACMDBG("ipa_WLAN (%s):ipa_index (%d) instance close \n",
+ IPACM_Iface::ipacmcfg->iface_table[ipa_if_num].iface_name, ipa_if_num);
+ delete this;
+ return;
+ }
+ }
+ break;
+
+ case IPA_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_addr *data = (ipacm_event_data_addr *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+
+ if (ipa_interface_index == ipa_if_num)
+ {
+ if ((data->iptype != ip_type) && (ip_type != IPA_IP_MAX)) // check not setup before
+ {
+ /* Post event to NAT */
+ if (data->iptype == IPA_IP_v4)
+ {
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_iface_up *info;
+
+ info = (ipacm_event_iface_up *)
+ malloc(sizeof(ipacm_event_iface_up));
+ if (info == NULL)
+ {
+ IPACMERR("Unable to allocate memory\n");
+ return;
+ }
+
+ memcpy(info->ifname, dev_name, IF_NAME_LEN);
+ info->ipv4_addr = data->ipv4_addr;
+ info->addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[0].subnet_mask;
+
+ evt_data.event = IPA_HANDLE_WLAN_UP;
+ evt_data.evt_data = (void *)info;
+
+ /* Insert IPA_HANDLE_WLAN_UP to command queue */
+ IPACMDBG("posting IPA_HANDLE_WLAN_UP for IPv4 with below information\n");
+ IPACMDBG("IPv4 address:0x%x, IPv4 address mask:0x%x\n",
+ info->ipv4_addr, info->addr_mask);
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ IPACM_Lan::handle_addr_evt(data);
+ handle_addr_evt(data);
+
+ IPACM_Lan::handle_private_subnet(data->iptype);
+ handle_private_subnet(data->iptype);
+
+ if (IPACM_Wan::isWanUP() && (data->iptype == IPA_IP_v4))
+ {
+ IPACM_Lan::handle_wan_up();
+ handle_wan_up();
+ }
+
+ IPACMDBG("posting IPA_HANDLE_WLAN_UP:Finished checking wan_up\n");
+ }
+ }
+ }
+ break;
+
+ case IPA_HANDLE_WAN_UP:
+ IPACMDBG("Received IPA_HANDLE_WAN_UP event\n");
+ IPACM_Lan::handle_wan_up();
+ handle_wan_up();
+ break;
+
+ case IPA_HANDLE_WAN_DOWN:
+ IPACMDBG("Received IPA_HANDLE_WAN_DOWN event\n");
+ IPACM_Lan::handle_wan_down();
+ handle_wan_down();
+ break;
+
+ case IPA_WLAN_CLIENT_ADD_EVENT:
+ {
+ ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_WLAN_CLIENT_ADD_EVENT\n");
+ handle_wlan_client_init(data->mac_addr);
+ }
+ }
+ break;
+
+ case IPA_WLAN_CLIENT_DEL_EVENT:
+ {
+ ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_WLAN_CLIENT_DEL_EVENT\n");
+ handle_wlan_client_down_evt(data->mac_addr);
+ }
+ }
+ break;
+
+ case IPA_WLAN_CLIENT_POWER_SAVE_EVENT:
+ {
+ ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_WLAN_CLIENT_POWER_SAVE_EVENT\n");
+ handle_wlan_client_pwrsave(data->mac_addr);
+ }
+ }
+ break;
+
+ case IPA_WLAN_CLIENT_RECOVER_EVENT:
+ {
+ ipacm_event_data_mac *data = (ipacm_event_data_mac *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_WLAN_CLIENT_RECOVER_EVENT\n");
+ if (ip_type != IPA_IP_v6) /* for ipv4 */
+ {
+ handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v4);
+ }
+
+ if (ip_type != IPA_IP_v4) /* for ipv6 */
+ {
+ handle_wlan_client_route_rule(data->mac_addr, IPA_IP_v6);
+ }
+ }
+ }
+ break;
+
+ case IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT:
+ {
+ ipacm_event_data_all *data = (ipacm_event_data_all *)param;
+ ipa_interface_index = iface_ipa_index_query(data->if_index);
+ if (ipa_interface_index == ipa_if_num)
+ {
+ IPACMDBG("Received IPA_NEIGH_CLIENT_IP_ADDR_ADD_EVENT\n");
+ if (handle_wlan_client_ipaddr(data) == IPACM_FAILURE)
+ {
+ return;
+ }
+ handle_wlan_client_route_rule(data->mac_addr, data->iptype);
+ }
+ }
+ break;
+
+ /* handle software routing enable event*/
+ case IPA_SW_ROUTING_ENABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_ENABLE\n");
+ IPACM_Iface::handle_software_routing_enable();
+ handle_software_routing_enable();
+ break;
+
+ /* handle software routing disable event*/
+ case IPA_SW_ROUTING_DISABLE:
+ IPACMDBG("Received IPA_SW_ROUTING_DISABLE\n");
+ IPACM_Iface::handle_software_routing_disable();
+ handle_software_routing_disable();
+ break;
+
+ default:
+ break;
+ }
+ return;
+}
+
+/* handle wifi client initial,copy all partial headers (tx property) */
+int IPACM_Wlan::handle_wlan_client_init(uint8_t *mac_addr)
+{
+
+#define WLAN_IFACE_INDEX_LEN 2
+
+ int res = IPACM_SUCCESS, len = 0;
+ char index[WLAN_IFACE_INDEX_LEN];
+ struct ipa_ioc_copy_hdr sCopyHeader;
+ struct ipa_ioc_add_hdr *pHeaderDescriptor = NULL;
+
+ /* start of adding header */
+ if ((num_wifi_client >= IPA_MAX_NUM_WIFI_CLIENTS) ||
+ (IPACM_Wlan::total_num_wifi_clients >= IPA_MAX_NUM_WIFI_CLIENTS))
+ {
+ IPACMERR("Reached maximum number of wlan clients\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("Wifi client number: %d\n", num_wifi_client);
+
+ IPACMDBG("Received Client MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ memcpy(get_client_memptr(wlan_client, num_wifi_client)->mac,
+ mac_addr,
+ sizeof(get_client_memptr(wlan_client, num_wifi_client)->mac));
+
+ IPACMDBG("stored MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ get_client_memptr(wlan_client, num_wifi_client)->mac[0],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[1],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[2],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[3],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[4],
+ get_client_memptr(wlan_client, num_wifi_client)->mac[5]);
+
+ /* add header to IPA */
+ len = sizeof(struct ipa_ioc_add_hdr) + (1 * sizeof(struct ipa_hdr_add));
+ pHeaderDescriptor = (struct ipa_ioc_add_hdr *)calloc(1, len);
+ if (pHeaderDescriptor == NULL)
+ {
+ IPACMERR("calloc failed to allocate pHeaderDescriptor\n");
+ return IPACM_FAILURE;
+ }
+
+ /* copy partial header */
+ memset(&sCopyHeader, 0, sizeof(sCopyHeader));
+ memcpy(sCopyHeader.name,
+ tx_prop->tx[0].hdr_name,
+ sizeof(sCopyHeader.name));
+
+ IPACMDBG("header name: %s\n", sCopyHeader.name);
+ if (m_header.CopyHeader(&sCopyHeader) == false)
+ {
+ PERROR("ioctl copy header failed");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("header length: %d, paritial: %d\n", sCopyHeader.hdr_len, sCopyHeader.is_partial);
+ if (sCopyHeader.hdr_len > IPA_HDR_MAX_SIZE)
+ {
+ IPACMERR("header oversize\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else
+ {
+ memcpy(pHeaderDescriptor->hdr[0].hdr,
+ sCopyHeader.hdr,
+ sCopyHeader.hdr_len);
+ }
+
+ /* copy client mac_addr to partial header */
+ memcpy(&pHeaderDescriptor->hdr[0].hdr[IPA_WLAN_PARTIAL_HDR_OFFSET],
+ get_client_memptr(wlan_client, num_wifi_client)->mac,
+ IPA_MAC_ADDR_SIZE);
+
+ pHeaderDescriptor->commit = true;
+ pHeaderDescriptor->num_hdrs = 1;
+
+ memset(pHeaderDescriptor->hdr[0].name, 0,
+ sizeof(pHeaderDescriptor->hdr[0].name));
+
+ sprintf(index, "%d", ipa_if_num);
+ strncpy(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+ strncat(pHeaderDescriptor->hdr[0].name,
+ IPA_WLAN_PARTIAL_HDR_NAME,
+ sizeof(IPA_WLAN_PARTIAL_HDR_NAME));
+
+ sprintf(index, "%d", header_name_count);
+ strncat(pHeaderDescriptor->hdr[0].name, index, sizeof(index));
+
+ pHeaderDescriptor->hdr[0].hdr_len = sCopyHeader.hdr_len;
+ pHeaderDescriptor->hdr[0].hdr_hdl = -1;
+ pHeaderDescriptor->hdr[0].is_partial = 0;
+ pHeaderDescriptor->hdr[0].status = -1;
+
+ if (m_header.AddHeader(pHeaderDescriptor) == false ||
+ pHeaderDescriptor->hdr[0].status != 0)
+ {
+ IPACMERR("ioctl IPA_IOC_ADD_HDR failed: %d\n", pHeaderDescriptor->hdr[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl = pHeaderDescriptor->hdr[0].hdr_hdl;
+ IPACMDBG("client(%d) full header name:%s header handle:(0x%x)\n",
+ num_wifi_client,
+ pHeaderDescriptor->hdr[0].name,
+ get_client_memptr(wlan_client, num_wifi_client)->hdr_hdl);
+ /* initialize wifi client*/
+ get_client_memptr(wlan_client, num_wifi_client)->route_rule_set_v4 = false;
+ get_client_memptr(wlan_client, num_wifi_client)->route_rule_set_v6 = false;
+ get_client_memptr(wlan_client, num_wifi_client)->ipv4_set = false;
+ get_client_memptr(wlan_client, num_wifi_client)->ipv6_set = false;
+
+ num_wifi_client++;
+ header_name_count++; //keep increasing header_name_count
+ IPACM_Wlan::total_num_wifi_clients++;
+ res = IPACM_SUCCESS;
+
+ IPACMDBG("Wifi client number: %d\n", num_wifi_client);
+
+fail:
+ free(pHeaderDescriptor);
+
+ return res;
+}
+
+/*handle wifi client */
+int IPACM_Wlan::handle_wlan_client_ipaddr(ipacm_event_data_all *data)
+{
+ int clnt_indx;
+
+ IPACMDBG("number of wifi clients: %d\n", num_wifi_client);
+ IPACMDBG(" event MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ data->mac_addr[0],
+ data->mac_addr[1],
+ data->mac_addr[2],
+ data->mac_addr[3],
+ data->mac_addr[4],
+ data->mac_addr[5]);
+
+ clnt_indx = get_wlan_client_index(data->mac_addr);
+ if (clnt_indx == IPACM_INVALID_INDEX)
+ {
+ if (clnt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG("wlan client not found/attached \n");
+ return IPACM_FAILURE;
+ }
+ }
+
+ IPACMDBG("Ip type received %d\n", data->iptype);
+ if (data->iptype == IPA_IP_v4)
+ {
+ IPACMDBG("Ipv4 with ipv4 address: 0x%x\n", data->ipv4_addr);
+ if (data->ipv4_addr != 0) /* not 0.0.0.0 */
+ {
+ if (get_client_memptr(wlan_client, clnt_indx)->ipv4_set == false)
+ {
+ get_client_memptr(wlan_client, clnt_indx)->v4_addr = data->ipv4_addr;
+ get_client_memptr(wlan_client, clnt_indx)->ipv4_set = true;
+ }
+ else
+ {
+ IPACMDBG("Already setup ipv4 addr for client:%d\n", clnt_indx);
+ }
+ }
+ }
+ else
+ {
+ if ((data->ipv6_addr[0] != 0) || (data->ipv6_addr[1] != 0) ||
+ (data->ipv6_addr[2] != 0) || (data->ipv6_addr[3] || 0)) /* check if all 0 not valid ipv6 address */
+ {
+ if (get_client_memptr(wlan_client, clnt_indx)->ipv6_set == false)
+ {
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[0] = data->ipv6_addr[0];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[1] = data->ipv6_addr[1];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[2] = data->ipv6_addr[2];
+ get_client_memptr(wlan_client, clnt_indx)->v6_addr[3] = data->ipv6_addr[3];
+ get_client_memptr(wlan_client, clnt_indx)->ipv6_set = true;
+ }
+ else
+ {
+ IPACMDBG("Already setup ipv6 addr for client:%d\n", clnt_indx);
+ }
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle wifi client routing rule*/
+int IPACM_Wlan::handle_wlan_client_route_rule(uint8_t *mac_addr, ipa_ip_type iptype)
+{
+ struct ipa_ioc_add_rt_rule *rt_rule;
+ struct ipa_rt_rule_add *rt_rule_entry;
+ uint32_t tx_index;
+ int wlan_index;
+
+ IPACMDBG("Received mac_addr MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2],
+ mac_addr[3], mac_addr[4], mac_addr[5]);
+
+ wlan_index = get_wlan_client_index(mac_addr);
+ if (wlan_index == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG("wlan client not found/attached \n");
+ return IPACM_SUCCESS;
+ }
+
+ IPACMDBG("wlan client index: %d, ip-type: %d, ipv4_set:%d, ipv4_rule_set:%d \n", wlan_index, iptype,
+ get_client_memptr(wlan_client, wlan_index)->ipv4_set,
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4);
+ /* Add default 4 Qos routing rules if not set yet */
+ if ((iptype == IPA_IP_v4
+ && get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 == false
+ && get_client_memptr(wlan_client, wlan_index)->ipv4_set == true)
+ || (iptype == IPA_IP_v6
+ && get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 == false
+ && get_client_memptr(wlan_client, wlan_index)->ipv6_set == true))
+ {
+ IPACMDBG("client index(%d):ipv4 address: 0x%x\n", wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->v4_addr);
+
+ IPACMDBG("client(%d): header handle:(0x%x), num of rules: %d\n",
+ wlan_index,
+ get_client_memptr(wlan_client, wlan_index)->hdr_hdl,
+ iface_query->num_tx_props);
+
+
+ rt_rule = (struct ipa_ioc_add_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_add_rt_rule) +
+ (iface_query->num_tx_props * sizeof(struct ipa_rt_rule_add)));
+
+ if (rt_rule == NULL)
+ {
+ PERROR("Error Locate ipa_ioc_add_rt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = iface_query->num_tx_props;
+ rt_rule->ip = iptype;
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype == IPA_IP_v4)
+ {
+ strncpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.name,
+ sizeof(rt_rule->rt_tbl_name));
+ }
+ else
+ {
+ strncpy(rt_rule->rt_tbl_name,
+ IPACM_Iface::ipacmcfg->rt_tbl_v6.name,
+ sizeof(rt_rule->rt_tbl_name));
+ }
+
+ rt_rule_entry = &rt_rule->rules[tx_index];
+ rt_rule_entry->at_rear = 0;
+ rt_rule_entry->rule.dst = tx_prop->tx[tx_index].dst_pipe;
+ rt_rule_entry->rule.hdr_hdl = get_client_memptr(wlan_client, wlan_index)->hdr_hdl;
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[tx_index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+
+ if (iptype == IPA_IP_v4)
+ {
+ rt_rule_entry->rule.attrib.u.v4.dst_addr = get_client_memptr(wlan_client, wlan_index)->v4_addr;
+ rt_rule_entry->rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+ }
+ else if (iptype == IPA_IP_v6)
+ {
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[0] = get_client_memptr(wlan_client, wlan_index)->v6_addr[0];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[1] = get_client_memptr(wlan_client, wlan_index)->v6_addr[1];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[2] = get_client_memptr(wlan_client, wlan_index)->v6_addr[2];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr[3] = get_client_memptr(wlan_client, wlan_index)->v6_addr[3];
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[0] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[1] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[2] = 0xFFFFFFFF;
+ rt_rule_entry->rule.attrib.u.v6.dst_addr_mask[3] = 0xFFFFFFFF;
+ }
+ } /* end of for loop */
+
+ if (false == m_routing.AddRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule addition failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (iptype == IPA_IP_v4)
+ {
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+ rt_rule->rules[tx_index].rt_rule_hdl;
+ IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4, iptype);
+ }
+ else if (iptype == IPA_IP_v6)
+ {
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6 =
+ rt_rule->rules[tx_index].rt_rule_hdl;
+ IPACMDBG("tx:%d, rt rule hdl=%x ip-type: %d\n", tx_index,
+ get_client_memptr(wlan_client, wlan_index)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6, iptype);
+ }
+ }
+
+ free(rt_rule);
+
+ if (iptype == IPA_IP_v4)
+ {
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v4 = true;
+ }
+ else
+ {
+ get_client_memptr(wlan_client, wlan_index)->route_rule_set_v6 = true;
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/*handle wifi client power-save mode*/
+int IPACM_Wlan::handle_wlan_client_pwrsave(uint8_t *mac_addr)
+{
+ int clt_indx;
+ IPACMDBG("wlan->handle_wlan_client_pwrsave();\n");
+
+ clt_indx = get_wlan_client_index(mac_addr);
+ if (clt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG("wlan client not attached\n");
+ return IPACM_SUCCESS;
+ }
+
+ /*check if got duplicate power-save mode*/
+ if ((ip_type != IPA_IP_v6 && get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 == true)
+ || (ip_type != IPA_IP_v4 && get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 == true))
+ {
+ return delete_default_qos_rtrules(clt_indx);
+ }
+ else
+ {
+ IPACMDBG("wlan client already in power-save mode\n");
+ return IPACM_SUCCESS;
+ }
+}
+
+/*handle wifi client del mode*/
+int IPACM_Wlan::handle_wlan_client_down_evt(uint8_t *mac_addr)
+{
+ int clt_indx;
+ uint32_t tx_index;
+ int num_wifi_client_tmp = num_wifi_client;
+
+ IPACMDBG("total client: %d\n", num_wifi_client_tmp);
+
+ clt_indx = get_wlan_client_index(mac_addr);
+ if (clt_indx == IPACM_INVALID_INDEX)
+ {
+ IPACMDBG("wlan client not attached\n");
+ return IPACM_SUCCESS;
+ }
+
+ if (delete_default_qos_rtrules(clt_indx))
+ {
+ IPACMDBG("unbale to delete default qos route rules\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Delete wlan client header */
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, clt_indx)->hdr_hdl)
+ == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ /* Reset ip_set to 0*/
+ get_client_memptr(wlan_client, clt_indx)->ipv4_set = false;
+ get_client_memptr(wlan_client, clt_indx)->ipv6_set = false;
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = false;
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = false;
+
+ for (; clt_indx < num_wifi_client_tmp - 1; clt_indx++)
+ {
+ memcpy(get_client_memptr(wlan_client, clt_indx)->mac,
+ get_client_memptr(wlan_client, (clt_indx + 1))->mac,
+ sizeof(get_client_memptr(wlan_client, clt_indx)->mac));
+
+ get_client_memptr(wlan_client, clt_indx)->hdr_hdl = get_client_memptr(wlan_client, (clt_indx + 1))->hdr_hdl;
+ get_client_memptr(wlan_client, clt_indx)->v4_addr = get_client_memptr(wlan_client, (clt_indx + 1))->v4_addr;
+
+ get_client_memptr(wlan_client, clt_indx)->ipv4_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv4_set;
+ get_client_memptr(wlan_client, clt_indx)->ipv6_set = get_client_memptr(wlan_client, (clt_indx + 1))->ipv6_set;
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v4 = get_client_memptr(wlan_client, (clt_indx + 1))->route_rule_set_v4;
+ get_client_memptr(wlan_client, clt_indx)->route_rule_set_v6 = get_client_memptr(wlan_client, (clt_indx + 1))->route_rule_set_v6;
+
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[0] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[0];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[1] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[1];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[2] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[2];
+ get_client_memptr(wlan_client, clt_indx)->v6_addr[3] = get_client_memptr(wlan_client, (clt_indx + 1))->v6_addr[3];
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4 =
+ get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+
+ get_client_memptr(wlan_client, clt_indx)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6 =
+ get_client_memptr(wlan_client, (clt_indx + 1))->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6;
+ }
+ }
+
+ IPACMDBG(" %d wifi client deleted successfully \n", num_wifi_client);
+ num_wifi_client = num_wifi_client - 1;
+ IPACM_Wlan::total_num_wifi_clients = IPACM_Wlan::total_num_wifi_clients - 1;
+ IPACMDBG(" Number of wifi client: %d\n", num_wifi_client);
+
+ return IPACM_SUCCESS;
+}
+
+/* duplicate ampdu filter rules for wan_up event */
+int IPACM_Wlan::handle_wan_up(void)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ IPACMDBG("Wlan->handle_wan_up(); \n");
+
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4))
+ {
+ IPACMDBG("m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_wan_v4=0x%p) Failed.\n", &IPACM_Iface::ipacmcfg->rt_tbl_wan_v4);
+ return IPACM_FAILURE;
+ }
+
+ memset(&flt_rule_entry, 0, sizeof(ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_SRC_NAT; //IPA_PASS_TO_ROUTING
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_wan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ /* Match-all rule */
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0x00000000;
+
+ memcpy(&m_pFilteringTable->rules[0], &flt_rule_entry, sizeof(flt_rule_entry));
+ if (m_filtering.AddFilteringRule(m_pFilteringTable) == false)
+ {
+ IPACMDBG("Error Adding Filtering Rule, aborting...\n");
+ perror("Wlan: Unable to add filtering table");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[0] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ free(m_pFilteringTable);
+
+ return IPACM_SUCCESS;
+}
+
+
+/*delete ampdu filter rules for wan_down event*/
+int IPACM_Wlan::handle_wan_down(void)
+{
+ IPACMDBG("\n");
+
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[0],
+ IPA_IP_v4, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ wlan_ampdu_flt_rule.hdl[0] = 0;
+
+ return IPACM_SUCCESS;
+}
+
+/*duplicate ampdu filter rules for software_routing event*/
+int IPACM_Wlan::handle_software_routing_enable(void)
+{
+
+ struct ipa_flt_rule_add flt_rule_entry;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+ int res = IPACM_SUCCESS;
+
+ IPACMDBG("\n");
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ 1 * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->num_rules = (uint8_t)1;
+
+
+ /* Configuring Software_routing Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = false;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+
+/* check iface is v4 or v6 or both*/
+ if (ip_type == IPA_IP_MAX)
+ {
+ /* handle v4 */
+ m_pFilteringTable->ip = IPA_IP_v4;
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+
+
+ /* handle v6*/
+ m_pFilteringTable->ip = IPA_IP_v6;
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+
+ }
+ else
+ {
+ if (ip_type == IPA_IP_v4) m_pFilteringTable->ip = IPA_IP_v4;
+ else m_pFilteringTable->ip = IPA_IP_v6;
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering rule, aborting...\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ else if (m_pFilteringTable->rules[0].status)
+ {
+ IPACMDBG("adding flt rule failed status=0x%x\n", m_pFilteringTable->rules[0].status);
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("soft-routing flt rule hdl0=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl);
+ /* copy filter hdls */
+ if (ip_type == IPA_IP_v4) wlan_ampdu_flt_rule.hdl[1] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ else wlan_ampdu_flt_rule.hdl[2] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ }
+
+fail:
+ free(m_pFilteringTable);
+
+ return res;
+
+}
+
+/*delete ampdu filter rules for disabling software_routing event*/
+int IPACM_Wlan::handle_software_routing_disable(void)
+{
+
+ if (ip_type == IPA_IP_MAX)
+ {
+ /* ipv4 case */
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[1],
+ IPA_IP_v4, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ /* ipv6 case */
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[2],
+ IPA_IP_v6, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+
+ }
+ else
+ {
+ if (ip_type == IPA_IP_v4)
+ {
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[1],
+ IPA_IP_v4, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ else if (ip_type == IPA_IP_v6)
+ {
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[2],
+ IPA_IP_v6, 1) == false)
+ {
+ return IPACM_FAILURE;
+ }
+ }
+ }
+
+ return IPACM_SUCCESS;
+}
+
+
+/*duplicate ampdu filter rules for initial iface configuration*/
+int IPACM_Wlan::init_fl_rule(ipa_ip_type iptype)
+{
+ int res = IPACM_SUCCESS;
+ struct ipa_flt_rule_add flt_rule_entry;
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ IPACMDBG("ip-type: %d\n", iptype);
+
+ if (iptype == IPA_IP_v4)
+ {
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ IPV4_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV4_DEFAULT_FILTERTING_RULES;
+
+ /* Configuring Fragment Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_FRAGMENT;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring Multicast Filtering Rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xF0000000;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xE0000000; /* DST_IP == 224.0.0.0 */
+ memcpy(&(m_pFilteringTable->rules[1]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ /* Configuring Broadcast Filtering Rule */
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = 0xFFFFFFFF;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = 0xFFFFFFFF; /* Filter DST_IP == 127.0.0.1 */
+ memcpy(&(m_pFilteringTable->rules[2]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding RuleTable(2) to Filtering, aborting...\n");
+ res = IPACM_FAILURE;
+ }
+ else
+ {
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 1] = m_pFilteringTable->rules[1].flt_rule_hdl;
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 2] = m_pFilteringTable->rules[2].flt_rule_hdl;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v4;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 1] = IPA_IP_v4;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 2] = IPA_IP_v4;
+ wlan_ampdu_flt_rule.num_rules += IPV4_DEFAULT_FILTERTING_RULES;
+ }
+ }
+ else
+ {
+ /* IPv6 filter rule configuration */
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ IPV6_DEFAULT_FILTERTING_RULES * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_flt_rule_add memory...\n");
+ return IPACM_FAILURE;
+ }
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = iptype;
+ m_pFilteringTable->num_rules = (uint8_t)IPV6_DEFAULT_FILTERTING_RULES;
+
+ /* Configuring Fragment Filtering Rule */
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_EXCEPTION;
+
+ /* Configuring Multicast Filtering Rule */
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0xFF000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0XFF000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding Filtering Rule, aborting...\n");
+ res = IPACM_FAILURE;
+ }
+ else
+ {
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ //wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + 1] = m_pFilteringTable->rules[1].flt_rule_hdl;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v6;
+ //wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + 1] = IPA_IP_v6;
+ wlan_ampdu_flt_rule.num_rules += IPV6_DEFAULT_FILTERTING_RULES;
+ }
+ }
+
+ free(m_pFilteringTable);
+ return res;
+}
+
+
+/*duplicate ampdu filter rules for new_address event*/
+int IPACM_Wlan::handle_addr_evt(ipacm_event_data_addr *data)
+{
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+ struct ipa_flt_rule_add flt_rule_entry;
+ int NUM_RULES = 1;
+
+ IPACMDBG(" set route/filter rule ip-type: %d \n", data->iptype);
+ if (data->iptype == IPA_IP_v6)
+ {
+ if (num_dft_rt == 1) /*LAN handle_addr_evt will update this to 1*/
+ {
+ /* configure ampdu multicast/broadcast/fragment filter rule */
+ init_fl_rule(data->iptype);
+
+ /* add default v6 filter rule */
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ NUM_RULES * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v6;
+ m_pFilteringTable->num_rules = (uint8_t)NUM_RULES;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_v6))
+ {
+ PERROR("m_routing.GetRoutingTable() Failed.\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_v6.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[0] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr_mask[3] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[0] = 0X00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[1] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[2] = 0x00000000;
+ flt_rule_entry.rule.attrib.u.v6.dst_addr[3] = 0X00000000;
+
+ memcpy(&(m_pFilteringTable->rules[0]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+
+ }
+ else
+ {
+ IPACMDBG("flt rule hdl0=0x%x, status=0x%x\n", m_pFilteringTable->rules[0].flt_rule_hdl, m_pFilteringTable->rules[0].status);
+ }
+
+ /* copy filter hdls */
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules] = m_pFilteringTable->rules[0].flt_rule_hdl;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules] = IPA_IP_v6;
+ wlan_ampdu_flt_rule.num_rules++;
+ free(m_pFilteringTable);
+ }
+ }
+ else
+ {
+ init_fl_rule(data->iptype);
+ }
+ return IPACM_SUCCESS;
+}
+
+/*duplicate ampdu filter rules for private subnet configuration*/
+int IPACM_Wlan::handle_private_subnet(ipa_ip_type iptype)
+{
+ struct ipa_flt_rule_add flt_rule_entry;
+ int i;
+
+ IPACMDBG("wlan->handle_private_subnet(); set route/filter rule \n");
+
+ if (iptype == IPA_IP_v4)
+ {
+ /* construct ipa_ioc_add_flt_rule with 1 rules */
+ ipa_ioc_add_flt_rule *m_pFilteringTable;
+
+ m_pFilteringTable = (struct ipa_ioc_add_flt_rule *)
+ calloc(1,
+ sizeof(struct ipa_ioc_add_flt_rule) +
+ (IPACM_Iface::ipacmcfg->ipa_num_private_subnet) * sizeof(struct ipa_flt_rule_add)
+ );
+
+ if (!m_pFilteringTable)
+ {
+ PERROR("Error Locate ipa_ioc_add_flt_rule memory...\n");
+ return IPACM_FAILURE;
+ }
+
+ m_pFilteringTable->commit = 1;
+ m_pFilteringTable->ep = IPA_CLIENT_A5_WLAN_AMPDU_PROD;
+ m_pFilteringTable->global = false;
+ m_pFilteringTable->ip = IPA_IP_v4;
+ m_pFilteringTable->num_rules = (uint8_t)IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+ if (false == m_routing.GetRoutingTable(&IPACM_Iface::ipacmcfg->rt_tbl_lan_v4))
+ {
+ PERROR("WLAN m_routing.GetRoutingTable(IPACM_Iface::ipacmcfg->rt_tbl_lan_v4) Failed.\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ }
+
+ for (i = 0; i < IPACM_Iface::ipacmcfg->ipa_num_private_subnet; i++)
+ {
+ memset(&flt_rule_entry, 0, sizeof(struct ipa_flt_rule_add));
+ flt_rule_entry.at_rear = true;
+ flt_rule_entry.flt_rule_hdl = -1;
+ flt_rule_entry.status = -1;
+ flt_rule_entry.rule.action = IPA_PASS_TO_ROUTING;
+ flt_rule_entry.rule.rt_tbl_hdl = IPACM_Iface::ipacmcfg->rt_tbl_lan_v4.hdl;
+ memcpy(&flt_rule_entry.rule.attrib,
+ &rx_prop->rx[0].attrib,
+ sizeof(flt_rule_entry.rule.attrib));
+ flt_rule_entry.rule.attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr_mask = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_mask;
+ flt_rule_entry.rule.attrib.u.v4.dst_addr = IPACM_Iface::ipacmcfg->private_subnet_table[i].subnet_addr;
+ memcpy(&(m_pFilteringTable->rules[i]), &flt_rule_entry, sizeof(struct ipa_flt_rule_add));
+ }
+
+ if (false == m_filtering.AddFilteringRule(m_pFilteringTable))
+ {
+ PERROR("Error Adding RuleTable(0) to Filtering, aborting...\n");
+ free(m_pFilteringTable);
+ return IPACM_FAILURE;
+ };
+
+
+ /* copy filter hdls */
+ for (i = 0; i < (IPACM_Iface::ipacmcfg->ipa_num_private_subnet); i++)
+ {
+ wlan_ampdu_flt_rule.hdl[wlan_ampdu_flt_rule.num_rules + i] = m_pFilteringTable->rules[i].flt_rule_hdl;
+ wlan_ampdu_flt_rule.ip[wlan_ampdu_flt_rule.num_rules + i] = IPA_IP_v4;
+ }
+ wlan_ampdu_flt_rule.num_rules += IPACM_Iface::ipacmcfg->ipa_num_private_subnet;
+
+ IPACMDBG("wlan handle private ok~\n");
+ free(m_pFilteringTable);
+ }
+ return IPACM_SUCCESS;
+}
+
+
+/*handle wlan iface down event*/
+int IPACM_Wlan::handle_down_evt()
+{
+ IPACMDBG("ip-type: %d \n", ip_type);
+ uint32_t tx_index, rt_hdl;
+ ipa_ip_type ip;
+ int res = IPACM_SUCCESS, i;
+
+ /* no iface address up, directly close iface*/
+ if (ip_type == IPACM_IP_NULL)
+ {
+ IPACMERR("Invalid iptype: 0x%x\n", ip_type);
+ return IPACM_FAILURE;
+ }
+
+ /* Delete v6 filtering rules */
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG("Delete default v4 filter rules\n");
+ /* delete default filter rules */
+ if (m_filtering.DeleteFilteringHdls(dft_v4fl_rule_hdl,
+ IPA_IP_v4,
+ IPV4_DEFAULT_FILTERTING_RULES) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ IPACMDBG("Delete private v4 filter rules\n");
+ /* free private-ipv4 filter rules */
+ if (m_filtering.DeleteFilteringHdls(
+ private_fl_rule_hdl,
+ IPA_IP_v4,
+ IPACM_Iface::ipacmcfg->ipa_num_private_subnet) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* Delete v4 filtering rules */
+ if (ip_type != IPA_IP_v4)
+ {
+ IPACMDBG("Delete default %d v6 filter rules\n", IPV6_DEFAULT_FILTERTING_RULES);
+ /* delete default filter rules */
+ if (m_filtering.DeleteFilteringHdls(dft_v6fl_rule_hdl,
+ IPA_IP_v6,
+ IPV6_DEFAULT_FILTERTING_RULES) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ IPACMDBG("finished delte default filtering rules\n ");
+
+ /* delete WLAN IPA_CLIENT_A5_WLAN_AMPDU_PROD filter rules*/
+ for (i = 3; i < wlan_ampdu_flt_rule.num_rules; i++)
+ {
+ IPACMDBG("Delete WLAN IPA_CLIENT_A5_WLAN_AMPDU_PROD filter rules\n");
+ if (m_filtering.DeleteFilteringHdls(&wlan_ampdu_flt_rule.hdl[i],
+ wlan_ampdu_flt_rule.ip[i], 1) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ IPACMDBG("finished delte AMPDU filtering rules\n ");
+
+
+ /* Delete default v4 RT rule */
+ if (ip_type != IPA_IP_v6)
+ {
+ IPACMDBG("Delete default v4 routing rules\n");
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[0], IPA_IP_v4)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+
+ /* Delete default v6 RT rule */
+ if (ip_type != IPA_IP_v4)
+ {
+ IPACMDBG("Delete default v6 routing rules\n");
+ /* May have multiple ipv6 iface-RT rules */
+ for (i = 0; i < num_dft_rt; i++)
+ {
+ if (m_routing.DeleteRoutingHdl(dft_rt_rule_hdl[i + 1], IPA_IP_v6)
+ == false)
+ {
+ IPACMERR("Routing rule deletion failed!\n");
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+ }
+ }
+ IPACMDBG("finished deleting default RT rules\n ");
+
+
+ /* delete wan filter rule */
+ if (IPACM_Wan::isWanUP())
+ {
+ IPACMDBG("Delete wan filtering rules\n");
+
+ IPACM_Lan::handle_wan_down();
+ handle_wan_down();
+ }
+ IPACMDBG("finished deleting wan filtering rules\n ");
+
+
+ /* check software routing fl rule hdl */
+ if (softwarerouting_act == true)
+ {
+ IPACMDBG("Delete sw routing filtering rules\n");
+ IPACM_Iface::handle_software_routing_disable();
+ handle_software_routing_disable();
+ }
+ IPACMDBG("finished delete software-routing filtering rules\n ");
+
+
+ /* clean wifi-client header, routing rules */
+ /* clean wifi client rule*/
+ IPACMDBG("left %d wifi clients need to be deleted \n ", num_wifi_client);
+ for (i = 0; i < num_wifi_client; i++)
+ {
+
+ for (tx_index = 0; tx_index < iface_query->num_tx_props; tx_index++)
+ {
+ if (ip_type != IPA_IP_v6) /* for ipv4 */
+ {
+ rt_hdl = get_client_memptr(wlan_client, i)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v4;
+ ip = IPA_IP_v4;
+ }
+ else if (ip_type != IPA_IP_v4) /* for ipv6 */
+ {
+ rt_hdl = get_client_memptr(wlan_client, i)->wifi_rt_hdl[tx_index].wifi_rt_rule_hdl_v6;
+ ip = IPA_IP_v6;
+ }
+
+ IPACMDBG("Delete %d client route rule %d\n", num_wifi_client, tx_index);
+ if (m_routing.DeleteRoutingHdl(rt_hdl, ip) == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ } /* end of tx-index for loop*/
+
+ IPACMDBG("Delete %d client header\n", num_wifi_client);
+ if (m_header.DeleteHeaderHdl(get_client_memptr(wlan_client, i)->hdr_hdl)
+ == false)
+ {
+ res = IPACM_FAILURE;
+ goto fail;
+ }
+
+ } /* end of for loop */
+
+ /* free the wlan clients cache */
+ IPACMDBG("Free wlan clients cache\n");
+
+fail:
+ free(wlan_client);
+ free(tx_prop);
+ free(rx_prop);
+ free(iface_query);
+
+ return res;
+}
diff --git a/ipacm/src/IPACM_Xml.cpp b/ipacm/src/IPACM_Xml.cpp
new file mode 100644
index 0000000..8871b1d
--- /dev/null
+++ b/ipacm/src/IPACM_Xml.cpp
@@ -0,0 +1,1090 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_Xml.cpp
+
+ @brief
+ This file implements the XML specific parsing functionality.
+
+ @Author
+ Skylar Chang/Shihuan Liu
+*/
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "IPACM_Xml.h"
+#include "IPACM_Log.h"
+#include "IPACM_Netlink.h"
+
+static char* IPACM_read_content_element
+(
+ xmlNode* element
+);
+
+static int32_t IPACM_util_icmp_string
+(
+ const char* xml_str,
+ const char* str
+);
+
+static int ipacm_cfg_xml_parse_tree
+(
+ xmlNode* xml_node,
+ IPACM_conf_t *config
+);
+
+static int IPACM_firewall_xml_parse_tree
+(
+ xmlNode* xml_node,
+ IPACM_firewall_conf_t *config
+);
+
+/*Reads content (stored as child) of the element */
+static char* IPACM_read_content_element
+(
+ xmlNode* element
+)
+{
+ xmlNode* child_ptr;
+
+ for (child_ptr = element->children;
+ child_ptr != NULL;
+ child_ptr = child_ptr->next)
+ {
+ if (child_ptr->type == XML_TEXT_NODE)
+ {
+ return (char*)child_ptr->content;
+ }
+ }
+ return NULL;
+}
+
+/* insensitive comparison of a libxml's string (xml_str) and a regular string (str)*/
+static int32_t IPACM_util_icmp_string
+(
+ const char* xml_str,
+ const char* str
+)
+{
+ int32_t ret = -1;
+
+ if (NULL != xml_str && NULL != str)
+ {
+ uint32_t len1 = strlen(str);
+ uint32_t len2 = strlen(xml_str);
+ /* If the lengths match, do the string comparison */
+ if (len1 == len2)
+ {
+ ret = strncasecmp(xml_str, str, len1);
+ }
+ }
+
+ return ret;
+}
+
+/* This function read IPACM XML and populate the IPA CM Cfg */
+int ipacm_read_cfg_xml(char *xml_file, IPACM_conf_t *config)
+{
+ xmlDocPtr doc = NULL;
+ xmlNode* root = NULL;
+ int ret_val;
+
+ /* Invoke the XML parser and obtain the parse tree */
+ doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+ if (doc == NULL) {
+ IPACMDBG("IPACM_xml_parse: libxml returned parse error!\n");
+ return IPACM_FAILURE;
+ }
+
+ /*Get the root of the tree*/
+ root = xmlDocGetRootElement(doc);
+
+ memset(config, 0, sizeof(IPACM_conf_t));
+
+ /* parse the xml tree returned by libxml */
+ ret_val = ipacm_cfg_xml_parse_tree(root, config);
+
+ if (ret_val != IPACM_SUCCESS)
+ IPACMDBG("IPACM_xml_parse: ipacm_cfg_xml_parse_tree returned parse error!\n");
+
+ /* Free up the libxml's parse tree */
+ xmlFreeDoc(doc);
+ //xmlCleanupParser();
+
+ return ret_val;
+}
+
+/* This function traverses the xml tree*/
+static int ipacm_cfg_xml_parse_tree
+(
+ xmlNode* xml_node,
+ IPACM_conf_t *config
+)
+{
+ int32_t ret_val = IPACM_SUCCESS;
+ int str_size;
+ char* content;
+ char content_buf[MAX_XML_STR_LEN];
+
+ if (NULL == xml_node)
+ return ret_val;
+
+ while ( xml_node != NULL &&
+ ret_val == IPACM_SUCCESS)
+ {
+ switch (xml_node->type)
+ {
+ case XML_ELEMENT_NODE:
+ {
+ if (IPACM_util_icmp_string((char*)xml_node->name,
+ system_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMCFG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMIFACECFG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IFACE_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMPRIVATESUBNETCFG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ SUBNET_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMALG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ ALG_TAG) == 0 ||
+ IPACM_util_icmp_string((char*)xml_node->name,
+ IPACMNat_TAG) == 0)
+ {
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IFACE_TAG))
+ {
+ /* increase iface entry number */
+ config->iface_config.num_iface_entries++;
+ }
+
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ SUBNET_TAG))
+ {
+ /* increase iface entry number */
+ config->private_subnet_config.num_subnet_entries++;
+ }
+
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ ALG_TAG))
+ {
+ /* increase iface entry number */
+ config->alg_config.num_alg_entries++;
+ }
+ /* go to child */
+ ret_val = ipacm_cfg_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ NAME_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ strncpy(config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name, content_buf, str_size);
+ IPACMDBG("Name %s\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].iface_name);
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ CATEGORY_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if (0 == strncasecmp(content_buf, WANIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = WAN_IF;
+ IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, LANIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = LAN_IF;
+ IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, WLANIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = WLAN_IF;
+ IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ else if (0 == strncasecmp(content_buf, VIRTUALIF_TAG, str_size))
+ {
+ config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat = VIRTUAL_IF;
+ IPACMDBG("Category %d\n", config->iface_config.iface_entries[config->iface_config.num_iface_entries - 1].if_cat);
+ }
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ SUBNETADDRESS_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("subnet_addr: %s \n", content_buf);
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ SUBNETMASK_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->private_subnet_config.private_subnet_entries[config->private_subnet_config.num_subnet_entries - 1].subnet_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("subnet_mask: %s \n", content_buf);
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ Protocol_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+
+ if (0 == strncasecmp(content_buf, TCP_PROTOCOL_TAG, str_size))
+ {
+ config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol = IPPROTO_TCP;
+ IPACMDBG("Protocol %s: %d\n", content_buf, config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol);
+ }
+ else if (0 == strncasecmp(content_buf, UDP_PROTOCOL_TAG, str_size))
+ {
+ config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol = IPPROTO_UDP;
+ IPACMDBG("Protocol %s: %d\n", content_buf, config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].protocol);
+ }
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ Port_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].port
+ = atoi(content_buf);
+ IPACMDBG("port %d\n", config->alg_config.alg_entries[config->alg_config.num_alg_entries - 1].port);
+ }
+ }
+ else if (IPACM_util_icmp_string((char*)xml_node->name,
+ NAT_MaxEntries_TAG) == 0)
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->nat_max_entries = atoi(content_buf);
+ IPACMDBG("Nat Table Max Entries %d\n", config->nat_max_entries);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ /* go to sibling */
+ xml_node = xml_node->next;
+ } /* end while */
+ return ret_val;
+}
+
+/* This function read QCMAP CM Firewall XML and populate the QCMAP CM Cfg */
+int IPACM_read_firewall_xml(char *xml_file, IPACM_firewall_conf_t *config)
+{
+ xmlDocPtr doc = NULL;
+ xmlNode* root = NULL;
+ int ret_val;
+
+ IPACM_ASSERT(xml_file != NULL);
+ IPACM_ASSERT(config != NULL);
+
+ /* invoke the XML parser and obtain the parse tree */
+ doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
+ if (doc == NULL) {
+ IPACMDBG("IPACM_xml_parse: libxml returned parse error\n");
+ return IPACM_FAILURE;
+ }
+ /*get the root of the tree*/
+ root = xmlDocGetRootElement(doc);
+
+ /* parse the xml tree returned by libxml*/
+ ret_val = IPACM_firewall_xml_parse_tree(root, config);
+
+ if (ret_val != IPACM_SUCCESS)
+ IPACMDBG("IPACM_xml_parse: ipacm_firewall_xml_parse_tree returned parse error!\n");
+
+ /* free the tree */
+ xmlFreeDoc(doc);
+
+ return ret_val;
+}
+
+
+/* This function traverses the firewall xml tree */
+static int IPACM_firewall_xml_parse_tree
+(
+ xmlNode* xml_node,
+ IPACM_firewall_conf_t *config
+)
+{
+ int mask_value_v6, mask_index;
+ int32_t ret_val = IPACM_SUCCESS;
+ char *content;
+ int str_size;
+ char content_buf[MAX_XML_STR_LEN];
+ struct in6_addr ip6_addr;
+
+ IPACM_ASSERT(config != NULL);
+
+ if (NULL == xml_node)
+ return ret_val;
+
+ while ( xml_node != NULL &&
+ ret_val == IPACM_SUCCESS)
+ {
+ switch (xml_node->type)
+ {
+
+ case XML_ELEMENT_NODE:
+ {
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ system_TAG) ||
+ 0 == IPACM_util_icmp_string((char*)xml_node->name,
+ MobileAPFirewallCfg_TAG) ||
+ 0 == IPACM_util_icmp_string((char*)xml_node->name,
+ Firewall_TAG)
+ )
+ {
+ if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ Firewall_TAG))
+ {
+ /* increase firewall entry num */
+ config->num_extd_firewall_entries++;
+ }
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPFamily_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].ip_vsn
+ = (firewall_ip_version_enum)atoi(content_buf);
+ IPACMDBG("\n IP family type is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].ip_vsn);
+
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4SourceAddress_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_ADDR;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4SourceIPAddress_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("IPv4 source address is: %s \n", content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4SourceSubnetMask_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.src_addr_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("IPv4 source subnet mask is: %s \n", content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4DestinationAddress_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_ADDR;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4DestinationIPAddress_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("IPv4 destination address is: %s \n", content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4DestinationSubnetMask_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.dst_addr_mask
+ = ntohl(inet_addr(content_buf));
+ IPACMDBG("IPv4 destination subnet mask is: %s \n", content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4TypeOfService_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TOS;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TOSValue_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos
+ = atoi(content_buf);
+
+ IPACMDBG("\n IPV4 TOS val is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TOSMask_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos
+ &= atoi(content_buf);
+
+ IPACMDBG("\n IPv4 TOS mask is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.tos);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV4NextHeaderProtocol_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_PROTOCOL;
+
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.protocol = atoi(content_buf);
+
+ IPACMDBG("\n IPv4 next header prot is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v4.protocol);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6SourceAddress_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |=
+ IPA_FLT_SRC_ADDR;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6SourceIPAddress_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ inet_pton(AF_INET6, content_buf, &ip6_addr);
+ memcpy(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr,
+ ip6_addr.s6_addr, IPACM_IPV6_ADDR_LEN * sizeof(uint8_t));
+
+ IPACMDBG("\n ipv6 source addr is %d \n ",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr[0]);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6SourcePrefix_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ mask_value_v6 = atoi(content_buf);
+ for (mask_index = 0; mask_index < 4; mask_index++)
+ {
+ if (mask_value_v6 >= 32)
+ {
+ mask_v6(32, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr_mask[mask_index]));
+ mask_value_v6 -= 32;
+ }
+ else
+ {
+ mask_v6(mask_value_v6, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.src_addr_mask[mask_index]));
+ mask_value_v6 = 0;
+ }
+ }
+ IPACMDBG("\n ipv6 source prefix is %d \n",
+ atoi(content_buf));
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6DestinationAddress_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |=
+ IPA_FLT_DST_ADDR;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6DestinationIPAddress_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ inet_pton(AF_INET6, content_buf, &ip6_addr);
+
+ memcpy(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr,
+ ip6_addr.s6_addr, IPACM_IPV6_ADDR_LEN * sizeof(uint8_t));
+ IPACMDBG("\n ipv6 dest addr is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr[0]);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6DestinationPrefix_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ mask_value_v6 = atoi(content_buf);
+ for (mask_index = 0; mask_index < 4; mask_index++)
+ {
+ if (mask_value_v6 >= 32)
+ {
+ mask_v6(32, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr_mask[mask_index]));
+ mask_value_v6 -= 32;
+ }
+ else
+ {
+ mask_v6(mask_value_v6, &(config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.dst_addr_mask[mask_index]));
+ mask_value_v6 = 0;
+ }
+ }
+ IPACMDBG("\n ipv6 dest prefix is %d \n",
+ atoi(content_buf));
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6TrafficClass_TAG))
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TC;
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TrfClsValue_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc
+ = atoi(content_buf);
+ IPACMDBG("\n ipv6 trf class val is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TrfClsMask_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.tc
+ &= atoi(content_buf);
+
+ IPACMDBG("\n ipv6 trf class mask is %d \n",
+ atoi(content_buf));
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ IPV6NextHeaderProtocol_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_NEXT_HDR;
+
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.next_hdr
+ = atoi(content_buf);
+ IPACMDBG("\n ipv6 next header protocol is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.u.v6.next_hdr);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPSource_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPSourcePort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPSourceRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if (atoi(content_buf) != 0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = 0;
+ IPACMDBG("\n tcp source port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+ IPACMDBG("\n tcp source port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPDestination_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPDestinationPort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCPDestinationRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = 0;
+ IPACMDBG("\n tcp dest port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+ IPACMDBG("\n tcp dest port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPSource_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPSourcePort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPSourceRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = 0;
+ IPACMDBG("\n udp source port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+ IPACMDBG("\n udp source port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPDestination_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPDestinationPort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ UDPDestinationRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = 0;
+ IPACMDBG("\n UDP dest port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+ IPACMDBG("\n UDP dest port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ ICMPType_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.type = atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_TYPE;
+ IPACMDBG("\n icmp type is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.type);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ ICMPCode_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.code = atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_CODE;
+ IPACMDBG("\n icmp code is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.code);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ ESPSPI_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.spi = atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SPI;
+ IPACMDBG("\n esp spi is %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.spi);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPSource_TAG))
+ {
+ /* go to child */
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPSourcePort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content,str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPSourceRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port
+ = 0;
+ IPACMDBG("\n tcp_udp source port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_SRC_PORT;
+ IPACMDBG("\n tcp_udp source port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.src_port);
+
+ }
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPDestination_TAG))
+ {
+ ret_val = IPACM_firewall_xml_parse_tree(xml_node->children,
+ config);
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPDestinationPort_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = atoi(content_buf);
+ }
+ }
+ else if (0 == IPACM_util_icmp_string((char*)xml_node->name,
+ TCP_UDPDestinationRange_TAG))
+ {
+ content = IPACM_read_content_element(xml_node);
+ if (content)
+ {
+ str_size = strlen(content);
+ memset(content_buf, 0, sizeof(content_buf));
+ memcpy(content_buf, (void *)content, str_size);
+ if(atoi(content_buf)!=0)
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT_RANGE;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port;
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi
+ = config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port + atoi(content_buf);
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port
+ = 0;
+ IPACMDBG("\n tcp_udp dest port from %d to %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_lo,
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port_hi);
+ }
+ else
+ {
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.attrib_mask |= IPA_FLT_DST_PORT;
+ IPACMDBG("\n tcp_udp dest port= %d \n",
+ config->extd_firewall_entries[config->num_extd_firewall_entries - 1].attrib.dst_port);
+
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ /* go to sibling */
+ xml_node = xml_node->next;
+ } /* end while */
+ return ret_val;
+}
+
+
diff --git a/ipacm/src/IPACM_cfg.xml b/ipacm/src/IPACM_cfg.xml
new file mode 100644
index 0000000..06f20b6
--- /dev/null
+++ b/ipacm/src/IPACM_cfg.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ipacm_cfg.xsd">
+ <IPACM>
+ <IPACMIface>
+ <Iface>
+ <Name>rmnet0</Name>
+ <Category>WAN</Category>
+ </Iface>
+ <Iface>
+ <Name>rmnet1</Name>
+ <Category>LAN</Category>
+ </Iface>
+ <Iface>
+ <Name>wlan0</Name>
+ <Category>WLAN</Category>
+ </Iface>
+ <Iface>
+ <Name>bridge0</Name>
+ <Category>VIRTUAL</Category>
+ </Iface>
+ </IPACMIface>
+ <IPACMPrivateSubnet>
+ <Subnet>
+ <SubnetAddress>192.168.1.0</SubnetAddress>
+ <SubnetMask>255.255.255.0</SubnetMask>
+ </Subnet>
+ </IPACMPrivateSubnet>
+ <IPACMALG>
+ <ALG>
+ <Protocol>TCP</Protocol>
+ <Port>23</Port>
+ </ALG>
+ <ALG>
+ <Protocol>UDP</Protocol>
+ <Port>250</Port>
+ </ALG>
+ </IPACMALG>
+ <IPACMNAT>
+ <MaxNatEntries>100</MaxNatEntries>
+ </IPACMNAT>
+ </IPACM>
+</system>
diff --git a/ipacm/src/Makefile.am b/ipacm/src/Makefile.am
new file mode 100644
index 0000000..22fa657
--- /dev/null
+++ b/ipacm/src/Makefile.am
@@ -0,0 +1,41 @@
+EXTRA_CPPFLAGS = -DDEBUG
+
+AM_CPPFLAGS = -I./../inc -I$(WORKSPACE)/data-ipa/ipanat/inc -I$(WORKSPACE)/kernel/include -I/usr/include/libxml2
+AM_CPPFLAGS += -Wall -Wundef -Wno-trigraphs
+
+ipacm_SOURCES = IPACM_Main.cpp \
+ IPACM_Conntrack_NATApp.cpp\
+ IPACM_ConntrackClient.cpp \
+ IPACM_ConntrackListener.cpp \
+ IPACM_EvtDispatcher.cpp \
+ IPACM_Config.cpp \
+ IPACM_CmdQueue.cpp \
+ IPACM_Log.cpp \
+ IPACM_Filtering.cpp \
+ IPACM_Routing.cpp \
+ IPACM_Header.cpp \
+ IPACM_Lan.cpp \
+ IPACM_Iface.cpp \
+ IPACM_Wlan.cpp \
+ IPACM_Wan.cpp \
+ IPACM_IfaceManager.cpp \
+ IPACM_Neighbor.cpp \
+ IPACM_Netlink.cpp \
+ IPACM_Xml.cpp
+
+bin_PROGRAMS = ipacm
+
+requiredlibs = -lxml2 -lpthread -lnetfilter_conntrack -lnfnetlink\
+ ../../ipanat/src/libipanat.la
+
+ipacm_LDADD = $(requiredlibs)
+
+LOCAL_MODULE := libipanat
+LOCAL_PRELINK_MODULE := false
+include $(BUILD_SHARED_LIBRARY)
+
+etcdir = ${sysconfdir}
+etc_SCRIPTS = IPACM_cfg.xml mobileap_firewall.xml
+
+init_ddir = ${sysconfdir}/init.d
+init_d_SCRIPTS = start_ipacm_le
diff --git a/ipacm/src/mobileap_firewall.xml b/ipacm/src/mobileap_firewall.xml
new file mode 100644
index 0000000..c722511
--- /dev/null
+++ b/ipacm/src/mobileap_firewall.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<system xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="mobileap_firewall_cfg.xsd">
+ <MobileAPFirewallCfg>
+ </MobileAPFirewallCfg>
+</system>
diff --git a/ipacm/src/start_ipacm_le b/ipacm/src/start_ipacm_le
new file mode 100755
index 0000000..3541a0b
--- /dev/null
+++ b/ipacm/src/start_ipacm_le
@@ -0,0 +1,57 @@
+#! /bin/sh
+#
+################################
+# Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of The Linux Foundation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+################################
+
+# ipacm init.d script to start the data-ipa Software's ipacm daemon
+
+set -e
+
+case "$1" in
+ start)
+ echo -n "Starting ipacm: "
+ start-stop-daemon -S -b -a ipacm
+ echo "done"
+ ;;
+ stop)
+ echo -n "Stopping ipacm: "
+ start-stop-daemon -K -n ipacm
+ echo "done"
+ ;;
+ restart)
+ $0 stop
+ $0 start
+ ;;
+ *)
+ echo "Usage ipacm { start | stop | restart}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/ipanat/inc/ipa_nat_drv.h b/ipanat/inc/ipa_nat_drv.h
new file mode 100644
index 0000000..cda63f1
--- /dev/null
+++ b/ipanat/inc/ipa_nat_drv.h
@@ -0,0 +1,118 @@
+/*
+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 "string.h" /* memset */
+#include "stdlib.h" /* free, malloc */
+#include "stdint.h" /* uint32_t */
+
+/**
+ * struct ipa_nat_ipv4_rule - To hold ipv4 nat rule
+ * @target_ip: destination ip address
+ * @private_ip: private ip address
+ * @target_port: destination port
+ * @private_port: private port
+ * @protocol: protocol of rule (tcp/udp)
+ */
+typedef struct
+{
+ uint32_t target_ip;
+ uint32_t private_ip;
+ uint16_t target_port;
+ uint16_t private_port;
+ uint16_t public_port;
+ uint8_t protocol;
+
+}ipa_nat_ipv4_rule;
+
+/**
+ * ipa_nat_add_ipv4_tbl() - create ipv4 nat table
+ * @public_ip_addr: [in] public ipv4 address
+ * @number_of_entries: [in] number of nat entries
+ * @table_handle: [out] Handle of new ipv4 nat table
+ *
+ * To create new ipv4 nat table
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_tbl(uint32_t public_ip_addr,
+ uint16_t number_of_entries,
+ uint32_t *table_handle);
+
+/**
+ * ipa_nat_del_ipv4_tbl() - delete ipv4 table
+ * @table_handle: [in] Handle of ipv4 nat table
+ *
+ * To delete given ipv4 nat table
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_tbl(uint32_t table_handle);
+
+/**
+ * ipa_nat_add_ipv4_rule() - to insert new ipv4 rule
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule: [in] Pointer to new rule
+ * @rule_handle: [out] Return the handle to rule
+ *
+ * To insert new ipv4 nat rule into ipv4 nat table
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_rule(uint32_t table_handle,
+ const ipa_nat_ipv4_rule *rule,
+ uint32_t *rule_handle);
+
+/**
+ * ipa_nat_del_ipv4_rule() - to delete ipv4 nat rule
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule_handle: [in] ipv4 nat rule handle
+ *
+ * To insert new ipv4 nat rule into ipv4 nat table
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_rule(uint32_t table_handle,
+ uint32_t rule_handle);
+
+
+/**
+ * ipa_nat_query_timestamp() - to query timestamp
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule_handle: [in] ipv4 nat rule handle
+ * @time_stamp: [out] time stamp of rule
+ *
+ * To retrieve the timestamp that lastly the
+ * nat rule was accessed
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_query_timestamp(uint32_t table_handle,
+ uint32_t rule_handle,
+ uint32_t *time_stamp);
+
diff --git a/ipanat/inc/ipa_nat_drvi.h b/ipanat/inc/ipa_nat_drvi.h
new file mode 100644
index 0000000..9b56cf1
--- /dev/null
+++ b/ipanat/inc/ipa_nat_drvi.h
@@ -0,0 +1,474 @@
+/*
+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 IPA_NAT_DRVI_H
+#define IPA_NAT_DRVI_H
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <linux/msm_ipa.h>
+#include <netinet/in.h>
+#include <sys/inotify.h>
+
+#include "ipa_nat_logi.h"
+
+#define NAT_DUMP
+//#define IPADBG(fmt, args...) printf(" %s:%d " fmt, __FUNCTION__, __LINE__, ## args)
+//#define IPAERR(fmt, args...) printf(" %s:%d " fmt, __FUNCTION__, __LINE__, ## args)
+
+
+/*======= IMPLEMENTATION related data structures and functions ======= */
+#ifdef IPA_ON_R3PC
+#define NAT_MMAP_MEM_SIZE (2 * 1024UL * 1024UL - 1)
+#endif
+
+#define IPA_DEV_NAME "/dev/ipa"
+#define NAT_DEV_DIR "/dev"
+#define NAT_DEV_NAME "ipaNatTable"
+#define NAT_DEV_FULL_NAME "/dev/ipaNatTable"
+
+#define IPA_NAT_TABLE_VALID 1
+#define IPA_NAT_MAX_IP4_TBLS 1
+#define IPA_NAT_BASE_TABLE_PERCENTAGE .8
+#define IPA_NAT_EXPANSION_TABLE_PERCENTAGE .2
+
+#define IPA_NAT_NUM_OF_BASE_TABLES 2
+#define IPA_NAT_UNUSED_BASE_ENTRIES 2
+
+#define IPA_NAT_RULE_FLAG_FIELD_OFFSET 18
+#define IPA_NAT_RULE_NEXT_FIELD_OFFSET 8
+#define IPA_NAT_RULE_PROTO_FIELD_OFFSET 22
+
+#define IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET 2
+#define IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET 0
+
+#define IPA_NAT_RULE_FLAG_FIELD_SIZE 2
+#define IPA_NAT_RULE_NEXTFIELD_FIELD_SIZE 2
+
+#define IPA_NAT_FLAG_ENABLE_BIT_MASK 0x8000
+#define IPA_NAT_FLAG_DISABLE_BIT_MASK 0x0000
+
+#define IPA_NAT_FLAG_ENABLE_BIT 1
+#define IPA_NAT_FLAG_DISABLE_BIT 0
+
+#define IPA_NAT_INVALID_PROTO_FIELD_VALUE 0xFF00
+#define IPA_NAT_INVALID_PROTO_FIELD_CMP 0xFF
+
+#define IPA_NAT_INVALID_INDEX 0xFF
+#define IPA_NAT_INVALID_NAT_ENTRY 0x0
+
+#define INDX_TBL_ENTRY_SIZE_IN_BITS 16
+
+/* ----------- Rule id -----------------------
+
+ ------------------------------------------------
+ | 3bits | 12 bits | 1 bit |
+ ------------------------------------------------
+ | reserved | index into table | 0 - base |
+ | | | 1 - expansion |
+ ------------------------------------------------
+
+*/
+#define IPA_NAT_RULE_HDL_TBL_TYPE_BITS 0x1
+#define IPA_NAT_RULE_HDL_TBL_TYPE_MASK 0x1
+
+/* ----------- sw specif parameter -----
+ ------------------------------------
+ | 16 bits | 16 bits |
+ ------------------------------------
+ | index table | prev index |
+ | entry | |
+ ------------------------------------
+-----------------------------------------*/
+#define IPA_NAT_SW_PARAM_PREV_INDX_BYTE 0
+#define IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE 1
+
+typedef enum
+{
+ IPA_NAT_BASE_TBL = 0,
+ IPA_NAT_EXPN_TBL = 1,
+ IPA_NAT_INDX_TBL = 2,
+ IPA_NAT_INDEX_EXPN_TBL = 3,
+}nat_table_type;
+
+typedef enum
+{
+ NEXT_INDEX_FIELD,
+ PUBLIC_PORT_FILED,
+ PRIVATE_PORT_FIELD,
+ TARGET_PORT_FIELD,
+ IP_CHKSUM_FIELD,
+ ENABLE_FIELD,
+ TIME_STAMP_FIELD,
+ PROTOCOL_FIELD,
+ TCP_UDP_CHKSUM_FIELD,
+ SW_SPEC_PARAM_PREV_INDEX_FIELD,
+ SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD,
+ INDX_TBL_TBL_ENTRY_FIELD,
+ INDX_TBL_NEXT_INDEX_FILED
+
+}ipa_nat_rule_field_type;
+
+/*
+ ---------------------------------------------
+ | 3 | 2 | 1 | 0 |
+ ---------------------------------------------
+ | Public Port(2B) | Next Index(2B) |
+ ---------------------------------------------
+*/
+typedef struct
+{
+ uint32_t next_index:16;
+ uint32_t public_port:16;
+}next_index_pub_port;
+
+
+/*
+ ---------------------------------------------
+ | 3 | 2 | 1 | 0 |
+ ---------------------------------------------
+ | Flags(2B) | IP check sum Diff(2B)|
+ |EN|FIN|Resv | | |
+ ---------------------------------------------
+*/
+typedef struct
+{
+ uint32_t ip_chksum:16;
+ uint32_t rsvd1:14;
+ uint32_t redirect:1;
+ uint32_t enable:1;
+}ipcksum_enbl;
+
+
+/*
+ ---------------------------------------
+ | 7 | 6 | 5 | 4 |
+ ---------------------------------------
+ | Proto | TimeStamp(3B) |
+ | (1B) | |
+ ---------------------------------------
+*/
+typedef struct
+{
+ uint32_t time_stamp:24;
+ uint32_t protocol:8;
+}time_stamp_proto;
+
+
+/*
+ ---------------------------------------------
+ | 3 | 2 | 1 | 0 |
+ ---------------------------------------------
+ | next_index | Table entry |
+ ----------------------------------------------
+*/
+typedef struct {
+ uint16_t tbl_entry;
+ uint16_t next_index;
+}tbl_ent_nxt_indx;
+
+/*--------------------------------------------------
+ 32 bit sw_spec_params is interpreted as follows
+ ------------------------------------
+ | 16 bits | 16 bits |
+ ------------------------------------
+ | index table | prev index |
+ | entry | |
+ ------------------------------------
+--------------------------------------------------*/
+typedef struct {
+ uint16_t prev_index;
+ uint16_t index_table_entry;
+}sw_spec_params;
+
+/*------------------------ NAT Table Entry ---------------------------------------
+
+ -----------------------------------------------------------------------------------
+ | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+ -----------------------------------------------------------------------------------
+ | Target IP(4B) | Private IP(4B) |
+ -----------------------------------------------------------------------------------
+ |Target Port(2B) | Private Port(2B) | Public Port(2B) | Next Index(2B) |
+ -----------------------------------------------------------------------------------
+ | Proto | TimeStamp(3B) | Flags(2B) | IP check sum Diff(2B)|
+ | (1B) | |EN|FIN|Resv | | |
+ -----------------------------------------------------------------------------------
+ | TCP/UDP checksum | Reserved(2B) | SW Specific Parameters(4B) |
+ | diff (2B) | |
+ -----------------------------------------------------------------------------------
+
+ Dont change below structure definition.
+ It should be same as above(little endian order)
+ -------------------------------------------------------------------------------*/
+struct ipa_nat_rule {
+ uint64_t private_ip:32;
+ uint64_t target_ip:32;
+
+ uint64_t nxt_indx_pub_port:32;
+ uint64_t private_port:16;
+ uint64_t target_port:16;
+
+ uint64_t ip_cksm_enbl:32;
+ uint64_t ts_proto:32;
+
+ /*--------------------------------------------------
+ 32 bit sw_spec_params is interpreted as follows
+ ------------------------------------
+ | 16 bits | 16 bits |
+ ------------------------------------
+ | index table | prev index |
+ | entry | |
+ ------------------------------------
+ --------------------------------------------------*/
+ uint64_t sw_spec_params:32;
+
+ uint64_t rsvd2:16;
+ uint64_t tcp_udp_chksum:16;
+
+};
+
+struct ipa_nat_sw_rule {
+ uint64_t private_ip:32;
+ uint64_t target_ip:32;
+
+ uint64_t next_index:16;
+ uint64_t public_port:16;
+ uint64_t private_port:16;
+ uint64_t target_port:16;
+
+ uint64_t ip_chksum:16;
+ uint64_t rsvd1:14;
+ uint64_t redirect:1;
+ uint64_t enable:1;
+ uint64_t time_stamp:24;
+ uint64_t protocol:8;
+
+ /*--------------------------------------------------
+ 32 bit sw_spec_params is interpreted as follows
+ ------------------------------------
+ | 16 bits | 16 bits |
+ ------------------------------------
+ | index table | prev index |
+ | entry | |
+ ------------------------------------
+ --------------------------------------------------*/
+ uint64_t prev_index:16;
+ uint64_t indx_tbl_entry:16;
+ uint64_t rsvd2:16;
+ uint64_t tcp_udp_chksum:16;
+
+};
+#define IPA_NAT_TABLE_ENTRY_SIZE 32
+#define IPA_NAT_INDEX_TABLE_ENTRY_SIZE 4
+
+struct ipa_nat_indx_tbl_rule {
+ uint32_t tbl_entry_nxt_indx;
+};
+
+struct ipa_nat_sw_indx_tbl_rule {
+ uint16_t tbl_entry;
+ uint16_t next_index;
+};
+
+struct ipa_nat_indx_tbl_meta_info {
+ uint16_t prev_index;
+};
+
+struct ipa_nat_ip4_table_cache {
+ uint8_t valid;
+ uint32_t public_addr;
+
+ int nat_fd;
+ int size;
+ uint32_t tbl_addr_offset;
+ char table_name[IPA_RESOURCE_NAME_MAX];
+
+ char *ipv4_rules_addr;
+ char *index_table_addr;
+ uint16_t table_entries;
+
+ char *ipv4_expn_rules_addr;
+ char *index_table_expn_addr;
+ uint16_t expn_table_entries;
+
+ struct ipa_nat_indx_tbl_meta_info *index_expn_table_meta;
+
+ uint16_t *rule_id_array;
+#ifdef IPA_ON_R3PC
+ uint32_t mmap_offset;
+#endif
+};
+
+struct ipa_nat_cache {
+ struct ipa_nat_ip4_table_cache ip4_tbl[IPA_NAT_MAX_IP4_TBLS];
+ int ipa_fd;
+ uint8_t table_cnt;
+};
+
+struct ipa_nat_indx_tbl_sw_rule {
+ uint16_t tbl_entry;
+ uint16_t next_index;
+ uint16_t prev_index;
+};
+
+typedef enum
+{
+ IPA_NAT_DEL_TYPE_ONLY_ONE,
+ IPA_NAT_DEL_TYPE_HEAD,
+ IPA_NAT_DEL_TYPE_MIDDLE,
+ IPA_NAT_DEL_TYPE_LAST,
+}del_type;
+
+/**
+ * ipa_nati_parse_ipv4_rule_hdl() - prase rule handle
+ * @tbl_hdl: [in] nat table rule
+ * @rule_hdl: [in] nat rule handle
+ * @expn_tbl: [out] expansion table or not
+ * @tbl_entry: [out] index into table
+ *
+ * Parse the rule handle to retrieve the nat table
+ * type and entry of nat table
+ *
+ * Returns: None
+ */
+void ipa_nati_parse_ipv4_rule_hdl(uint8_t tbl_hdl,
+ uint16_t rule_hdl,
+ uint8_t *expn_tbl,
+ uint16_t *tbl_entry);
+
+/**
+ * ipa_nati_make_rule_hdl() - makes nat rule handle
+ * @tbl_hdl: [in] nat table handle
+ * @tbl_entry: [in] nat table entry
+ *
+ * Calculate the nat rule handle which from
+ * nat entry which will be returned to client of
+ * nat driver
+ *
+ * Returns: >0 nat rule handle
+ */
+uint16_t ipa_nati_make_rule_hdl(uint16_t tbl_hdl,
+ uint16_t tbl_entry);
+
+uint32_t ipa_nati_get_index_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+ nat_table_type tbl_type,
+ uint16_t indx_tbl_entry);
+uint32_t ipa_nati_get_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+ nat_table_type tbl_type,
+ uint16_t tbl_entry);
+
+int ipa_nati_add_ipv4_tbl(uint32_t public_ip_addr,
+ uint16_t number_of_entries,
+ uint32_t *table_hanle);
+
+int ipa_nati_alloc_table(uint16_t number_of_entries,
+ struct ipa_ioc_nat_alloc_mem *mem,
+ uint16_t *tbl_entries, uint16_t *expn_tbl_entries);
+
+int ipa_nati_update_cache(struct ipa_ioc_nat_alloc_mem *,
+ uint32_t public_ip_addr,
+ uint16_t tbl_entries,
+ uint16_t expn_tbl_entries);
+
+int ipa_nati_del_ipv4_table(uint32_t tbl_hdl);
+int ipa_nati_reset_ipv4_table(uint32_t tbl_hdl);
+int ipa_nati_post_ipv4_init_cmd(uint8_t tbl_index);
+
+int ipa_nati_query_timestamp(uint32_t tbl_hdl,
+ uint32_t rule_hdl,
+ uint32_t *time_stamp);
+
+uint32_t ipa_nati_add_ipv4_rule(uint32_t tbl_hdl,
+ const ipa_nat_ipv4_rule *clnt_rule);
+
+int ipa_nati_generate_rule(uint32_t tbl_hdl,
+ const ipa_nat_ipv4_rule *clnt_rule,
+ struct ipa_nat_sw_rule *rule,
+ struct ipa_nat_indx_tbl_sw_rule *index_sw_rule,
+ uint16_t *tbl_entry,
+ uint16_t *indx_tbl_entry);
+uint16_t ipa_nati_expn_tbl_free_entry(struct ipa_nat_rule *expn_tbl,
+ uint16_t size);
+uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule,
+ struct ipa_nat_sw_rule *sw_rule,
+ struct ipa_nat_ip4_table_cache *tbl_ptr);
+uint16_t ipa_nati_generate_index_rule(const ipa_nat_ipv4_rule *clnt_rule,
+ struct ipa_nat_indx_tbl_sw_rule *sw_rule,
+ struct ipa_nat_ip4_table_cache *tbl_ptr);
+uint16_t ipa_nati_index_expn_get_free_entry(struct ipa_nat_indx_tbl_rule *tbl,
+ uint16_t size);
+
+void ipa_nati_copy_ipv4_rule_to_hw(
+ struct ipa_nat_ip4_table_cache *ipv4_cache,
+ struct ipa_nat_sw_rule *rule,
+ uint16_t entry, uint8_t tbl_index);
+void ipa_nati_copy_ipv4_index_rule_to_hw(
+ struct ipa_nat_ip4_table_cache *ipv4_cache,
+ struct ipa_nat_indx_tbl_sw_rule *indx_sw_rule,
+ uint16_t entry, uint8_t tbl_index);
+
+void ipa_nati_write_next_index(uint8_t tbl_indx,
+ nat_table_type tbl_type,
+ uint16_t value,
+ uint32_t offset);
+int ipa_nati_post_ipv4_dma_cmd(uint8_t tbl_indx,
+ uint16_t entry);
+
+int ipa_nati_del_ipv4_rule(uint32_t tbl_hdl,
+ uint32_t rule_hdl);
+int ipa_nati_post_del_dma_cmd(uint8_t tbl_indx,
+ uint16_t tbl_entry,
+ uint8_t expn_tbl,
+ del_type rule_pos);
+void ipa_nati_find_index_rule_pos(
+ struct ipa_nat_ip4_table_cache *cache_ptr,
+ uint16_t tbl_entry,
+ del_type *rule_pos);
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx);
+void ipa_nati_find_rule_pos(struct ipa_nat_ip4_table_cache *cache_ptr,
+ uint8_t expn_tbl,
+ uint16_t tbl_entry,
+ del_type *rule_pos);
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx);
+
+
+/* ========================================================
+ Debug functions
+ ========================================================*/
+#ifdef NAT_DUMP
+void ipa_nati_print_rule(struct ipa_nat_rule *rule, uint32_t rule_id);
+void ipa_nati_dump_rule_buf(void *param1, uint8_t size, uint32_t rule_id);
+void ipa_nat_dump_ipv4_table(uint32_t tbl_hdl);
+void ipa_nati_dump_index_rule_buf(void *param1, uint8_t size, uint32_t rule_id);
+#endif
+
+#endif /* #ifndef IPA_NAT_DRVI_H */
diff --git a/ipanat/inc/ipa_nat_logi.h b/ipanat/inc/ipa_nat_logi.h
new file mode 100644
index 0000000..0ffa672
--- /dev/null
+++ b/ipanat/inc/ipa_nat_logi.h
@@ -0,0 +1,79 @@
+/*
+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_nat_logi.h
+
+ @brief
+ This file implements the IPAM log functionality.
+
+ @Author
+
+
+*/
+
+#ifndef IPA_NAT_LOGI_H
+#define IPA_NAT_LOGI_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#define NAT_LOG_SIZE 200
+
+#define PERROR(fmt) printf("%s:%d %s()", __FILE__, __LINE__, __FUNCTION__);\
+ perror(fmt);
+
+#define IPADBG(fmt, ...) {\
+ int n =0; \
+ n = snprintf(nat_log_buf, sizeof(nat_log_buf), "%s:%d %s() ", __FILE__, __LINE__, __FUNCTION__);\
+ snprintf((nat_log_buf+n), (sizeof(nat_log_buf)-n-1), fmt, ##__VA_ARGS__);\
+ log_nat_message(nat_log_buf);\
+ }
+
+
+#define IPAERR(fmt, ...) {\
+ int n =0; \
+ n = snprintf(nat_log_buf, sizeof(nat_log_buf), "%s:%d %s() %s", __FILE__, __LINE__, __FUNCTION__, "Error:");\
+ snprintf((nat_log_buf+n), (sizeof(nat_log_buf)-n-1), fmt, ##__VA_ARGS__);\
+ log_nat_message(nat_log_buf);\
+ }
+
+extern void log_nat_message(char *msg);
+extern char nat_log_buf[NAT_LOG_SIZE];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* IPA_NAT_LOGI_H */
diff --git a/ipanat/src/Makefile.am b/ipanat/src/Makefile.am
new file mode 100644
index 0000000..cf9fc3f
--- /dev/null
+++ b/ipanat/src/Makefile.am
@@ -0,0 +1,20 @@
+AM_CFLAGS = -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
+AM_CFLAGS += -I./../inc -I$(WORKSPACE)/kernel/include
+
+c_sources = ipa_nat_drv.c \
+ ipa_nat_drvi.c \
+ ipa_nat_logi.c
+
+library_includedir = $(pkgincludedir)
+library_include_HEADERS = ./../inc/ipa_nat_drvi.h \
+ ./../inc/ipa_nat_drv.h \
+ ./../inc/ipa_nat_logi.h
+
+lib_LTLIBRARIES = libipanat.la
+libipanat_la_C = @C@
+libipanat_la_SOURCES = $(c_sources)
+libipanat_la_CFLAGS = $(AM_CFLAGS)
+libipanat_la_LDFLAGS = -shared -version-info 1:0:0
+
+
+
diff --git a/ipanat/src/ipa_nat_drv.c b/ipanat/src/ipa_nat_drv.c
new file mode 100644
index 0000000..68e2de8
--- /dev/null
+++ b/ipanat/src/ipa_nat_drv.c
@@ -0,0 +1,177 @@
+/*
+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 "ipa_nat_drv.h"
+#include "ipa_nat_drvi.h"
+
+/**
+ * ipa_nat_add_ipv4_tbl() - create ipv4 nat table
+ * @public_ip_addr: [in] public ipv4 address
+ * @number_of_entries: [in] number of nat entries
+ * @table_handle: [out] Handle of new ipv4 nat table
+ *
+ * To create new ipv4 nat table
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_tbl(uint32_t public_ip_addr,
+ uint16_t number_of_entries,
+ uint32_t *tbl_hdl)
+{
+ int ret;
+
+ if (NULL == tbl_hdl || 0 == number_of_entries)
+ {
+ IPAERR("Invalid parameters \n");
+ return -1;
+ }
+
+ ret = ipa_nati_add_ipv4_tbl(public_ip_addr,
+ number_of_entries,
+ tbl_hdl);
+ if (ret != 0)
+ {
+ IPAERR("unable to add table \n");
+ return -1;
+ }
+ IPADBG("Returning table handle 0x%x\n", *tbl_hdl);
+
+ return ret;
+} /* __ipa_nat_add_ipv4_tbl() */
+
+/**
+ * ipa_nat_del_ipv4_tbl() - delete ipv4 table
+ * @table_handle: [in] Handle of ipv4 nat table
+ *
+ * To delete given ipv4 nat table
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_tbl(uint32_t tbl_hdl)
+{
+ if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+ tbl_hdl > IPA_NAT_MAX_IP4_TBLS)
+ {
+ IPAERR("invalid table handle passed \n");
+ return -1;
+ }
+ IPADBG("Passed Table Handle: 0x%x\n", tbl_hdl);
+
+ return ipa_nati_del_ipv4_table(tbl_hdl);
+}
+
+/**
+ * ipa_nat_add_ipv4_rule() - to insert new ipv4 rule
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule: [in] Pointer to new rule
+ * @rule_handle: [out] Return the handle to rule
+ *
+ * To insert new ipv4 nat rule into ipv4 nat table
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_add_ipv4_rule(uint32_t tbl_hdl,
+ const ipa_nat_ipv4_rule *clnt_rule,
+ uint32_t *rule_hdl)
+{
+
+ if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+ tbl_hdl > IPA_NAT_MAX_IP4_TBLS || NULL == rule_hdl ||
+ NULL == clnt_rule)
+ {
+ IPAERR("invalide table handle passed \n");
+ return -1;
+ }
+ IPADBG("Passed Table handle: 0x%x\n", tbl_hdl);
+
+ *rule_hdl = ipa_nati_add_ipv4_rule(tbl_hdl, clnt_rule);
+ IPADBG("returning rule handle 0x%x\n", *rule_hdl);
+
+ return 0;
+}
+
+
+/**
+ * ipa_nat_del_ipv4_rule() - to delete ipv4 nat rule
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule_handle: [in] ipv4 nat rule handle
+ *
+ * To insert new ipv4 nat rule into ipv4 nat table
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_del_ipv4_rule(uint32_t tbl_hdl,
+ uint32_t rule_hdl)
+{
+
+ if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+ IPA_NAT_INVALID_NAT_ENTRY == rule_hdl)
+ {
+ IPAERR("invalide parameters\n");
+ return -1;
+ }
+ IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl);
+
+ if (-1 == ipa_nati_del_ipv4_rule(tbl_hdl, rule_hdl))
+ {
+ IPAERR("unable to delete rule from hw \n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * ipa_nat_query_timestamp() - to query timestamp
+ * @table_handle: [in] handle of ipv4 nat table
+ * @rule_handle: [in] ipv4 nat rule handle
+ * @time_stamp: [out] time stamp of rule
+ *
+ * To retrieve the timestamp that lastly the
+ * nat rule was accessed
+ *
+ * Returns: 0 On Success, negative on failure
+ */
+int ipa_nat_query_timestamp(uint32_t tbl_hdl,
+ uint32_t rule_hdl,
+ uint32_t *time_stamp)
+{
+
+ if (0 == tbl_hdl || tbl_hdl > IPA_NAT_MAX_IP4_TBLS ||
+ NULL == time_stamp)
+ {
+ IPAERR("invalid parameters passed \n");
+ return -1;
+ }
+ IPADBG("Passed Table: 0x%x and rule handle 0x%x\n", tbl_hdl, rule_hdl);
+
+ return ipa_nati_query_timestamp(tbl_hdl, rule_hdl, time_stamp);
+}
+
+
diff --git a/ipanat/src/ipa_nat_drvi.c b/ipanat/src/ipa_nat_drvi.c
new file mode 100644
index 0000000..d542a88
--- /dev/null
+++ b/ipanat/src/ipa_nat_drvi.c
@@ -0,0 +1,2387 @@
+/*
+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 "ipa_nat_drv.h"
+#include "ipa_nat_drvi.h"
+
+struct ipa_nat_cache ipv4_nat_cache;
+
+/* ------------------------------------------
+ UTILITY FUNCTIONS START
+ --------------------------------------------*/
+
+/**
+ * UpdateSwSpecParams() - updates sw specific params
+ * @rule: [in/out] nat table rule
+ * @param_type: [in] which param need to update
+ * @value: [in] value of param
+ *
+ * Update SW specific params in the passed rule.
+ *
+ * Returns: None
+ */
+void UpdateSwSpecParams(struct ipa_nat_rule *rule,
+ uint8_t param_type,
+ uint32_t value)
+{
+
+ uint32_t temp = rule->sw_spec_params;
+
+ if(IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE == param_type)
+ {
+ value = (value << INDX_TBL_ENTRY_SIZE_IN_BITS);
+ }
+
+ temp = (temp | value);
+ rule->sw_spec_params = temp;
+ return;
+}
+
+/**
+ * Read8BitFieldValue()
+ * @rule: [in/out]
+ * @param_type: [in]
+ * @value: [in]
+ *
+ *
+ *
+ * Returns: None
+ */
+
+uint8_t Read8BitFieldValue(uint32_t param,
+ ipa_nat_rule_field_type fld_type)
+{
+
+ void *temp = (void *)&param;
+
+ switch (fld_type)
+ {
+
+ case PROTOCOL_FIELD:
+ return ((time_stamp_proto *)temp)->protocol;
+
+ default:
+ IPAERR("Invalid Field type passed\n");
+ return 0;
+ }
+
+}
+
+uint16_t Read16BitFieldValue(uint32_t param,
+ ipa_nat_rule_field_type fld_type)
+{
+
+ void *temp = (void *)&param;
+
+ switch (fld_type)
+ {
+
+ case NEXT_INDEX_FIELD:
+ return ((next_index_pub_port *)temp)->next_index;
+
+ case PUBLIC_PORT_FILED:
+ return ((next_index_pub_port *)temp)->public_port;
+
+ case ENABLE_FIELD:
+ return ((ipcksum_enbl *)temp)->enable;
+
+ case SW_SPEC_PARAM_PREV_INDEX_FIELD:
+ return ((sw_spec_params *)temp)->prev_index;
+
+ case SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD:
+ return ((sw_spec_params *)temp)->index_table_entry;
+
+ case INDX_TBL_TBL_ENTRY_FIELD:
+ return ((tbl_ent_nxt_indx *)temp)->tbl_entry;
+
+ case INDX_TBL_NEXT_INDEX_FILED:
+ return ((tbl_ent_nxt_indx *)temp)->next_index;
+
+#ifdef NAT_DUMP
+ case IP_CHKSUM_FIELD:
+ return ((ipcksum_enbl *)temp)->ip_chksum;
+#endif
+
+ default:
+ IPAERR("Invalid Field type passed\n");
+ return 0;
+ }
+
+}
+
+uint32_t Read32BitFieldValue(uint32_t param,
+ ipa_nat_rule_field_type fld_type)
+{
+
+ void *temp = (void *)&param;
+
+ switch (fld_type)
+ {
+
+ case TIME_STAMP_FIELD:
+ return ((time_stamp_proto *)temp)->time_stamp;
+
+ default:
+ IPAERR("Invalid Field type passed\n");
+ return 0;
+ }
+
+}
+
+
+/**
+ * CreateNatDevice() - Create nat devices
+ * @mem: [in] name of device that need to create
+ *
+ * Create Nat device and Register for file create
+ * notification in given directory and wait till
+ * receive notification
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int CreateNatDevice(struct ipa_ioc_nat_alloc_mem *mem)
+{
+
+#define EVENT_SIZE (sizeof (struct inotify_event))
+#define FILE_NAME_LENGTH (sizeof(NAT_DEV_NAME)*2 + 1)
+#define BUF_LEN (EVENT_SIZE + FILE_NAME_LENGTH)
+
+ int length;
+ int wd;
+ char buffer[BUF_LEN];
+ int ret, inotify_fd;
+
+ inotify_fd = inotify_init();
+ if (inotify_fd < 0)
+ {
+ perror("inotify_init");
+ return -1;
+ }
+
+ IPADBG("Waiting for nofications in dir %s\n", NAT_DEV_DIR);
+ wd = inotify_add_watch(inotify_fd,
+ NAT_DEV_DIR,
+ IN_CREATE);
+
+ ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_ALLOC_NAT_MEM, mem);
+ if (ret != 0)
+ {
+ perror("CreateNatDevice(): ioctl error value");
+ IPAERR("unable to post nat mem init. Error ;%d\n", ret);
+ IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+ return -1;
+ }
+ IPADBG("posted IPA_IOC_ALLOC_NAT_MEM to kernel successfully \n");
+
+ length = read(inotify_fd, buffer, BUF_LEN );
+
+ if (length < 0)
+ {
+ perror("inotify read");
+ return -1;
+ }
+
+ struct inotify_event *event = (struct inotify_event *)buffer;
+ if(event->len)
+ {
+ if(event->mask & IN_CREATE)
+ {
+ if( event->mask & IN_ISDIR)
+ {
+ IPADBG("The directory %s was created.\n", event->name);
+ }
+ else
+ {
+ IPADBG("The file %s was created.\n", event->name);
+ }
+ }
+ }
+
+ (void) inotify_rm_watch(inotify_fd, wd);
+ (void) close(inotify_fd);
+ return 0;
+}
+
+/**
+ * GetNearest2Power() - Returns the nearest power of 2
+ * @num: [in] given number
+ * @ret: [out] nearest power of 2
+ *
+ * Returns the nearest power of 2 for a
+ * given number
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int GetNearest2Power (uint16_t num, uint16_t *ret)
+{
+ uint16_t number = num;
+ uint16_t tmp = 1;
+ *ret = 0;
+
+ if(0 == num)
+ {
+ return -1;
+ }
+
+ if(1 == num)
+ {
+ *ret = 2;
+ return 0;
+ }
+
+ for(;;)
+ {
+ if(1 == num)
+ {
+ if(number != tmp)
+ {
+ tmp *= 2;
+ }
+
+ *ret = tmp;
+ return 0;
+ }
+
+ num >>= 1;
+ tmp *= 2;
+ }
+
+ return -1;
+}
+
+/**
+ * GetNearestEven() - Returns the nearest even number
+ * @num: [in] given number
+ * @ret: [out] nearest even number
+ *
+ * Returns the nearest even number for a given number
+ *
+ * Returns: 0 on success, negative on failure
+ */
+void GetNearestEven (uint16_t num, uint16_t *ret)
+{
+
+ if(num < 2)
+ {
+ *ret = 2;
+ return;
+ }
+
+ while ((num % 2) != 0)
+ {
+ num = num + 1;
+ }
+
+ *ret = num;
+ return;
+}
+
+/**
+ * dst_hash() - Find the index into ipv4 base table
+ * @trgt_ip: [in] Target IP address
+ * @trgt_port: [in] Target port
+ * @public_port: [in] Public port
+ * @proto: [in] Protocol (TCP/IP)
+ * @size: [in] size of the ipv4 base Table
+ *
+ * This hash method is used to find the hash index of new nat
+ * entry into ipv4 base table. In case of zero index, the
+ * new entry will be stored into N-1 index where N is size of
+ * ipv4 base table
+ *
+ * Returns: >0 index into ipv4 base table, negative on failure
+ */
+static uint16_t dst_hash(uint32_t trgt_ip, uint16_t trgt_port,
+ uint16_t public_port, uint8_t proto,
+ uint16_t size)
+{
+ uint16_t hash = ((uint16_t)(trgt_ip)) ^ ((uint16_t)(trgt_ip>>16)) ^
+ (trgt_port) ^ (public_port) ^ (proto);
+
+ IPADBG("trgt_ip: 0x%x trgt_port: 0x%x\n", trgt_ip, trgt_port);
+ IPADBG("public_port: 0x%x\n", public_port);
+ IPADBG("proto: 0x%x size: 0x%x\n", proto, size);
+
+ hash = (hash & size);
+
+ /* If the hash resulted to zero then set it to maximum value
+ as zero is unused entry in nat tables */
+ if (0 == hash)
+ {
+ return size;
+ }
+
+ IPADBG("dst_hash returning value: %d\n", hash);
+ return hash;
+}
+
+/**
+ * src_hash() - Find the index into ipv4 index base table
+ * @priv_ip: [in] Private IP address
+ * @priv_port: [in] Private port
+ * @trgt_ip: [in] Target IP address
+ * @trgt_port: [in] Target Port
+ * @proto: [in] Protocol (TCP/IP)
+ * @size: [in] size of the ipv4 index base Table
+ *
+ * This hash method is used to find the hash index of new nat
+ * entry into ipv4 index base table. In case of zero index, the
+ * new entry will be stored into N-1 index where N is size of
+ * ipv4 index base table
+ *
+ * Returns: >0 index into ipv4 index base table, negative on failure
+ */
+static uint16_t src_hash(uint32_t priv_ip, uint16_t priv_port, uint32_t trgt_ip, uint16_t trgt_port, uint8_t proto, uint16_t size)
+{
+ uint16_t hash = ((uint16_t)(priv_ip)) ^ ((uint16_t)(priv_ip>>16)) ^
+ (priv_port) ^
+ ((uint16_t)(trgt_ip)) ^ ((uint16_t)(trgt_ip>>16)) ^
+ (trgt_port) ^ (proto);
+
+ IPADBG("priv_ip: 0x%x priv_port: 0x%x\n", priv_ip, priv_port);
+ IPADBG("trgt_ip: 0x%x trgt_port: 0x%x\n", trgt_ip, trgt_port);
+ IPADBG("proto: 0x%x size: 0x%x\n", proto, size);
+
+ hash = (hash & size);
+
+ /* If the hash resulted to zero then set it to maximum value
+ as zero is unused entry in nat tables */
+ if (0 == hash)
+ {
+ return size;
+ }
+
+ IPADBG("src_hash returning value: %d\n", hash);
+ return hash;
+}
+
+/**
+ * ipa_nati_calc_ip_cksum() - Calculate the source nat
+ * IP checksum diff
+ * @pub_ip_addr: [in] public ip address
+ * @priv_ip_addr: [in] Private ip address
+ *
+ * source nat ip checksum different is calculated as
+ * public_ip_addr - private_ip_addr
+ * Here we are using 1's complement to represent -ve number.
+ * So take 1's complement of private ip addr and add it
+ * to public ip addr.
+ *
+ * Returns: >0 ip checksum diff
+ */
+static uint16_t ipa_nati_calc_ip_cksum(uint32_t pub_ip_addr,
+ uint32_t priv_ip_addr)
+{
+ uint16_t ret;
+ uint32_t cksum = 0;
+
+ /* Add LSB(2 bytes) of public ip address to cksum */
+ cksum += (pub_ip_addr & 0xFFFF);
+
+ /* Add MSB(2 bytes) of public ip address to cksum
+ and check for carry forward(CF), if any add it
+ */
+ cksum += (pub_ip_addr>>16);
+ if (cksum>>16)
+ {
+ cksum = (cksum & 0x0000FFFF);
+ cksum += 1;
+ }
+
+ /* Calculate the 1's complement of private ip address */
+ priv_ip_addr = (~priv_ip_addr);
+
+ /* Add LSB(2 bytes) of private ip address to cksum
+ and check for carry forward(CF), if any add it
+ */
+ cksum += (priv_ip_addr & 0xFFFF);
+ if (cksum>>16)
+ {
+ cksum = (cksum & 0x0000FFFF);
+ cksum += 1;
+ }
+
+ /* Add MSB(2 bytes) of private ip address to cksum
+ and check for carry forward(CF), if any add it
+ */
+ cksum += (priv_ip_addr>>16);
+ if (cksum>>16)
+ {
+ cksum = (cksum & 0x0000FFFF);
+ cksum += 1;
+ }
+
+ /* Return the LSB(2 bytes) of checksum */
+ ret = (uint16_t)cksum;
+ return ret;
+
+}
+
+/**
+ * ipa_nati_calc_tcp_udp_cksum() - Calculate the source nat
+ * TCP/UDP checksum diff
+ * @pub_ip_addr: [in] public ip address
+ * @pub_port: [in] public tcp/udp port
+ * @priv_ip_addr: [in] Private ip address
+ * @priv_port: [in] Private tcp/udp prot
+ *
+ * source nat tcp/udp checksum is calculated as
+ * (pub_ip_addr + pub_port) - (priv_ip_addr + priv_port)
+ * Here we are using 1's complement to represent -ve number.
+ * So take 1's complement of prviate ip addr &private port
+ * and add it public ip addr & public port.
+ *
+ * Returns: >0 tcp/udp checksum diff
+ */
+static uint16_t ipa_nati_calc_tcp_udp_cksum(uint32_t pub_ip_addr, uint16_t pub_port,
+ uint32_t priv_ip_addr, uint16_t priv_port)
+{
+ uint16_t ret=0;
+ uint32_t cksum =0;
+
+ /* Add LSB(2 bytes) of public ip address to cksum */
+ cksum += (pub_ip_addr & 0xFFFF);
+
+ /* Add MSB(2 bytes) of public ip address to cksum
+ and check for carry forward(CF), if any add it
+ */
+ cksum += (pub_ip_addr>>16);
+ if (cksum>>16)
+ {
+ cksum = (cksum & 0x0000FFFF);
+ cksum += 1;
+ }
+
+ /* Add public port to cksum and
+ check for carry forward(CF), if any add it */
+ cksum += pub_port;
+ if (cksum>>16)
+ {
+ cksum = (cksum & 0x0000FFFF);
+ cksum += 1;
+ }
+
+ /* Calculate the 1's complement of private ip address */
+ priv_ip_addr = (~priv_ip_addr);
+
+ /* Add LSB(2 bytes) of private ip address to cksum
+ and check for carry forward(CF), if any add it
+ */
+ cksum += (priv_ip_addr & 0xFFFF);
+ if (cksum>>16)
+ {
+ cksum = (cksum & 0x0000FFFF);
+ cksum += 1;
+ }
+
+ /* Add MSB(2 bytes) of private ip address to cksum
+ and check for carry forward(CF), if any add
+ */
+ cksum += (priv_ip_addr>>16);
+ if (cksum>>16)
+ {
+ cksum = (cksum & 0x0000FFFF);
+ cksum += 1;
+ }
+
+ /* Calculate the 1's complement of private port */
+ priv_port = (~priv_port);
+
+ /* Add public port to cksum and
+ check for carry forward(CF), if any add it */
+ cksum += priv_port;
+ if (cksum>>16)
+ {
+ cksum = (cksum & 0x0000FFFF);
+ cksum += 1;
+ }
+
+ /* return the LSB(2 bytes) of checksum */
+ ret = (uint16_t)cksum;
+ return ret;
+
+}
+
+/**
+ * ipa_nati_make_rule_hdl() - makes nat rule handle
+ * @tbl_hdl: [in] nat table handle
+ * @tbl_entry: [in] nat table entry
+ *
+ * Calculate the nat rule handle which from
+ * nat entry which will be returned to client of
+ * nat driver
+ *
+ * Returns: >0 nat rule handle
+ */
+uint16_t ipa_nati_make_rule_hdl(uint16_t tbl_hdl,
+ uint16_t tbl_entry)
+{
+ struct ipa_nat_ip4_table_cache *tbl_ptr;
+ uint16_t rule_hdl = 0;
+ uint16_t cnt = 0;
+
+ tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1];
+
+ if (tbl_entry >= tbl_ptr->table_entries)
+ {
+ /* Update the index into table */
+ rule_hdl = tbl_entry - tbl_ptr->table_entries;
+ rule_hdl = (rule_hdl << IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+ /* Update the table type mask */
+ rule_hdl = (rule_hdl | IPA_NAT_RULE_HDL_TBL_TYPE_MASK);
+ }
+ else
+ {
+ rule_hdl = tbl_entry;
+ rule_hdl = (rule_hdl << IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+ }
+
+ for(; cnt< (tbl_ptr->table_entries + tbl_ptr->expn_table_entries); cnt++)
+ {
+ if (IPA_NAT_INVALID_NAT_ENTRY == tbl_ptr->rule_id_array[cnt])
+ {
+ tbl_ptr->rule_id_array[cnt] = rule_hdl;
+ return (cnt+1);
+ }
+ }
+
+ return cnt;
+}
+
+/**
+ * ipa_nati_parse_ipv4_rule_hdl() - prase rule handle
+ * @tbl_hdl: [in] nat table rule
+ * @rule_hdl: [in] nat rule handle
+ * @expn_tbl: [out] expansion table or not
+ * @tbl_entry: [out] index into table
+ *
+ * Parse the rule handle to retrieve the nat table
+ * type and entry of nat table
+ *
+ * Returns: None
+ */
+void ipa_nati_parse_ipv4_rule_hdl(uint8_t tbl_index,
+ uint16_t rule_hdl,
+ uint8_t *expn_tbl,
+ uint16_t *tbl_entry)
+{
+ struct ipa_nat_ip4_table_cache *tbl_ptr;
+ uint16_t rule_id;
+
+ *expn_tbl = 0;
+ *tbl_entry = IPA_NAT_INVALID_NAT_ENTRY;
+ tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_index];
+
+ if (rule_hdl >= (tbl_ptr->table_entries + tbl_ptr->expn_table_entries))
+ {
+ IPAERR("invalid rule handle\n");
+ return;
+ }
+
+ rule_id = tbl_ptr->rule_id_array[rule_hdl-1];
+
+ /* Retrieve the table type */
+ *expn_tbl = 0;
+ if(rule_id & IPA_NAT_RULE_HDL_TBL_TYPE_MASK)
+ {
+ *expn_tbl = 1;
+ }
+
+ /* Retrieve the table entry */
+ *tbl_entry = (rule_id >> IPA_NAT_RULE_HDL_TBL_TYPE_BITS);
+
+ return;
+}
+
+uint32_t ipa_nati_get_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+ nat_table_type tbl_type,
+ uint16_t tbl_entry)
+{
+ struct ipa_nat_rule *tbl_ptr;
+ uint32_t ret = 0;
+
+ if (IPA_NAT_EXPN_TBL == tbl_type)
+ {
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+ }
+ else
+ {
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+ }
+
+ ret = (char *)&tbl_ptr[tbl_entry] - (char *)tbl_ptr;
+ ret += cache_ptr->tbl_addr_offset;
+ return ret;
+}
+
+uint32_t ipa_nati_get_index_entry_offset(struct ipa_nat_ip4_table_cache *cache_ptr,
+ nat_table_type tbl_type,
+ uint16_t indx_tbl_entry)
+{
+ struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+ uint32_t ret = 0;
+
+ if (IPA_NAT_INDEX_EXPN_TBL == tbl_type)
+ {
+ indx_tbl_ptr =
+ (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+ }
+ else
+ {
+ indx_tbl_ptr =
+ (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+ }
+
+ ret = (char *)&indx_tbl_ptr[indx_tbl_entry] - (char *)indx_tbl_ptr;
+ ret += cache_ptr->tbl_addr_offset;
+ return ret;
+}
+
+/* ------------------------------------------
+ UTILITY FUNCTIONS END
+--------------------------------------------*/
+
+/* ------------------------------------------
+ Main Functions
+--------------------------------------------**/
+void ipa_nati_reset_tbl(uint8_t tbl_indx)
+{
+ uint16_t table_entries = ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+ uint16_t expn_table_entries = ipv4_nat_cache.ip4_tbl[tbl_indx].expn_table_entries;
+
+ /* Base table */
+ IPADBG("memset() base table to 0, %p\n",
+ ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr);
+
+ memset(ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr,
+ 0,
+ IPA_NAT_TABLE_ENTRY_SIZE * table_entries);
+
+ /* Base expansino table */
+ IPADBG("memset() expn base table to 0, %p\n",
+ ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr);
+
+ memset(ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr,
+ 0,
+ IPA_NAT_TABLE_ENTRY_SIZE * expn_table_entries);
+
+ /* Index table */
+ IPADBG("memset() index table to 0, %p\n",
+ ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_addr);
+
+ memset(ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_addr,
+ 0,
+ IPA_NAT_INDEX_TABLE_ENTRY_SIZE * table_entries);
+
+ /* Index expansion table */
+ IPADBG("memset() index expn table to 0, %p\n",
+ ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_expn_addr);
+
+ memset(ipv4_nat_cache.ip4_tbl[tbl_indx].index_table_expn_addr,
+ 0,
+ IPA_NAT_INDEX_TABLE_ENTRY_SIZE * expn_table_entries);
+
+ IPADBG("returning from ipa_nati_reset_tbl()\n");
+ return;
+}
+
+int ipa_nati_add_ipv4_tbl(uint32_t public_ip_addr,
+ uint16_t number_of_entries,
+ uint32_t *tbl_hdl)
+{
+ struct ipa_ioc_nat_alloc_mem mem;
+ uint8_t tbl_indx = ipv4_nat_cache.table_cnt;
+ uint16_t table_entries, expn_table_entries;
+ int ret;
+
+ *tbl_hdl = 0;
+ /* Allocate table */
+ memset(&mem, 0, sizeof(mem));
+ ret = ipa_nati_alloc_table(number_of_entries,
+ &mem,
+ &table_entries,
+ &expn_table_entries);
+ if (0 != ret)
+ {
+ IPAERR("unable to allocate nat table\n");
+ return -1;
+ }
+
+ /* Update the cache
+ The (IPA_NAT_UNUSED_BASE_ENTRIES/2) indicates zero entry entries
+ for both base and expansion table
+ */
+ ret = ipa_nati_update_cache(&mem,
+ public_ip_addr,
+ table_entries,
+ expn_table_entries);
+ if (0 != ret)
+ {
+ IPAERR("unable to update cache Error: %d\n", ret);
+ return -1;
+ }
+
+ /* Initialize the ipa hw with nat table dimensions */
+ ret = ipa_nati_post_ipv4_init_cmd(tbl_indx);
+ if (0 != ret)
+ {
+ IPAERR("unable to post nat_init command Error %d\n", ret);
+ return -1;
+ }
+
+ ipa_nati_reset_tbl(tbl_indx);
+
+ /* Return table handle */
+ ipv4_nat_cache.table_cnt++;
+ *tbl_hdl = ipv4_nat_cache.table_cnt;
+
+#ifdef NAT_DUMP
+ ipa_nat_dump_ipv4_table(*tbl_hdl);
+#endif
+ return 0;
+}
+
+int ipa_nati_alloc_table(uint16_t number_of_entries,
+ struct ipa_ioc_nat_alloc_mem *mem,
+ uint16_t *table_entries,
+ uint16_t *expn_table_entries)
+{
+ int fd = 0, ret;
+ uint16_t total_entries;
+
+ /* Copy the table name */
+ strcpy(mem->dev_name, NAT_DEV_NAME);
+
+ /* Calculate the size for base table and expansion table */
+ *table_entries = (uint16_t)(number_of_entries * IPA_NAT_BASE_TABLE_PERCENTAGE);
+ if(*table_entries == 0)
+ {
+ *table_entries = 1;
+ }
+ if(-1 == GetNearest2Power(*table_entries, table_entries))
+ {
+ IPAERR("unable to calculate power of 2\n");
+ return -1;
+ }
+
+ *expn_table_entries = (uint16_t)(number_of_entries * IPA_NAT_EXPANSION_TABLE_PERCENTAGE);
+ GetNearestEven(*expn_table_entries, expn_table_entries);
+
+ total_entries = (*table_entries) + (*expn_table_entries);
+
+ /* Calclate the memory size for both table and index table entries */
+ mem->size = (IPA_NAT_TABLE_ENTRY_SIZE * total_entries);
+ mem->size += (IPA_NAT_INDEX_TABLE_ENTRY_SIZE * total_entries);
+
+ if (!ipv4_nat_cache.ipa_fd)
+ {
+ fd = open(IPA_DEV_NAME, O_RDONLY);
+ if (fd < 0)
+ {
+ perror("ipa_nati_alloc_table(): open error value:");
+ IPAERR("unable to open ipa device\n");
+ return -1;
+ }
+ ipv4_nat_cache.ipa_fd = fd;
+ }
+
+ ret = CreateNatDevice(mem);
+ return ret;
+}
+
+
+int ipa_nati_update_cache(struct ipa_ioc_nat_alloc_mem *mem,
+ uint32_t public_addr,
+ uint16_t tbl_entries,
+ uint16_t expn_tbl_entries)
+{
+ uint32_t index = ipv4_nat_cache.table_cnt;
+ char *ipv4_rules_addr = NULL;
+
+ int fd = 0;
+ int flags = MAP_SHARED;
+ int prot = PROT_READ | PROT_WRITE;
+ off_t offset = 0;
+#ifdef IPA_ON_R3PC
+ int ret = 0;
+ uint32_t nat_mem_offset = 0;
+#endif
+
+ ipv4_nat_cache.ip4_tbl[index].valid = IPA_NAT_TABLE_VALID;
+ ipv4_nat_cache.ip4_tbl[index].public_addr = public_addr;
+ ipv4_nat_cache.ip4_tbl[index].size = mem->size;
+ ipv4_nat_cache.ip4_tbl[index].tbl_addr_offset = mem->offset;
+
+ ipv4_nat_cache.ip4_tbl[index].table_entries = tbl_entries;
+ ipv4_nat_cache.ip4_tbl[index].expn_table_entries = expn_tbl_entries;
+
+ IPADBG("num of ipv4 rules:%d\n",tbl_entries);
+ IPADBG("num of ipv4 expn rules:%d\n",expn_tbl_entries);
+
+ /* allocate memory for nat index expansion table */
+ if (NULL == ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta)
+ {
+ ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta =
+ malloc(sizeof(struct ipa_nat_indx_tbl_meta_info) * expn_tbl_entries);
+
+ if (NULL == ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta)
+ {
+ IPAERR("Fail to allocate ipv4 index expansion table meta\n");
+ return 0;
+ }
+
+ memset(ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta,
+ 0,
+ sizeof(struct ipa_nat_indx_tbl_meta_info) * expn_tbl_entries);
+ }
+
+ /* Allocate memory for rule_id_array */
+ if (NULL == ipv4_nat_cache.ip4_tbl[index].rule_id_array)
+ {
+ ipv4_nat_cache.ip4_tbl[index].rule_id_array =
+ malloc(sizeof(uint16_t) * (tbl_entries + expn_tbl_entries));
+
+ if (NULL == ipv4_nat_cache.ip4_tbl[index].rule_id_array)
+ {
+ IPAERR("Fail to allocate rule id array\n");
+ return 0;
+ }
+
+ memset(ipv4_nat_cache.ip4_tbl[index].rule_id_array,
+ 0,
+ sizeof(uint16_t) * (tbl_entries + expn_tbl_entries) );
+ }
+
+
+ /* open the nat table */
+ strcpy(mem->dev_name, NAT_DEV_FULL_NAME);
+ fd = open(mem->dev_name, O_RDWR);
+ if(fd < 0)
+ {
+ perror("ipa_nati_update_cache(): open error value:");
+ IPAERR("unable to open nat device. Error:%d\n",fd);
+ return -1;
+ }
+
+ /* copy the nat table name */
+ strncpy(ipv4_nat_cache.ip4_tbl[index].table_name,
+ mem->dev_name,
+ IPA_RESOURCE_NAME_MAX);
+ ipv4_nat_cache.ip4_tbl[index].nat_fd = fd;
+
+ /* open the nat device Table */
+#ifndef IPA_ON_R3PC
+ ipv4_rules_addr = (void *)mmap(NULL, mem->size,
+ prot, flags,
+ fd, offset);
+#else
+ IPADBG("user space r3pc \n");
+ ipv4_rules_addr = (void *)mmap((caddr_t)0, NAT_MMAP_MEM_SIZE,
+ prot, flags,
+ fd, offset);
+#endif
+ if(NULL == ipv4_rules_addr)
+ {
+ perror("unable to mmap the memory\n");
+ return -1;
+ }
+
+#ifdef IPA_ON_R3PC
+ ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_GET_NAT_OFFSET, &nat_mem_offset);
+ if (ret != 0)
+ {
+ perror("ipa_nati_post_ipv4_init_cmd(): ioctl error value");
+ IPAERR("unable to post ant offset cmd Error: %d\n",ret);
+ IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+ return -1;
+ }
+ ipv4_rules_addr += nat_mem_offset;
+ ipv4_nat_cache.ip4_tbl[index].mmap_offset = nat_mem_offset;
+#endif
+
+ IPADBG("mmap return value 0x%lx\n", (long unsigned int)ipv4_rules_addr);
+
+ ipv4_nat_cache.ip4_tbl[index].ipv4_rules_addr = ipv4_rules_addr;
+
+ ipv4_nat_cache.ip4_tbl[index].ipv4_expn_rules_addr =
+ ipv4_rules_addr + (IPA_NAT_TABLE_ENTRY_SIZE * tbl_entries);
+
+ ipv4_nat_cache.ip4_tbl[index].index_table_addr =
+ ipv4_rules_addr + (IPA_NAT_TABLE_ENTRY_SIZE * (tbl_entries + expn_tbl_entries));
+
+ ipv4_nat_cache.ip4_tbl[index].index_table_expn_addr =
+ ipv4_rules_addr +
+ (IPA_NAT_TABLE_ENTRY_SIZE * (tbl_entries + expn_tbl_entries)) +
+ (IPA_NAT_INDEX_TABLE_ENTRY_SIZE * tbl_entries);
+
+ return 0;
+}
+
+/* comment: check the implementation once
+ offset should be in terms of byes */
+int ipa_nati_post_ipv4_init_cmd(uint8_t tbl_index)
+{
+ struct ipa_ioc_v4_nat_init cmd;
+ uint32_t offset = ipv4_nat_cache.ip4_tbl[tbl_index].tbl_addr_offset;
+ int ret;
+
+ cmd.tbl_index = tbl_index;
+
+ cmd.ipv4_rules_offset = offset;
+ cmd.expn_rules_offset = cmd.ipv4_rules_offset +
+ (ipv4_nat_cache.ip4_tbl[tbl_index].table_entries * IPA_NAT_TABLE_ENTRY_SIZE);
+
+ cmd.index_offset = cmd.expn_rules_offset +
+ (ipv4_nat_cache.ip4_tbl[tbl_index].expn_table_entries * IPA_NAT_TABLE_ENTRY_SIZE);
+
+ cmd.index_expn_offset = cmd.index_offset +
+ (ipv4_nat_cache.ip4_tbl[tbl_index].table_entries * IPA_NAT_INDEX_TABLE_ENTRY_SIZE);
+
+ cmd.table_entries = ipv4_nat_cache.ip4_tbl[tbl_index].table_entries - 1;
+ cmd.expn_table_entries = ipv4_nat_cache.ip4_tbl[tbl_index].expn_table_entries;
+
+ cmd.ip_addr = ipv4_nat_cache.ip4_tbl[tbl_index].public_addr;
+
+ ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_V4_INIT_NAT, &cmd);
+ if (ret != 0)
+ {
+ perror("ipa_nati_post_ipv4_init_cmd(): ioctl error value");
+ IPAERR("unable to post init cmd Error: %d\n",ret);
+ IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+ return -1;
+ }
+ IPADBG("Posted IPA_IOC_V4_INIT_NAT to kernel successfully \n");
+
+ return 0;
+}
+
+int ipa_nati_del_ipv4_table(uint32_t tbl_hdl)
+{
+ uint8_t index = (uint8_t)(tbl_hdl - 1);
+ void *addr = (void *)ipv4_nat_cache.ip4_tbl[index].ipv4_rules_addr;
+ struct ipa_ioc_v4_nat_del del_cmd;
+ int ret;
+
+ if (!ipv4_nat_cache.ip4_tbl[index].valid)
+ {
+ IPAERR("invalid table handle passed\n");
+ return -1;
+ }
+
+ /* unmap the device memory from user space */
+#ifndef IPA_ON_R3PC
+ munmap(addr, ipv4_nat_cache.ip4_tbl[index].size);
+#else
+ addr = (char *)addr - ipv4_nat_cache.ip4_tbl[index].mmap_offset;
+ munmap(addr, NAT_MMAP_MEM_SIZE);
+#endif
+
+ /* close the file descriptor of nat device */
+ if (close(ipv4_nat_cache.ip4_tbl[index].nat_fd))
+ {
+ IPAERR("unable to close the file descriptor\n");
+ return -1;
+ }
+
+ del_cmd.table_index = index;
+ del_cmd.public_ip_addr = ipv4_nat_cache.ip4_tbl[index].public_addr;
+ ret = ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_V4_DEL_NAT, &del_cmd);
+ if (ret != 0)
+ {
+ perror("ipa_nati_del_ipv4_table(): ioctl error value");
+ IPAERR("unable to post nat del command init Error: %d\n",ret);
+ IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+ return -1;
+ }
+ IPADBG("posted IPA_IOC_V4_DEL_NAT to kernel successfully \n");
+
+ free(ipv4_nat_cache.ip4_tbl[index].index_expn_table_meta);
+ free(ipv4_nat_cache.ip4_tbl[index].rule_id_array);
+
+ memset(&ipv4_nat_cache.ip4_tbl[index],
+ 0,
+ sizeof(ipv4_nat_cache.ip4_tbl[index]));
+
+ /* Decrease the table count by 1*/
+ ipv4_nat_cache.table_cnt--;
+
+ return 0;
+}
+
+int ipa_nati_query_timestamp(uint32_t tbl_hdl,
+ uint32_t rule_hdl,
+ uint32_t *time_stamp)
+{
+ uint8_t tbl_index = (uint8_t)(tbl_hdl - 1);
+ uint8_t expn_tbl = 0;
+ uint16_t tbl_entry = 0;
+ struct ipa_nat_rule *tbl_ptr = NULL;
+
+ if (!ipv4_nat_cache.ip4_tbl[tbl_index].valid)
+ {
+ IPAERR("invalid table handle\n");
+ return -1;
+ }
+
+ ipa_nati_parse_ipv4_rule_hdl(tbl_index, (uint16_t)rule_hdl,
+ &expn_tbl, &tbl_entry);
+
+ tbl_ptr =
+ (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_index].ipv4_rules_addr;
+ if (expn_tbl)
+ {
+ tbl_ptr =
+ (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_index].ipv4_expn_rules_addr;
+ }
+
+ *time_stamp = Read32BitFieldValue(tbl_ptr[tbl_entry].ts_proto,
+ TIME_STAMP_FIELD);
+ return 0;
+}
+
+uint32_t ipa_nati_add_ipv4_rule(uint32_t tbl_hdl,
+ const ipa_nat_ipv4_rule *clnt_rule)
+{
+ struct ipa_nat_ip4_table_cache *tbl_ptr;
+ struct ipa_nat_sw_rule sw_rule;
+ struct ipa_nat_indx_tbl_sw_rule index_sw_rule;
+ uint16_t new_entry, new_index_tbl_entry;
+ uint32_t rule_hdl = 0;
+
+ memset(&sw_rule, 0, sizeof(sw_rule));
+ memset(&index_sw_rule, 0, sizeof(index_sw_rule));
+
+ /* Generate rule from client input */
+ if (-1 == ipa_nati_generate_rule(tbl_hdl, clnt_rule,
+ &sw_rule, &index_sw_rule,
+ &new_entry, &new_index_tbl_entry))
+ {
+ IPAERR("unable to generate rule\n");
+ return -1;
+ }
+
+ tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1];
+ ipa_nati_copy_ipv4_rule_to_hw(tbl_ptr, &sw_rule, new_entry, (uint8_t)(tbl_hdl-1));
+ ipa_nati_copy_ipv4_index_rule_to_hw(tbl_ptr,
+ &index_sw_rule,
+ new_index_tbl_entry,
+ (uint8_t)(tbl_hdl-1));
+
+ IPADBG("new entry:%d, new index entry: %d\n", new_entry, new_index_tbl_entry);
+ if( -1 == ipa_nati_post_ipv4_dma_cmd((uint8_t)(tbl_hdl-1), new_entry))
+ {
+ IPAERR("unable to post dma command\n");
+ return -1;
+ }
+
+ /* Generate rule handle */
+ rule_hdl = ipa_nati_make_rule_hdl((uint16_t)tbl_hdl, new_entry);
+ if (!rule_hdl)
+ {
+ IPAERR("unable to generate rule handle\n");
+ return -1;
+ }
+
+#ifdef NAT_DUMP
+ ipa_nat_dump_ipv4_table(tbl_hdl);
+#endif
+
+ return rule_hdl;
+}
+int ipa_nati_generate_rule(uint32_t tbl_hdl,
+ const ipa_nat_ipv4_rule *clnt_rule,
+ struct ipa_nat_sw_rule *rule,
+ struct ipa_nat_indx_tbl_sw_rule *index_sw_rule,
+ uint16_t *tbl_entry,
+ uint16_t *indx_tbl_entry)
+{
+
+ struct ipa_nat_ip4_table_cache *tbl_ptr;
+ uint16_t tmp;
+
+ if (NULL == clnt_rule || NULL == index_sw_rule ||
+ NULL == rule || NULL == tbl_entry ||
+ NULL == indx_tbl_entry)
+ {
+ IPAERR("invalid parameters\n");
+ return -1;
+ }
+
+ tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_hdl-1];
+
+ *tbl_entry = ipa_nati_generate_tbl_rule(clnt_rule,
+ rule,
+ tbl_ptr);
+ if (IPA_NAT_INVALID_NAT_ENTRY == *tbl_entry)
+ {
+ IPAERR("unable to generate table entry\n");
+ return -1;
+ }
+
+ index_sw_rule->tbl_entry = *tbl_entry;
+ *indx_tbl_entry = ipa_nati_generate_index_rule(clnt_rule,
+ index_sw_rule,
+ tbl_ptr);
+ if (IPA_NAT_INVALID_NAT_ENTRY == *indx_tbl_entry)
+ {
+ IPAERR("unable to generate index table entry\n");
+ return -1;
+ }
+
+ rule->indx_tbl_entry = *indx_tbl_entry;
+ if (*indx_tbl_entry >= tbl_ptr->table_entries)
+ {
+ tmp = *indx_tbl_entry - tbl_ptr->table_entries;
+ tbl_ptr->index_expn_table_meta[tmp].prev_index = index_sw_rule->prev_index;
+ }
+
+ return 0;
+}
+
+uint16_t ipa_nati_generate_tbl_rule(const ipa_nat_ipv4_rule *clnt_rule,
+ struct ipa_nat_sw_rule *sw_rule,
+ struct ipa_nat_ip4_table_cache *tbl_ptr)
+{
+ uint32_t pub_ip_addr;
+ uint16_t prev=0, nxt_indx=0, new_entry;
+ struct ipa_nat_rule *tbl = NULL, *expn_tbl = NULL;
+
+ pub_ip_addr = tbl_ptr->public_addr;
+
+ tbl = (struct ipa_nat_rule *)tbl_ptr->ipv4_rules_addr;
+ expn_tbl = (struct ipa_nat_rule *)tbl_ptr->ipv4_expn_rules_addr;
+
+ /* copy the values from client rule to sw rule */
+ sw_rule->private_ip = clnt_rule->private_ip;
+ sw_rule->private_port = clnt_rule->private_port;
+ sw_rule->protocol = clnt_rule->protocol;
+ sw_rule->public_port = clnt_rule->public_port;
+ sw_rule->target_ip = clnt_rule->target_ip;
+ sw_rule->target_port = clnt_rule->target_port;
+
+ /* consider only public and private ip fields */
+ sw_rule->ip_chksum = ipa_nati_calc_ip_cksum(pub_ip_addr,
+ clnt_rule->private_ip);
+
+ if(IPPROTO_TCP == sw_rule->protocol ||
+ IPPROTO_UDP == sw_rule->protocol)
+ {
+ /* consider public and private ip & port fields */
+ sw_rule->tcp_udp_chksum = ipa_nati_calc_tcp_udp_cksum(
+ pub_ip_addr,
+ clnt_rule->public_port,
+ clnt_rule->private_ip,
+ clnt_rule->private_port);
+ }
+
+ sw_rule->rsvd1 = 0;
+ sw_rule->enable = IPA_NAT_FLAG_DISABLE_BIT;
+ sw_rule->next_index = 0;
+
+ /*
+ SW sets this timer to 0.
+ The assumption is that 0 is an invalid clock value and no clock
+ wraparounds are expected
+ */
+ sw_rule->time_stamp = 0;
+ sw_rule->rsvd2 = 0;
+ sw_rule->prev_index = 0;
+ sw_rule->indx_tbl_entry = 0;
+
+ new_entry = dst_hash(clnt_rule->target_ip,
+ clnt_rule->target_port,
+ clnt_rule->public_port,
+ clnt_rule->protocol,
+ tbl_ptr->table_entries-1 );
+
+ /* check whether there is any collision
+ if no collision return */
+ if (! Read16BitFieldValue(tbl[new_entry].ip_cksm_enbl,
+ ENABLE_FIELD))
+ {
+ sw_rule->prev_index = 0;
+ IPADBG("Destination Nat New Entry Index %d\n",new_entry);
+ return new_entry;
+ }
+
+ /* First collision */
+ if (Read16BitFieldValue(tbl[new_entry].nxt_indx_pub_port,
+ NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ sw_rule->prev_index = new_entry;
+ }
+ /* check for more than one collision */
+ else
+ {
+ /* Find the IPA_NAT_DEL_TYPE_LAST entry in list */
+ nxt_indx = Read16BitFieldValue(tbl[new_entry].nxt_indx_pub_port,
+ NEXT_INDEX_FIELD);
+
+ while(nxt_indx != IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ prev = nxt_indx;
+
+ nxt_indx -= tbl_ptr->table_entries;
+ nxt_indx = Read16BitFieldValue(expn_tbl[nxt_indx].nxt_indx_pub_port,
+ NEXT_INDEX_FIELD);
+
+ /* Handling error case */
+ if(prev == nxt_indx)
+ {
+ IPAERR("Error: Prev index:%d and next:%d index should not be same \n", prev, nxt_indx);
+ return IPA_NAT_INVALID_NAT_ENTRY;
+ }
+ }
+
+ sw_rule->prev_index = prev;
+ }
+
+ /* On collision check for the free entry in expansion table */
+ new_entry = ipa_nati_expn_tbl_free_entry(expn_tbl,
+ tbl_ptr->expn_table_entries);
+
+ if (IPA_NAT_INVALID_NAT_ENTRY == new_entry)
+ {
+ /* Expansion table is full return*/
+ IPAERR("expansion table is full\n");
+ return IPA_NAT_INVALID_NAT_ENTRY;
+ }
+ new_entry += tbl_ptr->table_entries;
+
+ IPADBG("new entry index %d\n",new_entry);
+ return new_entry;
+}
+
+/* returns expn table entry index */
+uint16_t ipa_nati_expn_tbl_free_entry(struct ipa_nat_rule *expn_tbl,
+ uint16_t size)
+{
+ int cnt;
+
+ for (cnt=1; cnt<size; cnt++)
+ {
+ if (!Read16BitFieldValue(expn_tbl[cnt].ip_cksm_enbl,
+ ENABLE_FIELD))
+ {
+ IPADBG("new expansion table entry index %d\n",cnt);
+ return cnt;
+ }
+ }
+
+ IPAERR("nat expansion table is full\n");
+ return 0;
+
+}
+
+uint16_t ipa_nati_generate_index_rule(const ipa_nat_ipv4_rule *clnt_rule,
+ struct ipa_nat_indx_tbl_sw_rule *sw_rule,
+ struct ipa_nat_ip4_table_cache *tbl_ptr)
+{
+ struct ipa_nat_indx_tbl_rule *indx_tbl, *indx_expn_tbl;
+ uint16_t prev=0, nxt_indx=0, new_entry;
+
+ indx_tbl =
+ (struct ipa_nat_indx_tbl_rule *)tbl_ptr->index_table_addr;
+ indx_expn_tbl =
+ (struct ipa_nat_indx_tbl_rule *)tbl_ptr->index_table_expn_addr;
+
+ new_entry = src_hash(clnt_rule->private_ip,
+ clnt_rule->private_port,
+ clnt_rule->target_ip,
+ clnt_rule->target_port,
+ clnt_rule->protocol,
+ tbl_ptr->table_entries-1);
+
+ /* check whether there is any collision
+ if no collision return */
+ if (!Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+ INDX_TBL_TBL_ENTRY_FIELD) )
+ {
+ sw_rule->prev_index = 0;
+ IPADBG("Source Nat Index Table Entry %d\n",new_entry);
+ return new_entry;
+ }
+
+ /* check for more than one collision */
+ if (Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ sw_rule->prev_index = new_entry;
+ IPADBG("First collosion. Entry %d\n",new_entry);
+ }
+ else
+ {
+ /* Find the IPA_NAT_DEL_TYPE_LAST entry in list */
+ nxt_indx = Read16BitFieldValue(indx_tbl[new_entry].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED);
+ //prev = nxt_indx;
+
+ while(nxt_indx != IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ prev = nxt_indx;
+
+ nxt_indx -= tbl_ptr->table_entries;
+ nxt_indx = Read16BitFieldValue(indx_expn_tbl[nxt_indx].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED);
+
+ /* Handling error case */
+ if(prev == nxt_indx)
+ {
+ IPAERR("Error: Prev:%d and next:%d index should not be same \n", prev, nxt_indx);
+ return IPA_NAT_INVALID_NAT_ENTRY;
+ }
+ }
+
+ sw_rule->prev_index = prev;
+ }
+
+ /* On collision check for the free entry in expansion table */
+ new_entry = ipa_nati_index_expn_get_free_entry(
+ indx_expn_tbl,
+ tbl_ptr->expn_table_entries);
+
+ if ( IPA_NAT_INVALID_NAT_ENTRY == new_entry)
+ {
+ /* Expansion table is full return*/
+ IPAERR("index expansion table is full\n");
+ return IPA_NAT_INVALID_NAT_ENTRY;
+ }
+ new_entry += tbl_ptr->table_entries;
+
+ IPADBG("index table entry %d\n", new_entry);
+ return new_entry;
+}
+
+/* returns index expn table entry index */
+uint16_t ipa_nati_index_expn_get_free_entry(struct ipa_nat_indx_tbl_rule *indx_tbl,
+ uint16_t size)
+{
+ int cnt;
+ for (cnt=1; cnt<size; cnt++)
+ {
+ if (!Read16BitFieldValue(indx_tbl[cnt].tbl_entry_nxt_indx,
+ INDX_TBL_TBL_ENTRY_FIELD))
+ {
+ return cnt;
+ }
+ }
+
+ IPAERR("nat index expansion table is full\n");
+ return 0;
+}
+
+void ipa_nati_write_next_index(uint8_t tbl_indx,
+ nat_table_type tbl_type,
+ uint16_t value,
+ uint32_t offset)
+{
+ struct ipa_ioc_nat_dma_cmd *cmd;
+
+ IPADBG("Updating next index field of table %d on collosion using dma\n", tbl_type);
+ IPADBG("table index: %d, value: %d offset;%d \n", tbl_indx, value, offset);
+
+ cmd = (struct ipa_ioc_nat_dma_cmd *)
+ malloc( sizeof(struct ipa_ioc_nat_dma_cmd) +
+ sizeof(struct ipa_ioc_nat_dma_one));
+ if(NULL == cmd)
+ {
+ IPAERR("unable to allocate memory\n");
+ return;
+ }
+
+ cmd->dma[0].table_index = tbl_indx;
+ cmd->dma[0].base_addr = tbl_type;
+ cmd->dma[0].data = value;
+ cmd->dma[0].offset = offset;
+
+ cmd->entries = 1;
+ if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd))
+ {
+ perror("ipa_nati_post_ipv4_dma_cmd(): ioctl error value");
+ IPAERR("unable to call dma icotl to update next index\n");
+ IPAERR("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+ goto fail;
+ }
+
+ fail:
+ free(cmd);
+
+ return;
+}
+
+void ipa_nati_copy_ipv4_rule_to_hw(
+ struct ipa_nat_ip4_table_cache *ipv4_cache,
+ struct ipa_nat_sw_rule *rule,
+ uint16_t entry, uint8_t tbl_index)
+{
+ struct ipa_nat_rule *tbl_ptr;
+ uint16_t prev_entry = rule->prev_index;
+ nat_table_type tbl_type;
+ uint32_t offset = 0;
+
+ if (entry < ipv4_cache->table_entries)
+ {
+ tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_rules_addr;
+
+ memcpy( &tbl_ptr[entry],
+ rule,
+ sizeof(struct ipa_nat_rule));
+ }
+ else
+ {
+ tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_expn_rules_addr;
+ memcpy( &tbl_ptr[entry - ipv4_cache->table_entries],
+ rule,
+ sizeof(struct ipa_nat_rule));
+ }
+
+ /* Update the previos entry next_index */
+ if(IPA_NAT_INVALID_NAT_ENTRY != prev_entry)
+ {
+
+ if (prev_entry < ipv4_cache->table_entries)
+ {
+ tbl_type = IPA_NAT_BASE_TBL;
+ tbl_ptr = (struct ipa_nat_rule *)ipv4_cache->ipv4_rules_addr;
+ }
+ else
+ {
+ tbl_type = IPA_NAT_EXPN_TBL;
+ /* tbp_ptr is already pointing to expansion table
+ no need to initialize it */
+ prev_entry = prev_entry - ipv4_cache->table_entries;
+ }
+
+ offset = ipa_nati_get_entry_offset(ipv4_cache, tbl_type, prev_entry);
+ offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+
+ ipa_nati_write_next_index(tbl_index, tbl_type, entry, offset);
+ }
+
+ return;
+}
+
+void ipa_nati_copy_ipv4_index_rule_to_hw(
+ struct ipa_nat_ip4_table_cache *ipv4_cache,
+ struct ipa_nat_indx_tbl_sw_rule *indx_sw_rule,
+ uint16_t entry,
+ uint8_t tbl_index)
+{
+ struct ipa_nat_indx_tbl_rule *tbl_ptr;
+ struct ipa_nat_sw_indx_tbl_rule sw_rule;
+ uint16_t prev_entry = indx_sw_rule->prev_index;
+ nat_table_type tbl_type;
+ uint16_t offset = 0;
+
+ sw_rule.next_index = indx_sw_rule->next_index;
+ sw_rule.tbl_entry = indx_sw_rule->tbl_entry;
+
+ if (entry < ipv4_cache->table_entries)
+ {
+ tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_addr;
+
+ memcpy( &tbl_ptr[entry],
+ &sw_rule,
+ sizeof(struct ipa_nat_indx_tbl_rule));
+ }
+ else
+ {
+ tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_expn_addr;
+
+ memcpy( &tbl_ptr[entry - ipv4_cache->table_entries],
+ &sw_rule,
+ sizeof(struct ipa_nat_indx_tbl_rule));
+ }
+
+ /* Update the next field of previous entry on collosion */
+ if (IPA_NAT_INVALID_NAT_ENTRY != prev_entry)
+ {
+ if (prev_entry < ipv4_cache->table_entries)
+ {
+ tbl_type = IPA_NAT_INDX_TBL;
+ tbl_ptr = (struct ipa_nat_indx_tbl_rule *)ipv4_cache->index_table_addr;
+ }
+ else
+ {
+ tbl_type = IPA_NAT_INDEX_EXPN_TBL;
+ /* tbp_ptr is already pointing to expansion table
+ no need to initialize it */
+ prev_entry = prev_entry - ipv4_cache->table_entries;
+ }
+
+ offset = ipa_nati_get_index_entry_offset(ipv4_cache, tbl_type, prev_entry);
+ offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+
+ IPADBG("Updating next index field of index table on collosion using dma()\n");
+ ipa_nati_write_next_index(tbl_index, tbl_type, entry, offset);
+ }
+
+ return;
+}
+
+int ipa_nati_post_ipv4_dma_cmd(uint8_t tbl_indx,
+ uint16_t entry)
+{
+ struct ipa_ioc_nat_dma_cmd *cmd;
+ struct ipa_nat_rule *tbl_ptr;
+ uint32_t offset = ipv4_nat_cache.ip4_tbl[tbl_indx].tbl_addr_offset;
+ int ret = 0;
+
+ cmd = (struct ipa_ioc_nat_dma_cmd *)
+ malloc( sizeof(struct ipa_ioc_nat_dma_cmd) +
+ sizeof(struct ipa_ioc_nat_dma_one));
+ if(NULL == cmd)
+ {
+ IPAERR("unable to allocate memory\n");
+ return -1;
+ }
+
+ if (entry < ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries)
+ {
+ tbl_ptr =
+ (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr;
+
+ cmd->dma[0].table_index = tbl_indx;
+ cmd->dma[0].base_addr = IPA_NAT_BASE_TBL;
+ cmd->dma[0].data = IPA_NAT_FLAG_ENABLE_BIT_MASK;
+
+ cmd->dma[0].offset = (char *)&tbl_ptr[entry] - (char *)tbl_ptr;
+ cmd->dma[0].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+ }
+ else
+ {
+ tbl_ptr =
+ (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_expn_rules_addr;
+ entry = entry - ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+
+ cmd->dma[0].table_index = tbl_indx;
+ cmd->dma[0].base_addr = IPA_NAT_EXPN_TBL;
+ cmd->dma[0].data = IPA_NAT_FLAG_ENABLE_BIT_MASK;
+
+ cmd->dma[0].offset = (char *)&tbl_ptr[entry] - (char *)tbl_ptr;
+ cmd->dma[0].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+ cmd->dma[0].offset += offset;
+ }
+
+ cmd->entries = 1;
+ if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd))
+ {
+ perror("ipa_nati_post_ipv4_dma_cmd(): ioctl error value");
+ IPAERR("unable to call dma icotl\n");
+ IPADBG("ipa fd %d\n",ipv4_nat_cache.ipa_fd);
+ ret = -1;
+ goto fail;
+ }
+ IPADBG("posted IPA_IOC_NAT_DMA to kernel successfully during add operation \n");
+
+
+ fail:
+ free(cmd);
+
+ return ret;
+}
+
+
+int ipa_nati_del_ipv4_rule(uint32_t tbl_hdl,
+ uint32_t rule_hdl)
+{
+ uint8_t expn_tbl;
+ uint16_t tbl_entry;
+ struct ipa_nat_ip4_table_cache *tbl_ptr;
+ del_type rule_pos;
+ uint8_t tbl_indx = (uint8_t)(tbl_hdl-1);
+
+ /* Parse the rule handle */
+ ipa_nati_parse_ipv4_rule_hdl(tbl_indx, (uint16_t)rule_hdl,
+ &expn_tbl, &tbl_entry);
+ if (IPA_NAT_INVALID_NAT_ENTRY == tbl_entry)
+ {
+ IPAERR("Invalid Rule Entry\n");
+ return -1;
+ }
+
+ IPADBG("Delete below rule\n");
+ IPADBG("tbl_entry:%d expn_tbl:%d \n",tbl_entry, expn_tbl);
+
+ tbl_ptr = &ipv4_nat_cache.ip4_tbl[tbl_indx];
+ if (!tbl_ptr->valid)
+ {
+ IPAERR("invalid table handle\n");
+ return -1;
+ }
+
+ ipa_nati_find_rule_pos(tbl_ptr, expn_tbl,
+ tbl_entry, &rule_pos);
+ IPADBG("rule_pos:%d\n", rule_pos);
+
+ if(0 != ipa_nati_post_del_dma_cmd(tbl_indx, tbl_entry,
+ expn_tbl, rule_pos))
+ {
+ return -1;
+ }
+
+ ipa_nati_del_dead_ipv4_head_nodes(tbl_indx);
+
+ /* Reset rule_id_array entry */
+ ipv4_nat_cache.ip4_tbl[tbl_indx].rule_id_array[rule_hdl-1] =
+ IPA_NAT_INVALID_NAT_ENTRY;
+
+#ifdef NAT_DUMP
+ IPADBG("Dumping Table after deleting rule\n");
+ ipa_nat_dump_ipv4_table(tbl_hdl);
+#endif
+
+ return 0;
+}
+
+void ReorderCmds(struct ipa_ioc_nat_dma_cmd *cmd, int size)
+{
+ int indx_tbl_start = 0, cnt, cnt1;
+ struct ipa_ioc_nat_dma_cmd *tmp;
+
+ IPADBG("called ReorderCmds() with entries :%d\n", cmd->entries);
+
+ for (cnt=0; cnt<cmd->entries; cnt++)
+ {
+ if (cmd->dma[cnt].base_addr == IPA_NAT_INDX_TBL ||
+ cmd->dma[cnt].base_addr == IPA_NAT_INDEX_EXPN_TBL)
+ {
+ indx_tbl_start = cnt;
+ break;
+ }
+ }
+
+ if (indx_tbl_start == 0)
+ {
+ IPADBG("Reorder not needed\n");
+ return;
+ }
+
+ tmp = (struct ipa_ioc_nat_dma_cmd *)malloc(size);
+ if (tmp == NULL)
+ {
+ IPAERR("unable to allocate memory\n");
+ return;
+ }
+
+ cnt1 = 0;
+ tmp->entries = cmd->entries;
+ for (cnt=indx_tbl_start; cnt<cmd->entries; cnt++)
+ {
+ memcpy(&tmp->dma[cnt1], &cmd->dma[cnt],
+ sizeof(struct ipa_ioc_nat_dma_one));
+ cnt1++;
+ }
+
+ for (cnt = 0; cnt<indx_tbl_start; cnt++)
+ {
+ memcpy(&tmp->dma[cnt1], &cmd->dma[cnt],
+ sizeof(struct ipa_ioc_nat_dma_one));
+ cnt1++;
+ }
+
+ memset(cmd, 0, size);
+ memcpy(cmd, tmp, size);
+ free(tmp);
+
+ return;
+}
+
+int ipa_nati_post_del_dma_cmd(uint8_t tbl_indx,
+ uint16_t cur_tbl_entry,
+ uint8_t expn_tbl,
+ del_type rule_pos)
+{
+
+#define MAX_DMA_ENTRIES_FOR_DEL 3
+
+ struct ipa_nat_ip4_table_cache *cache_ptr;
+ struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+ struct ipa_nat_rule *tbl_ptr;
+ int ret = 0, size = 0;
+
+ uint16_t indx_tbl_entry = IPA_NAT_INVALID_NAT_ENTRY;
+ del_type indx_rule_pos;
+
+ struct ipa_ioc_nat_dma_cmd *cmd;
+ uint8_t no_of_cmds = 0;
+
+ uint16_t prev_entry = IPA_NAT_INVALID_NAT_ENTRY;
+ uint16_t next_entry = IPA_NAT_INVALID_NAT_ENTRY;
+ uint16_t table_entry;
+
+ size = sizeof(struct ipa_ioc_nat_dma_cmd) +
+ (MAX_DMA_ENTRIES_FOR_DEL * sizeof(struct ipa_ioc_nat_dma_one));
+
+ cmd = (struct ipa_ioc_nat_dma_cmd *)malloc(size);
+ if (NULL == cmd)
+ {
+ IPAERR("unable to allocate memory\n");
+ return -1;
+ }
+
+ cache_ptr = &ipv4_nat_cache.ip4_tbl[tbl_indx];
+ if (!expn_tbl)
+ {
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+ }
+ else
+ {
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+ }
+
+
+ if (!Read16BitFieldValue(tbl_ptr[cur_tbl_entry].ip_cksm_enbl,
+ ENABLE_FIELD))
+ {
+ IPAERR("Deleting invalid(not enabled) rule\n");
+ ret = -1;
+ goto fail;
+ }
+
+ indx_tbl_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+ SW_SPEC_PARAM_INDX_TBL_ENTRY_FIELD);
+ /* ================================================
+ Base Table rule Deletion
+ ================================================*/
+ /* Just delete the current rule by disabling the flag field */
+ if (IPA_NAT_DEL_TYPE_ONLY_ONE == rule_pos)
+ {
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+ cmd->dma[no_of_cmds].data = IPA_NAT_FLAG_DISABLE_BIT_MASK;
+
+ cmd->dma[no_of_cmds].offset =
+ ipa_nati_get_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ cur_tbl_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_FLAG_FIELD_OFFSET;
+ }
+
+ /* Just update the protocol field to invalid */
+ if (IPA_NAT_DEL_TYPE_HEAD == rule_pos)
+ {
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+ cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_PROTO_FIELD_VALUE;
+
+ cmd->dma[no_of_cmds].offset =
+ ipa_nati_get_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ cur_tbl_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_PROTO_FIELD_OFFSET;
+
+ IPADBG("writing invalid proto: 0x%x\n", cmd->dma[no_of_cmds].data);
+ }
+
+ /*
+ Update the previous entry of next_index field value
+ with current entry next_index field value
+ */
+ if (IPA_NAT_DEL_TYPE_MIDDLE == rule_pos)
+ {
+ prev_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+ SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+ cmd->dma[no_of_cmds].data = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].nxt_indx_pub_port,
+ NEXT_INDEX_FIELD);
+
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+ if (prev_entry >= cache_ptr->table_entries)
+ {
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_EXPN_TBL;
+ prev_entry -= cache_ptr->table_entries;
+ }
+
+ cmd->dma[no_of_cmds].offset = ipa_nati_get_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ prev_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+
+ }
+
+ /*
+ Reset the previous entry of next_index field with 0
+ */
+ if (IPA_NAT_DEL_TYPE_LAST == rule_pos)
+ {
+ prev_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+ SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+ cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_BASE_TBL;
+ if (prev_entry >= cache_ptr->table_entries)
+ {
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_EXPN_TBL;
+ prev_entry -= cache_ptr->table_entries;
+ }
+
+ cmd->dma[no_of_cmds].offset = ipa_nati_get_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ prev_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_RULE_NEXT_FIELD_OFFSET;
+ }
+
+ /* ================================================
+ Base Table rule Deletion End
+ ================================================*/
+
+ /* ================================================
+ Index Table rule Deletion
+ ================================================*/
+ ipa_nati_find_index_rule_pos(cache_ptr,
+ indx_tbl_entry,
+ &indx_rule_pos);
+ IPADBG("Index table entry: 0x%x\n", indx_tbl_entry);
+ IPADBG("and position: %d\n", indx_rule_pos);
+ if (indx_tbl_entry >= cache_ptr->table_entries)
+ {
+ indx_tbl_entry -= cache_ptr->table_entries;
+ indx_tbl_ptr =
+ (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+ }
+ else
+ {
+ indx_tbl_ptr =
+ (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+ }
+
+ /* Just delete the current rule by resetting nat_table_index field to 0 */
+ if (IPA_NAT_DEL_TYPE_ONLY_ONE == indx_rule_pos)
+ {
+ no_of_cmds++;
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+ cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+ cmd->dma[no_of_cmds].offset = ipa_nati_get_index_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ indx_tbl_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET;
+ }
+
+ /* copy the next entry values to current entry */
+ if (IPA_NAT_DEL_TYPE_HEAD == indx_rule_pos)
+ {
+ next_entry = Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED);
+ next_entry -= cache_ptr->table_entries;
+
+ no_of_cmds++;
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+
+ /* Copy the nat_table_index field value of next entry */
+ indx_tbl_ptr =
+ (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+ cmd->dma[no_of_cmds].data = Read16BitFieldValue(indx_tbl_ptr[next_entry].tbl_entry_nxt_indx,
+ INDX_TBL_TBL_ENTRY_FIELD);
+
+ cmd->dma[no_of_cmds].offset = ipa_nati_get_index_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ indx_tbl_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NAT_INDEX_FIELD_OFFSET;
+
+ /* Copy the next_index field value of next entry */
+ no_of_cmds++;
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+ cmd->dma[no_of_cmds].data = Read16BitFieldValue(indx_tbl_ptr[next_entry].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED);
+
+ cmd->dma[no_of_cmds].offset = ipa_nati_get_index_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ indx_tbl_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+ }
+
+ /*
+ Update the previous entry of next_index field value
+ with current entry next_index field value
+ */
+ if (IPA_NAT_DEL_TYPE_MIDDLE == indx_rule_pos)
+ {
+ prev_entry = cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+ no_of_cmds++;
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+ cmd->dma[no_of_cmds].data = Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED);
+
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+ if (prev_entry >= cache_ptr->table_entries)
+ {
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDEX_EXPN_TBL;
+ prev_entry -= cache_ptr->table_entries;
+ }
+
+ cmd->dma[no_of_cmds].offset = ipa_nati_get_index_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ prev_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+ }
+
+ /* Reset the previous entry next_index field with 0 */
+ if (IPA_NAT_DEL_TYPE_LAST == indx_rule_pos)
+ {
+ prev_entry = cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+ no_of_cmds++;
+ cmd->dma[no_of_cmds].table_index = tbl_indx;
+ cmd->dma[no_of_cmds].data = IPA_NAT_INVALID_NAT_ENTRY;
+
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDX_TBL;
+ if (prev_entry >= cache_ptr->table_entries)
+ {
+ cmd->dma[no_of_cmds].base_addr = IPA_NAT_INDEX_EXPN_TBL;
+ prev_entry -= cache_ptr->table_entries;
+ }
+
+ cmd->dma[no_of_cmds].offset =
+ ipa_nati_get_index_entry_offset(cache_ptr,
+ cmd->dma[no_of_cmds].base_addr,
+ prev_entry);
+ cmd->dma[no_of_cmds].offset += IPA_NAT_INDEX_RULE_NEXT_FIELD_OFFSET;
+ }
+
+ /* ================================================
+ Index Table rule Deletion End
+ ================================================*/
+ cmd->entries = no_of_cmds + 1;
+
+ if (cmd->entries > 1)
+ {
+ ReorderCmds(cmd, size);
+ }
+ if (ioctl(ipv4_nat_cache.ipa_fd, IPA_IOC_NAT_DMA, cmd))
+ {
+ perror("ipa_nati_post_del_dma_cmd(): ioctl error value");
+ IPAERR("unable to post cmd\n");
+ IPADBG("ipa fd %d\n", ipv4_nat_cache.ipa_fd);
+ ret = -1;
+ goto fail;
+ }
+
+ /* if entry exist in IPA_NAT_DEL_TYPE_MIDDLE of list
+ Update the previous entry in sw specific parameters
+ */
+ if (IPA_NAT_DEL_TYPE_MIDDLE == rule_pos)
+ {
+ /* Retrieve the current entry prev_entry value */
+ prev_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].sw_spec_params,
+ SW_SPEC_PARAM_PREV_INDEX_FIELD);
+
+ /* Retrieve the next entry */
+ next_entry = Read16BitFieldValue(tbl_ptr[cur_tbl_entry].nxt_indx_pub_port,
+ NEXT_INDEX_FIELD);
+ next_entry -= cache_ptr->table_entries;
+
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+
+ /* copy the current entry prev_entry value to next entry*/
+ UpdateSwSpecParams(&tbl_ptr[next_entry],
+ IPA_NAT_SW_PARAM_PREV_INDX_BYTE,
+ prev_entry);
+ }
+
+ /* Reset the other field values of current delete entry
+ In case of IPA_NAT_DEL_TYPE_HEAD, don't reset */
+ if (IPA_NAT_DEL_TYPE_HEAD != rule_pos)
+ {
+ memset(&tbl_ptr[cur_tbl_entry], 0, sizeof(struct ipa_nat_rule));
+ }
+
+ if (IPA_NAT_DEL_TYPE_HEAD == indx_rule_pos)
+ {
+ /* Reset the next entry to IPA_NAT_DEL_TYPE_HEAD as we copied
+ the next entry to IPA_NAT_DEL_TYPE_HEAD */
+ indx_tbl_ptr[next_entry].tbl_entry_nxt_indx = 0;
+
+ /*
+ In case of IPA_NAT_DEL_TYPE_HEAD, update the sw specific parameters
+ (index table entry) of base table entry
+ */
+ indx_tbl_ptr =
+ (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+ table_entry = Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+ INDX_TBL_TBL_ENTRY_FIELD);
+ if (table_entry >= cache_ptr->table_entries)
+ {
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+ table_entry -= cache_ptr->table_entries;
+ }
+ else
+ {
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+ }
+
+ UpdateSwSpecParams(&tbl_ptr[table_entry],
+ IPA_NAT_SW_PARAM_INDX_TBL_ENTRY_BYTE,
+ indx_tbl_entry);
+ }
+ else
+ {
+ /* Update the prev_entry value (in index_expn_table_meta)
+ for the next_entry in list with current entry prev_entry value
+ */
+ if (IPA_NAT_DEL_TYPE_MIDDLE == indx_rule_pos)
+ {
+ next_entry = Read16BitFieldValue(indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED);
+ if (next_entry >= cache_ptr->table_entries)
+ {
+ next_entry -= cache_ptr->table_entries;
+ }
+
+ cache_ptr->index_expn_table_meta[next_entry].prev_index =
+ cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index;
+
+ cache_ptr->index_expn_table_meta[indx_tbl_entry].prev_index =
+ IPA_NAT_INVALID_NAT_ENTRY;
+ }
+
+ IPADBG("At, indx_tbl_entry value: %d\n", indx_tbl_entry);
+ IPADBG("At, indx_tbl_entry member address: %p\n",
+ &indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx);
+
+ indx_tbl_ptr[indx_tbl_entry].tbl_entry_nxt_indx = 0;
+
+ }
+
+fail:
+ free(cmd);
+
+ return ret;
+}
+
+void ipa_nati_find_index_rule_pos(
+ struct ipa_nat_ip4_table_cache *cache_ptr,
+ uint16_t tbl_entry,
+ del_type *rule_pos)
+{
+
+ struct ipa_nat_indx_tbl_rule *tbl_ptr;
+
+ if(tbl_entry >= cache_ptr->table_entries)
+ {
+ tbl_ptr =
+ (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_expn_addr;
+
+ tbl_entry -= cache_ptr->table_entries;
+ if (Read16BitFieldValue(tbl_ptr[tbl_entry].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ *rule_pos = IPA_NAT_DEL_TYPE_LAST;
+ }
+ else
+ {
+ *rule_pos = IPA_NAT_DEL_TYPE_MIDDLE;
+ }
+ }
+ else
+ {
+ tbl_ptr =
+ (struct ipa_nat_indx_tbl_rule *)cache_ptr->index_table_addr;
+
+ if (Read16BitFieldValue(tbl_ptr[tbl_entry].tbl_entry_nxt_indx,
+ INDX_TBL_NEXT_INDEX_FILED) == IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ *rule_pos = IPA_NAT_DEL_TYPE_ONLY_ONE;
+ }
+ else
+ {
+ *rule_pos = IPA_NAT_DEL_TYPE_HEAD;
+ }
+ }
+}
+
+void ipa_nati_find_rule_pos(struct ipa_nat_ip4_table_cache *cache_ptr,
+ uint8_t expn_tbl,
+ uint16_t tbl_entry,
+ del_type *rule_pos)
+{
+
+ struct ipa_nat_rule *tbl_ptr;
+
+ if(expn_tbl)
+ {
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_expn_rules_addr;
+ if ( Read16BitFieldValue(tbl_ptr[tbl_entry].nxt_indx_pub_port,
+ NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ *rule_pos = IPA_NAT_DEL_TYPE_LAST;
+ }
+ else
+ {
+ *rule_pos = IPA_NAT_DEL_TYPE_MIDDLE;
+ }
+ }
+ else
+ {
+ tbl_ptr = (struct ipa_nat_rule *)cache_ptr->ipv4_rules_addr;
+ if( Read16BitFieldValue(tbl_ptr[tbl_entry].nxt_indx_pub_port,
+ NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ *rule_pos = IPA_NAT_DEL_TYPE_ONLY_ONE;
+ }
+ else
+ {
+ *rule_pos = IPA_NAT_DEL_TYPE_HEAD;
+ }
+ }
+}
+
+void ipa_nati_del_dead_ipv4_head_nodes(uint8_t tbl_indx)
+{
+ struct ipa_nat_rule *tbl_ptr;
+ uint16_t cnt;
+
+ tbl_ptr =
+ (struct ipa_nat_rule *)ipv4_nat_cache.ip4_tbl[tbl_indx].ipv4_rules_addr;
+
+ for(cnt=0;
+ cnt<ipv4_nat_cache.ip4_tbl[tbl_indx].table_entries;
+ cnt++)
+ {
+
+ if(Read8BitFieldValue(tbl_ptr[cnt].ts_proto,
+ PROTOCOL_FIELD) == IPA_NAT_INVALID_PROTO_FIELD_CMP
+ &&
+ Read16BitFieldValue(tbl_ptr[cnt].nxt_indx_pub_port,
+ NEXT_INDEX_FIELD) == IPA_NAT_INVALID_NAT_ENTRY)
+ {
+ /* Delete the IPA_NAT_DEL_TYPE_HEAD node */
+ IPADBG("deleting the dead node 0x%x\n", cnt);
+ memset(&tbl_ptr[cnt], 0, sizeof(struct ipa_nat_rule));
+ }
+ } /* end of for loop */
+
+ return;
+}
+
+
+/* ========================================================
+ Debug functions
+ ========================================================*/
+#ifdef NAT_DUMP
+void ipa_nat_dump_ipv4_table(uint32_t tbl_hdl)
+{
+ struct ipa_nat_rule *tbl_ptr;
+ struct ipa_nat_indx_tbl_rule *indx_tbl_ptr;
+ int cnt;
+ uint8_t atl_one = 0;
+
+ if (IPA_NAT_INVALID_NAT_ENTRY == tbl_hdl ||
+ tbl_hdl > IPA_NAT_MAX_IP4_TBLS)
+ {
+ IPAERR("invalid table handle passed \n");
+ return;
+ }
+
+ /* Print ipv4 rules */
+ IPADBG("Dumping ipv4 active rules:\n");
+ tbl_ptr = (struct ipa_nat_rule *)
+ ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_rules_addr;
+ for( cnt=0;
+ cnt<ipv4_nat_cache.ip4_tbl[tbl_hdl-1].table_entries;
+ cnt++)
+ {
+ if (Read16BitFieldValue( tbl_ptr[cnt].ip_cksm_enbl,
+ ENABLE_FIELD))
+ {
+ atl_one = 1;
+ ipa_nati_print_rule(&tbl_ptr[cnt], cnt);
+ ipa_nati_dump_rule_buf(&tbl_ptr[cnt],
+ sizeof(struct ipa_nat_rule),
+ cnt);
+ }
+ }
+ if(!atl_one)
+ {
+ IPADBG("No active base rules\n");
+ }
+ atl_one = 0;
+
+ /* Print ipv4 expansion rules */
+ IPADBG("Dumping ipv4 active expansion rules:\n");
+ tbl_ptr = (struct ipa_nat_rule *)
+ ipv4_nat_cache.ip4_tbl[tbl_hdl-1].ipv4_expn_rules_addr;
+ for( cnt=0;
+ cnt<ipv4_nat_cache.ip4_tbl[tbl_hdl-1].expn_table_entries;
+ cnt++)
+ {
+ if (Read16BitFieldValue(tbl_ptr[cnt].ip_cksm_enbl,
+ ENABLE_FIELD))
+ {
+ ipa_nati_print_rule(&tbl_ptr[cnt], cnt);
+ ipa_nati_dump_rule_buf(&tbl_ptr[cnt],
+ sizeof(struct ipa_nat_rule),
+ cnt);
+ }
+ }
+ if(!atl_one)
+ {
+ IPADBG("No active base expansion rules\n");
+ }
+ atl_one = 0;
+
+ /* Print ipv4 index rules */
+ IPADBG("Dumping ipv4 index active rules: \n");
+ indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+ ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_addr;
+ for( cnt=0;
+ cnt<ipv4_nat_cache.ip4_tbl[tbl_hdl-1].table_entries;
+ cnt++)
+ {
+ if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+ INDX_TBL_TBL_ENTRY_FIELD))
+ {
+ ipa_nati_dump_index_rule_buf(&indx_tbl_ptr[cnt],
+ sizeof(struct ipa_nat_indx_tbl_rule),
+ cnt);
+ }
+ }
+ if(!atl_one)
+ {
+ IPADBG("No active index table rules\n");
+ }
+ atl_one = 0;
+
+
+ /* Print ipv4 index expansion rules */
+ IPADBG("Dumping ipv4 index expansion active rules: \n");
+ indx_tbl_ptr = (struct ipa_nat_indx_tbl_rule *)
+ ipv4_nat_cache.ip4_tbl[tbl_hdl-1].index_table_expn_addr;
+ for ( cnt=0;
+ cnt<ipv4_nat_cache.ip4_tbl[tbl_hdl-1].expn_table_entries;
+ cnt++)
+ {
+ if (Read16BitFieldValue(indx_tbl_ptr[cnt].tbl_entry_nxt_indx,
+ INDX_TBL_TBL_ENTRY_FIELD))
+ {
+ ipa_nati_dump_index_rule_buf(&indx_tbl_ptr[cnt],
+ sizeof(struct ipa_nat_indx_tbl_rule),
+ cnt);
+ }
+ }
+ if(!atl_one)
+ {
+ IPADBG("No active index expansion rules\n");
+ }
+ atl_one = 0;
+
+}
+
+
+void ipa_nati_dump_rule_buf(void *param1, uint8_t size, uint32_t rule_id)
+{
+ int cnt = 0;
+ uint8_t temp[IPA_NAT_TABLE_ENTRY_SIZE];
+ uint64_t *rule = NULL;
+
+ memcpy(&temp, param1, sizeof(temp));
+ rule = (uint64_t *)temp;
+
+ IPADBG("Address :%p, rule id: %d size: %d\n",
+ rule, rule_id, size);
+ for(; cnt<size; )
+ {
+ uint8_t *byte = (uint8_t *)rule;
+
+ IPADBG("uint64[%d]: 0x%x:\n", cnt, (unsigned int)rule);
+ IPADBG("%02x\t%02x\t%02x\t%02x\n", byte[0], byte[1], byte[2], byte[3]);
+ IPADBG("%02x\t%02x\t%02x\t%02x\n", byte[4], byte[5], byte[6], byte[7]);
+
+ cnt += 8;
+ rule++;
+ }
+
+ return;
+}
+
+void ipa_nati_dump_index_rule_buf(void *param1, uint8_t size, uint32_t rule_id)
+{
+ int cnt = 0;
+ uint8_t temp[IPA_NAT_INDEX_TABLE_ENTRY_SIZE];
+ uint16_t *rule = NULL;
+
+ memcpy(&temp, param1, sizeof(temp));
+ rule = (uint16_t *)temp;
+
+ IPADBG("Address :%p, rule id: %d size: %d\n",
+ rule, rule_id, size);
+
+ for(; cnt<size; )
+ {
+ uint8_t *byte = (uint8_t *)rule;
+
+ IPADBG("uint64[%d]: 0x%x:\n", cnt, (unsigned int)rule);
+ IPADBG("%02x\t%02x\n", byte[0], byte[1]);
+ IPADBG("\n");
+
+ cnt += 2;
+ rule++;
+ }
+
+ return;
+}
+
+void ipa_nati_print_rule(struct ipa_nat_rule *param, uint32_t rule_id)
+{
+ struct ipa_nat_sw_rule sw_rule;
+ memcpy(&sw_rule, param, sizeof(sw_rule));
+
+ IPADBG("Printing NAT Rule:%d at memory location:%p\n", rule_id, param);
+
+ IPADBG("Target IP: 0x%x Target Port: 0x%x\n",
+ sw_rule.target_ip, sw_rule.target_port);
+
+ IPADBG("Private IP: 0x%x Private Port: 0x%x\n",
+ sw_rule.private_ip, sw_rule.private_port);
+
+ IPADBG("Public Port: 0x%x Next index: 0x%x\n",
+ sw_rule.public_port, sw_rule.next_index);
+
+ IPADBG("IP ChkSum: 0x%x Enable bit: 0x%x\n",
+ sw_rule.ip_chksum, sw_rule.enable);
+
+ IPADBG("Time Stamp: 0x%x Protocol: 0x%x\n",
+ sw_rule.time_stamp, sw_rule.protocol);
+
+ IPADBG("Prev Index: 0x%x Next Index: 0x%x\n",
+ sw_rule.prev_index, sw_rule.next_index);
+
+ IPADBG("TCP UDP Chksum: 0x%x\n", sw_rule.tcp_udp_chksum);
+
+ return;
+}
+#endif
diff --git a/ipanat/src/ipa_nat_logi.c b/ipanat/src/ipa_nat_logi.c
new file mode 100644
index 0000000..11991c9
--- /dev/null
+++ b/ipanat/src/ipa_nat_logi.c
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*!
+ @file
+ IPACM_log.cpp
+
+ @brief
+ This file implements the IPAM log functionality.
+
+ @Author
+ Skylar Chang
+
+*/
+#include "ipa_nat_logi.h"
+#include <stdlib.h>
+
+#define NAT_FILE_NAME "/usr/ipanat_log.txt"
+
+static FILE *nat_fp = NULL;
+char nat_log_buf[NAT_LOG_SIZE];
+
+void log_nat_message(char *msg)
+{
+ printf("%s", msg);
+#if 0
+ if(nat_fp == NULL)
+ {
+ nat_fp = fopen(NAT_FILE_NAME, "wb+");
+ if(nat_fp == NULL)
+ {
+ printf("unable to open file\n");
+ return;
+ }
+ }
+
+ fprintf(nat_fp, msg);
+ fflush(nat_fp);
+#endif
+ return;
+}
+
+