diff options
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 *)¶m; + + 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 *)¶m; + + 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 *)¶m; + + 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; +} + + |