aboutsummaryrefslogtreecommitdiff
path: root/data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp
diff options
context:
space:
mode:
authorFedor917 <cryscript@gmail.com>2016-10-26 00:02:15 +0700
committerFedor917 <cryscript@gmail.com>2016-10-26 00:02:15 +0700
commit4a6f194ca90f6975820d22008fd93af691957cef (patch)
treea88ccfadec9c524a6f5404a2a9ad52dd42c9f563 /data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp
parent514fff9c46d0e960ce1f57d6d38de6a15f6501f4 (diff)
Initial commit
Diffstat (limited to 'data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp')
-rw-r--r--data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp1773
1 files changed, 1773 insertions, 0 deletions
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp
new file mode 100644
index 0000000..30295b1
--- /dev/null
+++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_Netlink.cpp
@@ -0,0 +1,1773 @@
+/*
+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"
+
+int ipa_get_if_name(char *if_name, int if_index);
+int find_mask(int ip_v4_last, int *mask_value);
+
+#ifdef FEATURE_IPA_ANDROID
+
+#define IPACM_NL_COPY_ADDR( event_info, element ) \
+ memcpy( &event_info->attr_info.element.__data, \
+ RTA_DATA(rtah), \
+ sizeof(event_info->attr_info.element.__data) );
+
+#define IPACM_EVENT_COPY_ADDR_v6( event_data, element) \
+ memcpy( event_data, element.__data, sizeof(event_data));
+
+#define IPACM_EVENT_COPY_ADDR_v4( event_data, element) \
+ memcpy( &event_data, element.__data, sizeof(event_data));
+
+#define IPACM_NL_REPORT_ADDR( prefix, addr ) \
+ if( AF_INET6 == (addr).ss_family ) { \
+ IPACM_LOG_IPV6_ADDR( prefix, addr.__data); \
+ } else { \
+ IPACM_LOG_IPV4_ADDR( prefix, (*(unsigned int*)&(addr).__data) ); \
+ }
+
+#else/* defined(FEATURE_IPA_ANDROID) */
+
+#define IPACM_NL_COPY_ADDR( event_info, element ) \
+ memcpy( &event_info->attr_info.element.__ss_padding, \
+ RTA_DATA(rtah), \
+ sizeof(event_info->attr_info.element.__ss_padding) );
+
+#define IPACM_EVENT_COPY_ADDR_v6( event_data, element) \
+ memcpy( event_data, element.__ss_padding, sizeof(event_data));
+
+#define IPACM_EVENT_COPY_ADDR_v4( event_data, element) \
+ memcpy( &event_data, element.__ss_padding, sizeof(event_data));
+
+#define IPACM_NL_REPORT_ADDR( prefix, addr ) \
+ if( AF_INET6 == (addr).ss_family ) { \
+ IPACM_LOG_IPV6_ADDR( prefix, addr.__ss_padding); \
+ } else { \
+ IPACM_LOG_IPV4_ADDR( prefix, (*(unsigned int*)&(addr).__ss_padding) ); \
+ }
+#endif /* defined(FEATURE_IPA_ANDROID)*/
+
+#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
+#define IPACM_LOG_IPV6_ADDR(prefix, ip_addr) \
+ IPACMDBG_H(prefix); \
+ IPACMDBG_H(" IPV6 Address %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", \
+ (int)ip_addr[0], (int)ip_addr[1], \
+ (int)ip_addr[2], (int)ip_addr[3], \
+ (int)ip_addr[4], (int)ip_addr[5], \
+ (int)ip_addr[6], (int)ip_addr[7], \
+ (int)ip_addr[8], (int)ip_addr[9], \
+ (int)ip_addr[10], (int)ip_addr[11], \
+ (int)ip_addr[12], (int)ip_addr[13], \
+ (int)ip_addr[14], (int)ip_addr[15]);
+
+#define IPACM_LOG_IPV4_ADDR(prefix, ip_addr) \
+ IPACMDBG_H(prefix); \
+ IPACMDBG_H(" IPV4 Address %d.%d.%d.%d\n", \
+ (unsigned char)(ip_addr), \
+ (unsigned char)(ip_addr >> 8), \
+ (unsigned char)(ip_addr >> 16) , \
+ (unsigned char)(ip_addr >> 24));
+
+/* Opens a netlink socket*/
+static int ipa_nl_open_socket
+(
+ ipa_nl_sk_info_t *sk_info,
+ int protocol,
+ unsigned int grps
+ )
+{
+ int *p_sk_fd;
+ int buf_size = 6669999, sendbuff=0, res;
+ struct sockaddr_nl *p_sk_addr_loc;
+ socklen_t optlen;
+
+ p_sk_fd = &(sk_info->sk_fd);
+ p_sk_addr_loc = &(sk_info->sk_addr_loc);
+
+ /* Open netlink socket for specified protocol */
+ if((*p_sk_fd = socket(AF_NETLINK, SOCK_RAW, protocol)) < 0)
+ {
+ IPACMERR("cannot open netlink socket\n");
+ return IPACM_FAILURE;
+ }
+
+ optlen = sizeof(sendbuff);
+ res = getsockopt(*p_sk_fd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);
+
+ if(res == -1) {
+ IPACMDBG("Error getsockopt one");
+ } else {
+ IPACMDBG("orignal send buffer size = %d\n", sendbuff);
+ }
+ IPACMDBG("sets the send buffer to %d\n", buf_size);
+ if (setsockopt(*p_sk_fd, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(int)) == -1) {
+ IPACMERR("Error setting socket opts\n");
+ }
+
+ /* Initialize socket addresses to null */
+ memset(p_sk_addr_loc, 0, sizeof(struct sockaddr_nl));
+
+ /* Populate local socket address using specified groups */
+ p_sk_addr_loc->nl_family = AF_NETLINK;
+ p_sk_addr_loc->nl_pid = getpid();
+ p_sk_addr_loc->nl_groups = grps;
+
+ /* Bind socket to the local address, i.e. specified groups. This ensures
+ that multicast messages for these groups are delivered over this
+ socket. */
+
+ if(bind(*p_sk_fd,
+ (struct sockaddr *)p_sk_addr_loc,
+ sizeof(struct sockaddr_nl)) < 0)
+ {
+ IPACMERR("Socket bind failed\n");
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Add fd to fdmap array and store read handler function ptr (up to MAX_NUM_OF_FD).*/
+static int ipa_nl_addfd_map
+(
+ ipa_nl_sk_fd_set_info_t *info,
+ int fd,
+ ipa_sock_thrd_fd_read_f read_f
+ )
+{
+ if(info->num_fd < MAX_NUM_OF_FD)
+ {
+ FD_SET(fd, &info->fdset);
+
+ /* Add fd to fdmap array and store read handler function ptr */
+ info->sk_fds[info->num_fd].sk_fd = fd;
+ info->sk_fds[info->num_fd].read_func = read_f;
+
+ /* Increment number of fds stored in fdmap */
+ info->num_fd++;
+ if(info->max_fd < fd)
+ info->max_fd = fd;
+ }
+ else
+ {
+ return IPACM_FAILURE;
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* start socket listener */
+static int ipa_nl_sock_listener_start
+(
+ ipa_nl_sk_fd_set_info_t *sk_fd_set
+ )
+{
+ int i, ret;
+
+ while(true)
+ {
+ for(i = 0; i < sk_fd_set->num_fd; i++ )
+ {
+ FD_SET(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset));
+ }
+
+ if((ret = select(sk_fd_set->max_fd + 1, &(sk_fd_set->fdset), NULL, NULL, NULL)) < 0)
+ {
+ IPACMERR("ipa_nl select failed\n");
+ }
+ else
+ {
+ for(i = 0; i < sk_fd_set->num_fd; i++)
+ {
+
+ if(FD_ISSET(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset)))
+ {
+
+ if(sk_fd_set->sk_fds[i].read_func)
+ {
+ if(IPACM_SUCCESS != ((sk_fd_set->sk_fds[i].read_func)(sk_fd_set->sk_fds[i].sk_fd)))
+ {
+ IPACMERR("Error on read callback[%d] fd=%d\n",
+ i,
+ sk_fd_set->sk_fds[i].sk_fd);
+ }
+ FD_CLR(sk_fd_set->sk_fds[i].sk_fd, &(sk_fd_set->fdset));
+ }
+ else
+ {
+ IPACMERR("No read function\n");
+ }
+ }
+
+ } /* end of for loop*/
+ } /* end of else */
+ } /* end of while */
+
+ return IPACM_SUCCESS;
+}
+
+/* allocate memory for ipa_nl__msg */
+static struct msghdr* ipa_nl_alloc_msg
+(
+ uint32_t msglen
+ )
+{
+ unsigned char *buf = NULL;
+ struct sockaddr_nl *nladdr = NULL;
+ struct iovec *iov = NULL;
+ struct msghdr *msgh = NULL;
+
+ if(IPA_NL_MSG_MAX_LEN < msglen)
+ {
+ IPACMERR("Netlink message exceeds maximum length\n");
+ return NULL;
+ }
+
+ msgh = (struct msghdr *)malloc(sizeof(struct msghdr));
+ if(msgh == NULL)
+ {
+ IPACMERR("Failed malloc for msghdr\n");
+ return NULL;
+ }
+
+ nladdr = (struct sockaddr_nl *)malloc(sizeof(struct sockaddr_nl));
+ if(nladdr == NULL)
+ {
+ IPACMERR("Failed malloc for sockaddr\n");
+ free(msgh);
+ return NULL;
+ }
+
+ iov = (struct iovec *)malloc(sizeof(struct iovec));
+ if(iov == NULL)
+ {
+ PERROR("Failed malloc for iovec");
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ buf = (unsigned char *)malloc(msglen);
+ if(buf == NULL)
+ {
+ IPACMERR("Failed malloc for mglen\n");
+ free(iov);
+ free(nladdr);
+ free(msgh);
+ return NULL;
+ }
+
+ memset(nladdr, 0, sizeof(struct sockaddr_nl));
+ nladdr->nl_family = AF_NETLINK;
+
+ memset(msgh, 0x0, sizeof(struct msghdr));
+ msgh->msg_name = nladdr;
+ msgh->msg_namelen = sizeof(struct sockaddr_nl);
+ msgh->msg_iov = iov;
+ msgh->msg_iovlen = 1;
+
+ memset(iov, 0x0, sizeof(struct iovec));
+ iov->iov_base = buf;
+ iov->iov_len = msglen;
+
+ return msgh;
+}
+
+/* release IPA message */
+static void ipa_nl_release_msg
+(
+ struct msghdr *msgh
+ )
+{
+ unsigned char *buf = NULL;
+ struct sockaddr_nl *nladdr = NULL;
+ struct iovec *iov = NULL;
+
+ if(NULL == msgh)
+ {
+ return;
+ }
+
+ nladdr = (struct sockaddr_nl *)msgh->msg_name;
+ iov = msgh->msg_iov;
+ if(msgh->msg_iov)
+ {
+ buf = (unsigned char *)msgh->msg_iov->iov_base;
+ }
+
+ if(buf)
+ {
+ free(buf);
+ }
+ if(iov)
+ {
+ free(iov);
+ }
+ if(nladdr)
+ {
+ free(nladdr);
+ }
+ if(msgh)
+ {
+ free(msgh);
+ }
+ return;
+}
+
+/* receive and process nl message */
+static int ipa_nl_recv
+(
+ int fd,
+ struct msghdr **msg_pptr,
+ unsigned int *msglen_ptr
+ )
+{
+ struct msghdr *msgh = NULL;
+ int rmsgl;
+
+ msgh = ipa_nl_alloc_msg(IPA_NL_MSG_MAX_LEN);
+ if(NULL == msgh)
+ {
+ IPACMERR("Failed to allocate NL message\n");
+ goto error;
+ }
+
+
+ /* Receive message over the socket */
+ rmsgl = recvmsg(fd, msgh, 0);
+
+ /* Verify that something was read */
+ if(rmsgl <= 0)
+ {
+ PERROR("NL recv error");
+ goto error;
+ }
+
+ /* Verify that NL address length in the received message is expected value */
+ if(sizeof(struct sockaddr_nl) != msgh->msg_namelen)
+ {
+ IPACMERR("rcvd msg with namelen != sizeof sockaddr_nl\n");
+ goto error;
+ }
+
+ /* Verify that message was not truncated. This should not occur */
+ if(msgh->msg_flags & MSG_TRUNC)
+ {
+ IPACMERR("Rcvd msg truncated!\n");
+ goto error;
+ }
+
+ *msg_pptr = msgh;
+ *msglen_ptr = rmsgl;
+
+ return IPACM_SUCCESS;
+
+/* An error occurred while receiving the message. Free all memory before
+ returning. */
+error:
+ ipa_nl_release_msg(msgh);
+ *msg_pptr = NULL;
+ *msglen_ptr = 0;
+
+ return IPACM_FAILURE;
+}
+
+/* decode the rtm netlink message */
+static int ipa_nl_decode_rtm_link
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_link_info_t *link_info
+)
+{
+ struct rtattr;
+ /* NL message header */
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;
+
+ /* Extract the header data */
+ link_info->metainfo = *(struct ifinfomsg *)NLMSG_DATA(nlh);
+ buflen -= sizeof(struct nlmsghdr);
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel address message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_addr
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_addr_info_t *addr_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ addr_info->metainfo = *((struct ifaddrmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ /* Extract the available attributes */
+ addr_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+ rtah = IFA_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case IFA_ADDRESS:
+ addr_info->attr_info.prefix_addr.ss_family = addr_info->metainfo.ifa_family;
+ IPACM_NL_COPY_ADDR( addr_info, prefix_addr );
+ addr_info->attr_info.param_mask |= IPA_NLA_PARAM_PREFIXADDR;
+ break;
+ default:
+ break;
+
+ }
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel neighbor message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_neigh
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_neigh_info_t *neigh_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ neigh_info->metainfo = *((struct ndmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ /* Extract the available attributes */
+ neigh_info->attr_info.param_mask = IPA_NLA_PARAM_NONE;
+
+ rtah = NDA_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case NDA_DST:
+ neigh_info->attr_info.local_addr.ss_family = neigh_info->metainfo.ndm_family;
+ IPACM_NL_COPY_ADDR( neigh_info, local_addr );
+ break;
+
+ case NDA_LLADDR:
+ memcpy(neigh_info->attr_info.lladdr_hwaddr.sa_data,
+ RTA_DATA(rtah),
+ sizeof(neigh_info->attr_info.lladdr_hwaddr.sa_data));
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* Decode kernel route message parameters from Netlink attribute TLVs. */
+static int ipa_nl_decode_rtm_route
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_route_info_t *route_info
+ )
+{
+ struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; /* NL message header */
+ struct rtattr *rtah = NULL;
+
+ /* Extract the header data */
+ route_info->metainfo = *((struct rtmsg *)NLMSG_DATA(nlh));
+ buflen -= sizeof(struct nlmsghdr);
+
+ route_info->attr_info.param_mask = IPA_RTA_PARAM_NONE;
+ rtah = RTM_RTA(NLMSG_DATA(nlh));
+
+ while(RTA_OK(rtah, buflen))
+ {
+ switch(rtah->rta_type)
+ {
+
+ case RTA_DST:
+ route_info->attr_info.dst_addr.ss_family = route_info->metainfo.rtm_family;
+ IPACM_NL_COPY_ADDR( route_info, dst_addr );
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_DST;
+ break;
+
+ case RTA_SRC:
+ route_info->attr_info.src_addr.ss_family = route_info->metainfo.rtm_family;
+ IPACM_NL_COPY_ADDR( route_info, src_addr );
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_SRC;
+ break;
+
+ case RTA_GATEWAY:
+ route_info->attr_info.gateway_addr.ss_family = route_info->metainfo.rtm_family;
+ IPACM_NL_COPY_ADDR( route_info, gateway_addr );
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_GATEWAY;
+ break;
+
+ case RTA_IIF:
+ memcpy(&route_info->attr_info.iif_index,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.iif_index));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_IIF;
+ break;
+
+ case RTA_OIF:
+ memcpy(&route_info->attr_info.oif_index,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.oif_index));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_OIF;
+ break;
+
+ case RTA_PRIORITY:
+ memcpy(&route_info->attr_info.priority,
+ RTA_DATA(rtah),
+ sizeof(route_info->attr_info.priority));
+ route_info->attr_info.param_mask |= IPA_RTA_PARAM_PRIORITY;
+ break;
+
+ default:
+ break;
+
+ }
+
+ /* Advance to next attribute */
+ rtah = RTA_NEXT(rtah, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* decode the ipa nl-message */
+static int ipa_nl_decode_nlmsg
+(
+ const char *buffer,
+ unsigned int buflen,
+ ipa_nl_msg_t *msg_ptr
+ )
+{
+ char dev_name[IF_NAME_LEN]={0};
+ int ret_val, mask_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, if_ipv4_addr_gw =0;
+
+ ipacm_cmd_q_data evt_data;
+ ipacm_event_data_all *data_all;
+ ipacm_event_data_fid *data_fid;
+ ipacm_event_data_addr *data_addr;
+
+
+ while(NLMSG_OK(nlh, buflen))
+ {
+ memset(dev_name,0,IF_NAME_LEN);
+ IPACMDBG("Received msg:%d from netlink\n", nlh->nlmsg_type)
+ switch(nlh->nlmsg_type)
+ {
+ case RTM_NEWLINK:
+ msg_ptr->type = nlh->nlmsg_type;
+ msg_ptr->link_event = true;
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+ {
+ IPACMERR("Failed to decode rtm link message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("Got RTM_NEWLINK with below values\n");
+ IPACMDBG("RTM_NEWLINK, ifi_change:%d\n", msg_ptr->nl_link_info.metainfo.ifi_change);
+ IPACMDBG("RTM_NEWLINK, ifi_flags:%d\n", msg_ptr->nl_link_info.metainfo.ifi_flags);
+ IPACMDBG("RTM_NEWLINK, ifi_index:%d\n", msg_ptr->nl_link_info.metainfo.ifi_index);
+ IPACMDBG("RTM_NEWLINK, family:%d\n", msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* RTM_NEWLINK event with AF_BRIDGE family should be ignored in Android
+ but this should be processed in case of MDM for Ehernet interface.
+ */
+#ifdef FEATURE_IPA_ANDROID
+ if (msg_ptr->nl_link_info.metainfo.ifi_family == AF_BRIDGE)
+ {
+ IPACMERR(" ignore this RTM_NEWLINK msg \n");
+ return IPACM_SUCCESS;
+ }
+#endif
+ if(IFF_UP & msg_ptr->nl_link_info.metainfo.ifi_change)
+ {
+ IPACMDBG("GOT useful newlink event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ if(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_UP)
+ {
+ IPACMDBG_H("Interface %s bring up with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* post link up to command queue */
+ evt_data.event = IPA_LINK_UP_EVENT;
+ IPACMDBG_H("Posting IPA_LINK_UP_EVENT with if index: %d\n",
+ msg_ptr->nl_link_info.metainfo.ifi_index);
+ }
+ else
+ {
+ IPACMDBG_H("Interface %s bring down with IP-family: %d \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* post link down to command queue */
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ IPACMDBG_H("Posting IPA_LINK_DOWN_EVENT with if index: %d\n",
+ data_fid->if_index);
+ }
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+
+ /* Add IPACM support for ECM plug-in/plug_out */
+ /*--------------------------------------------------------------------------
+ Check if the interface is running.If its a RTM_NEWLINK and the interface
+ is running then it means that its a link up event
+ ---------------------------------------------------------------------------*/
+ if((msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_RUNNING) &&
+ (msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_LOWER_UP))
+ {
+
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Got a usb link_up event (Interface %s, %d) \n", dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+
+ /*--------------------------------------------------------------------------
+ Post LAN iface (ECM) link up event
+ ---------------------------------------------------------------------------*/
+ evt_data.event = IPA_USB_LINK_UP_EVENT;
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG_H("Posting usb IPA_LINK_UP_EVENT with if index: %d\n",
+ data_fid->if_index);
+ }
+ else if(!(msg_ptr->nl_link_info.metainfo.ifi_flags & IFF_LOWER_UP))
+ {
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG_H("Got a usb link_down event (Interface %s) \n", dev_name);
+
+ /*--------------------------------------------------------------------------
+ Post LAN iface (ECM) link down event
+ ---------------------------------------------------------------------------*/
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ IPACMDBG_H("Posting usb IPA_LINK_DOWN_EVENT with if index: %d\n",
+ data_fid->if_index);
+ }
+ }
+ break;
+
+ case RTM_DELLINK:
+ IPACMDBG("\n GOT dellink event\n");
+ msg_ptr->type = nlh->nlmsg_type;
+ msg_ptr->link_event = true;
+ IPACMDBG("entering rtm decode\n");
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_link(buffer, buflen, &(msg_ptr->nl_link_info)))
+ {
+ IPACMERR("Failed to decode rtm link message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("Got RTM_DELLINK with below values\n");
+ IPACMDBG("RTM_DELLINK, ifi_change:%d\n", msg_ptr->nl_link_info.metainfo.ifi_change);
+ IPACMDBG("RTM_DELLINK, ifi_flags:%d\n", msg_ptr->nl_link_info.metainfo.ifi_flags);
+ IPACMDBG("RTM_DELLINK, ifi_index:%d\n", msg_ptr->nl_link_info.metainfo.ifi_index);
+ IPACMDBG("RTM_DELLINK, family:%d\n", msg_ptr->nl_link_info.metainfo.ifi_family);
+ /* RTM_NEWLINK event with AF_BRIDGE family should be ignored in Android
+ but this should be processed in case of MDM for Ehernet interface.
+ */
+#ifdef FEATURE_IPA_ANDROID
+ if (msg_ptr->nl_link_info.metainfo.ifi_family == AF_BRIDGE)
+ {
+ IPACMERR(" ignore this RTM_DELLINK msg \n");
+ return IPACM_SUCCESS;
+ }
+#endif
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_link_info.metainfo.ifi_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Interface %s bring down \n", dev_name);
+
+ /* post link down to command queue */
+ evt_data.event = IPA_LINK_DOWN_EVENT;
+ data_fid = (ipacm_event_data_fid *)malloc(sizeof(ipacm_event_data_fid));
+ if(data_fid == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_fid\n");
+ return IPACM_FAILURE;
+ }
+
+ data_fid->if_index = msg_ptr->nl_link_info.metainfo.ifi_index;
+
+ IPACMDBG_H("posting IPA_LINK_DOWN_EVENT with if idnex:%d\n",
+ data_fid->if_index);
+ evt_data.evt_data = data_fid;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ break;
+
+ case RTM_NEWADDR:
+ IPACMDBG("\n GOT RTM_NEWADDR event\n");
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_addr(buffer, buflen, &(msg_ptr->nl_addr_info)))
+ {
+ IPACMERR("Failed to decode rtm addr message\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_addr_info.metainfo.ifa_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ }
+ IPACMDBG("Interface %s \n", dev_name);
+
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_addr_info.attr_info.prefix_addr.ss_family)
+ {
+ data_addr->iptype = IPA_IP_v6;
+ IPACM_NL_REPORT_ADDR( "IFA_ADDRESS:", msg_ptr->nl_addr_info.attr_info.prefix_addr );
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_addr_info.attr_info.prefix_addr);
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+ }
+ else
+ {
+ data_addr->iptype = IPA_IP_v4;
+ IPACM_NL_REPORT_ADDR( "IFA_ADDRESS:", msg_ptr->nl_addr_info.attr_info.prefix_addr );
+ IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr, msg_ptr->nl_addr_info.attr_info.prefix_addr);
+ data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+ }
+
+ evt_data.event = IPA_ADDR_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_addr_info.metainfo.ifa_index;
+ if(AF_INET6 == msg_ptr->nl_addr_info.attr_info.prefix_addr.ss_family)
+ {
+ IPACMDBG("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv6 addr:0x%x:%x:%x:%x\n",
+ data_addr->if_index,
+ data_addr->ipv6_addr[0],
+ data_addr->ipv6_addr[1],
+ data_addr->ipv6_addr[2],
+ data_addr->ipv6_addr[3]);
+ }
+ else
+ {
+ IPACMDBG("Posting IPA_ADDR_ADD_EVENT with if index:%d, ipv4 addr:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr);
+ }
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ }
+ break;
+
+ case RTM_NEWROUTE:
+
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+ {
+ IPACMERR("Failed to decode rtm route message\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG("In case RTM_NEWROUTE\n");
+ IPACMDBG("rtm_type: %d\n", msg_ptr->nl_route_info.metainfo.rtm_type);
+ IPACMDBG("protocol: %d\n", msg_ptr->nl_route_info.metainfo.rtm_protocol);
+ IPACMDBG("rtm_scope: %d\n", msg_ptr->nl_route_info.metainfo.rtm_scope);
+ IPACMDBG("rtm_table: %d\n", msg_ptr->nl_route_info.metainfo.rtm_table);
+ IPACMDBG("rtm_family: %d\n", msg_ptr->nl_route_info.metainfo.rtm_family);
+ IPACMDBG("param_mask: 0x%x\n", msg_ptr->nl_route_info.attr_info.param_mask);
+
+ /* take care of route add default route & uniroute */
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ ((msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) ||
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_RA)) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_scope == RT_SCOPE_UNIVERSE) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT RTM_NEWROUTE event\n");
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACM_NL_REPORT_ADDR( "route add -host", msg_ptr->nl_route_info.attr_info.dst_addr );
+ IPACM_NL_REPORT_ADDR( "gw", msg_ptr->nl_route_info.attr_info.gateway_addr );
+ IPACMDBG("dev %s\n",dev_name );
+ /* insert to command queue */
+ IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ temp = (-1);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+ {
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG_H("ip -6 route add default dev %s metric %d\n",
+ dev_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG_H("ip -6 route add default dev %s\n", dev_name);
+ }
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+ data_addr->ipv6_addr_gw[0] = ntohl(data_addr->ipv6_addr_gw[0]);
+ data_addr->ipv6_addr_gw[1] = ntohl(data_addr->ipv6_addr_gw[1]);
+ data_addr->ipv6_addr_gw[2] = ntohl(data_addr->ipv6_addr_gw[2]);
+ data_addr->ipv6_addr_gw[3] = ntohl(data_addr->ipv6_addr_gw[3]);
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+
+ }
+ else
+ {
+ IPACM_NL_REPORT_ADDR( "route add default gw \n", msg_ptr->nl_route_info.attr_info.gateway_addr );
+ IPACMDBG_H("dev %s \n", dev_name);
+ IPACM_NL_REPORT_ADDR( "dstIP:", msg_ptr->nl_route_info.attr_info.dst_addr );
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ IPACM_EVENT_COPY_ADDR_v4( if_ipipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+ IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_gw = ntohl(if_ipv4_addr_gw);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG_H("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv4 addr:0x%x, mask: 0x%x and gw: 0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask,
+ data_addr->ipv4_addr_gw);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+ }
+
+ /* ipv6 routing table */
+ if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT valid v6-RTM_NEWROUTE event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACM_NL_REPORT_ADDR( "Route ADD DST:", msg_ptr->nl_route_info.attr_info.dst_addr );
+ IPACMDBG("%d, metric %d, dev %s\n",
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+ mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+ for(mask_index = 0; mask_index < 4; mask_index++)
+ {
+ if(mask_value_v6 >= 32)
+ {
+ mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 -= 32;
+ }
+ else
+ {
+ mask_v6(mask_value_v6, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 = 0;
+ }
+ }
+
+ IPACMDBG("ADD IPV6 MASK %d: %08x:%08x:%08x:%08x \n",
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ data_addr->ipv6_addr_mask[0],
+ data_addr->ipv6_addr_mask[1],
+ data_addr->ipv6_addr_mask[2],
+ data_addr->ipv6_addr_mask[3]);
+
+ data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("Posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 addr\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_GATEWAY)
+ {
+ IPACM_NL_REPORT_ADDR( "Route ADD ::/0 Next Hop:", msg_ptr->nl_route_info.attr_info.gateway_addr );
+ IPACMDBG(" metric %d, dev %s\n",
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+ data_addr->ipv6_addr[0]=ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1]=ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2]=ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3]=ntohl(data_addr->ipv6_addr[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+ data_addr->ipv6_addr_mask[0]=ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1]=ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2]=ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3]=ntohl(data_addr->ipv6_addr_mask[3]);
+
+ evt_data.event = IPA_ROUTE_ADD_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG("posting IPA_ROUTE_ADD_EVENT with if index:%d, ipv6 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+ break;
+
+ case RTM_DELROUTE:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_route(buffer, buflen, &(msg_ptr->nl_route_info)))
+ {
+ IPACMERR("Failed to decode rtm route message\n");
+ return IPACM_FAILURE;
+ }
+ /* take care of route delete of default route & uniroute */
+ if((msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ ((msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_BOOT) ||
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_RA)) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_scope == 0) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+ IPACM_NL_REPORT_ADDR( "route del -host ", msg_ptr->nl_route_info.attr_info.dst_addr);
+ IPACM_NL_REPORT_ADDR( " gw ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+ IPACMDBG("dev %s\n", dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+ IPACM_EVENT_COPY_ADDR_v4( if_ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ temp = (-1);
+ if_ipipv4_addr_mask = ntohl(temp);
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v4;
+ data_addr->ipv4_addr = ntohl(if_ipv4_addr);
+ data_addr->ipv4_addr_mask = ntohl(if_ipipv4_addr_mask);
+
+ IPACMDBG_H("Posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address 0x%x, mask:0x%x\n",
+ data_addr->if_index,
+ data_addr->ipv4_addr,
+ data_addr->ipv4_addr_mask);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ else
+ {
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name\n");
+ return IPACM_FAILURE;
+ }
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ if(AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family)
+ {
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_PRIORITY)
+ {
+ IPACMDBG("ip -6 route del default dev %s metric %d\n",
+ dev_name,
+ msg_ptr->nl_route_info.attr_info.priority);
+ }
+ else
+ {
+ IPACMDBG("ip -6 route del default dev %s\n", dev_name);
+ }
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr_gw, msg_ptr->nl_route_info.attr_info.gateway_addr);
+ data_addr->ipv6_addr_gw[0] = ntohl(data_addr->ipv6_addr_gw[0]);
+ data_addr->ipv6_addr_gw[1] = ntohl(data_addr->ipv6_addr_gw[1]);
+ data_addr->ipv6_addr_gw[2] = ntohl(data_addr->ipv6_addr_gw[2]);
+ data_addr->ipv6_addr_gw[3] = ntohl(data_addr->ipv6_addr_gw[3]);
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_route_info.attr_info.gateway_addr);
+ data_addr->iptype = IPA_IP_v6;
+ }
+ else
+ {
+ IPACM_NL_REPORT_ADDR( "route del default gw", msg_ptr->nl_route_info.attr_info.gateway_addr);
+ IPACMDBG("dev %s\n", dev_name);
+
+ IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv4_addr = ntohl(data_addr->ipv4_addr);
+
+ IPACM_EVENT_COPY_ADDR_v4( data_addr->ipv4_addr_mask, msg_ptr->nl_route_info.attr_info.dst_addr);
+ data_addr->ipv4_addr_mask = ntohl(data_addr->ipv4_addr_mask);
+
+ data_addr->iptype = IPA_IP_v4;
+ }
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+
+ IPACMDBG_H("Posting IPA_ROUTE_DEL_EVENT with if index:%d\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+
+ /* ipv6 routing table */
+ if((AF_INET6 == msg_ptr->nl_route_info.metainfo.rtm_family) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_type == RTN_UNICAST) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_protocol == RTPROT_KERNEL) &&
+ (msg_ptr->nl_route_info.metainfo.rtm_table == RT_TABLE_MAIN))
+ {
+ IPACMDBG("\n GOT valid v6-RTM_DELROUTE event\n");
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_route_info.attr_info.oif_index);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface name");
+ return IPACM_FAILURE;
+ }
+
+ if(msg_ptr->nl_route_info.attr_info.param_mask & IPA_RTA_PARAM_DST)
+ {
+ IPACM_NL_REPORT_ADDR( "DEL", msg_ptr->nl_route_info.attr_info.dst_addr);
+ IPACMDBG("/%d, metric %d, dev %s\n",
+ msg_ptr->nl_route_info.metainfo.rtm_dst_len,
+ msg_ptr->nl_route_info.attr_info.priority,
+ dev_name);
+
+ /* insert to command queue */
+ data_addr = (ipacm_event_data_addr *)malloc(sizeof(ipacm_event_data_addr));
+ if(data_addr == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_addr\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACM_EVENT_COPY_ADDR_v6( data_addr->ipv6_addr, msg_ptr->nl_route_info.attr_info.dst_addr);
+
+ data_addr->ipv6_addr[0] = ntohl(data_addr->ipv6_addr[0]);
+ data_addr->ipv6_addr[1] = ntohl(data_addr->ipv6_addr[1]);
+ data_addr->ipv6_addr[2] = ntohl(data_addr->ipv6_addr[2]);
+ data_addr->ipv6_addr[3] = ntohl(data_addr->ipv6_addr[3]);
+
+ mask_value_v6 = msg_ptr->nl_route_info.metainfo.rtm_dst_len;
+ for(mask_index = 0; mask_index < 4; mask_index++)
+ {
+ IPACMDBG("%dst %d \n",
+ mask_index,
+ mask_value_v6);
+ if(mask_value_v6 >= 32)
+ {
+ mask_v6(32, &data_addr->ipv6_addr_mask[mask_index]);
+ mask_value_v6 -= 32;
+ IPACMDBG("%dst: %08x \n",
+ mask_index,
+ data_addr->ipv6_addr_mask[mask_index]);
+ }
+ else
+ {
+ mask_v6(mask_value_v6, data_addr->ipv6_addr_mask);
+ mask_value_v6 = 0;
+ IPACMDBG("%dst: %08x \n",
+ mask_index,
+ data_addr->ipv6_addr_mask[mask_index]);
+ }
+ }
+
+ IPACMDBG("DEL IPV6 MASK 0st: %08x ",
+ data_addr->ipv6_addr_mask[0]);
+ IPACMDBG("1st: %08x ",
+ data_addr->ipv6_addr_mask[1]);
+ IPACMDBG("2st: %08x ",
+ data_addr->ipv6_addr_mask[2]);
+ IPACMDBG("3st: %08x \n",
+ data_addr->ipv6_addr_mask[3]);
+
+ data_addr->ipv6_addr_mask[0] = ntohl(data_addr->ipv6_addr_mask[0]);
+ data_addr->ipv6_addr_mask[1] = ntohl(data_addr->ipv6_addr_mask[1]);
+ data_addr->ipv6_addr_mask[2] = ntohl(data_addr->ipv6_addr_mask[2]);
+ data_addr->ipv6_addr_mask[3] = ntohl(data_addr->ipv6_addr_mask[3]);
+
+ evt_data.event = IPA_ROUTE_DEL_EVENT;
+ data_addr->if_index = msg_ptr->nl_route_info.attr_info.oif_index;
+ data_addr->iptype = IPA_IP_v6;
+
+ IPACMDBG_H("posting event IPA_ROUTE_DEL_EVENT with if index:%d, ipv4 address\n",
+ data_addr->if_index);
+ evt_data.evt_data = data_addr;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ }
+ }
+ break;
+
+ case RTM_NEWNEIGH:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+ {
+ IPACMERR("Failed to decode rtm neighbor message\n");
+ return IPACM_FAILURE;
+ }
+
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface index\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("\n GOT RTM_NEWNEIGH event (%s) ip %d\n",dev_name,msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+ }
+
+ /* insert to command queue */
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if(data_all == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_all\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(data_all, 0, sizeof(ipacm_event_data_all));
+ if(msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET6)
+ {
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+ IPACM_EVENT_COPY_ADDR_v6( data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+
+ data_all->ipv6_addr[0]=ntohl(data_all->ipv6_addr[0]);
+ data_all->ipv6_addr[1]=ntohl(data_all->ipv6_addr[1]);
+ data_all->ipv6_addr[2]=ntohl(data_all->ipv6_addr[2]);
+ data_all->ipv6_addr[3]=ntohl(data_all->ipv6_addr[3]);
+ data_all->iptype = IPA_IP_v6;
+ }
+ else if (msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET)
+ {
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+ IPACM_EVENT_COPY_ADDR_v4( data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+ data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+ data_all->iptype = IPA_IP_v4;
+ }
+ else
+ {
+ data_all->iptype = IPA_IP_v6;
+ }
+
+ IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+
+ memcpy(data_all->mac_addr,
+ msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+ sizeof(data_all->mac_addr));
+ data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+ /* Add support to replace src-mac as bridge0 mac */
+ if((msg_ptr->nl_neigh_info.metainfo.ndm_family == AF_BRIDGE) &&
+ (msg_ptr->nl_neigh_info.metainfo.ndm_state == NUD_PERMANENT))
+ {
+ /* Posting IPA_BRIDGE_LINK_UP_EVENT event */
+ evt_data.event = IPA_BRIDGE_LINK_UP_EVENT;
+ IPACMDBG_H("posting IPA_BRIDGE_LINK_UP_EVENT (%s):index:%d \n",
+ dev_name,
+ data_all->if_index);
+ }
+ else
+ {
+ /* Posting new_neigh events for all LAN/WAN clients */
+ evt_data.event = IPA_NEW_NEIGH_EVENT;
+ IPACMDBG_H("posting IPA_NEW_NEIGH_EVENT (%s):index:%d ip-family: %d\n",
+ dev_name,
+ data_all->if_index,
+ msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+ }
+ evt_data.evt_data = data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ break;
+
+ case RTM_DELNEIGH:
+ if(IPACM_SUCCESS != ipa_nl_decode_rtm_neigh(buffer, buflen, &(msg_ptr->nl_neigh_info)))
+ {
+ IPACMERR("Failed to decode rtm neighbor message\n");
+ return IPACM_FAILURE;
+ }
+
+ ret_val = ipa_get_if_name(dev_name, msg_ptr->nl_neigh_info.metainfo.ndm_ifindex);
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Error while getting interface index\n");
+ return IPACM_FAILURE;
+ }
+ else
+ {
+ IPACMDBG("\n GOT RTM_DELNEIGH event (%s) ip %d\n",dev_name,msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+ }
+
+ /* insert to command queue */
+ data_all = (ipacm_event_data_all *)malloc(sizeof(ipacm_event_data_all));
+ if(data_all == NULL)
+ {
+ IPACMERR("unable to allocate memory for event data_all\n");
+ return IPACM_FAILURE;
+ }
+
+ memset(data_all, 0, sizeof(ipacm_event_data_all));
+ if(msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET6)
+ {
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+ IPACM_EVENT_COPY_ADDR_v6( data_all->ipv6_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+
+ data_all->ipv6_addr[0] = ntohl(data_all->ipv6_addr[0]);
+ data_all->ipv6_addr[1] = ntohl(data_all->ipv6_addr[1]);
+ data_all->ipv6_addr[2] = ntohl(data_all->ipv6_addr[2]);
+ data_all->ipv6_addr[3] = ntohl(data_all->ipv6_addr[3]);
+ data_all->iptype = IPA_IP_v6;
+ }
+ else if (msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family == AF_INET)
+ {
+ IPACM_NL_REPORT_ADDR( " ", msg_ptr->nl_neigh_info.attr_info.local_addr);
+ IPACM_EVENT_COPY_ADDR_v4( data_all->ipv4_addr, msg_ptr->nl_neigh_info.attr_info.local_addr);
+ data_all->ipv4_addr = ntohl(data_all->ipv4_addr);
+ data_all->iptype = IPA_IP_v4;
+ }
+ else
+ {
+ data_all->iptype = IPA_IP_v6;
+ }
+
+ IPACMDBG("NDA_LLADDR:MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[0],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[1],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[2],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[3],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[4],
+ (unsigned char)(msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr).sa_data[5]);
+
+ memcpy(data_all->mac_addr,
+ msg_ptr->nl_neigh_info.attr_info.lladdr_hwaddr.sa_data,
+ sizeof(data_all->mac_addr));
+ evt_data.event = IPA_DEL_NEIGH_EVENT;
+ data_all->if_index = msg_ptr->nl_neigh_info.metainfo.ndm_ifindex;
+
+ IPACMDBG_H("posting IPA_DEL_NEIGH_EVENT (%s):index:%d ip-family: %d\n",
+ dev_name,
+ data_all->if_index,
+ msg_ptr->nl_neigh_info.attr_info.local_addr.ss_family);
+ evt_data.evt_data = data_all;
+ IPACM_EvtDispatcher::PostEvt(&evt_data);
+ /* finish command queue */
+ break;
+
+ default:
+ IPACMDBG(" ignore NL event %d!!!\n ", nlh->nlmsg_type);
+ break;
+
+ }
+ nlh = NLMSG_NEXT(nlh, buflen);
+ }
+
+ return IPACM_SUCCESS;
+}
+
+
+/* Virtual function registered to receive incoming messages over the NETLINK routing socket*/
+int ipa_nl_recv_msg(int fd)
+{
+ struct msghdr *msghdr = NULL;
+ struct iovec *iov = NULL;
+ unsigned int msglen = 0;
+ ipa_nl_msg_t *nlmsg = NULL;
+
+ nlmsg = (ipa_nl_msg_t *)malloc(sizeof(ipa_nl_msg_t));
+ if(NULL == nlmsg)
+ {
+ IPACMERR("Failed alloc of nlmsg \n");
+ goto error;
+ }
+ else
+ {
+ if(IPACM_SUCCESS != ipa_nl_recv(fd, &msghdr, &msglen))
+ {
+ IPACMERR("Failed to receive nl message \n");
+ goto error;
+ }
+
+ if(msghdr== NULL)
+ {
+ IPACMERR(" failed to get msghdr\n");
+ goto error;
+ }
+
+ iov = msghdr->msg_iov;
+
+ memset(nlmsg, 0, sizeof(ipa_nl_msg_t));
+ if(IPACM_SUCCESS != ipa_nl_decode_nlmsg((char *)iov->iov_base, msglen, nlmsg))
+ {
+ IPACMERR("Failed to decode nl message \n");
+ goto error;
+ }
+ /* Release NetLink message buffer */
+ if(msghdr)
+ {
+ ipa_nl_release_msg(msghdr);
+ }
+ if(nlmsg)
+ {
+ free(nlmsg);
+ }
+ }
+
+ return IPACM_SUCCESS;
+
+error:
+ if(msghdr)
+ {
+ ipa_nl_release_msg(msghdr);
+ }
+ if(nlmsg)
+ {
+ free(nlmsg);
+ }
+
+ return IPACM_FAILURE;
+}
+
+/* get ipa interface name */
+int ipa_get_if_name
+(
+ char *if_name,
+ int if_index
+ )
+{
+ int fd;
+ struct ifreq ifr;
+
+ if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ IPACMERR("get interface name socket create failed \n");
+ return IPACM_FAILURE;
+ }
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ ifr.ifr_ifindex = if_index;
+ IPACMDBG("Interface index %d\n", if_index);
+
+ if(ioctl(fd, SIOCGIFNAME, &ifr) < 0)
+ {
+ IPACMERR("call_ioctl_on_dev: ioctl failed:\n");
+ close(fd);
+ return IPACM_FAILURE;
+ }
+
+ (void)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;
+ int ret_val;
+
+ memset(&sk_info, 0, sizeof(ipa_nl_sk_info_t));
+ IPACMDBG_H("Entering IPA NL listener init\n");
+
+ if(ipa_nl_open_socket(&sk_info, nl_type, nl_groups) == IPACM_SUCCESS)
+ {
+ IPACMDBG_H("IPA Open netlink socket succeeds\n");
+ }
+ else
+ {
+ IPACMERR("Netlink socket open failed\n");
+ return IPACM_FAILURE;
+ }
+
+ /* Add NETLINK socket to the list of sockets that the listener
+ thread should listen on. */
+
+ if(ipa_nl_addfd_map(sk_fdset, sk_info.sk_fd, read_f) != IPACM_SUCCESS)
+ {
+ IPACMERR("cannot add nl routing sock for reading\n");
+ close(sk_info.sk_fd);
+ return IPACM_FAILURE;
+ }
+
+ /* Start the socket listener thread */
+ ret_val = ipa_nl_sock_listener_start(sk_fdset);
+
+ if(ret_val != IPACM_SUCCESS)
+ {
+ IPACMERR("Failed to start NL listener\n");
+ }
+
+ return IPACM_SUCCESS;
+}
+
+/* find the newroute subnet mask */
+int find_mask(int ip_v4_last, int *mask_value)
+{
+
+ switch(ip_v4_last)
+ {
+
+ case 3:
+ *mask_value = 252;
+ return IPACM_SUCCESS;
+ break;
+
+ case 7:
+ *mask_value = 248;
+ return IPACM_SUCCESS;
+ break;
+
+ case 15:
+ *mask_value = 240;
+ return IPACM_SUCCESS;
+ break;
+
+ case 31:
+ *mask_value = 224;
+ return IPACM_SUCCESS;
+ break;
+
+ case 63:
+ *mask_value = 192;
+ return IPACM_SUCCESS;
+ break;
+
+ case 127:
+ *mask_value = 128;
+ return IPACM_SUCCESS;
+ break;
+
+ case 255:
+ *mask_value = 0;
+ return IPACM_SUCCESS;
+ break;
+
+ default:
+ return IPACM_FAILURE;
+ break;
+
+ }
+}
+
+/* map mask value for ipv6 */
+int mask_v6(int index, uint32_t *mask)
+{
+ switch(index)
+ {
+
+ case 0:
+ *mask = 0x00000000;
+ return IPACM_SUCCESS;
+ break;
+ case 4:
+ *mask = 0xf0000000;
+ return IPACM_SUCCESS;
+ break;
+ case 8:
+ *mask = 0xff000000;
+ return IPACM_SUCCESS;
+ break;
+ case 12:
+ *mask = 0xfff00000;
+ return IPACM_SUCCESS;
+ break;
+ case 16:
+ *mask = 0xffff0000;
+ return IPACM_SUCCESS;
+ break;
+ case 20:
+ *mask = 0xfffff000;
+ return IPACM_SUCCESS;
+ break;
+ case 24:
+ *mask = 0xffffff00;
+ return IPACM_SUCCESS;
+ break;
+ case 28:
+ *mask = 0xfffffff0;
+ return IPACM_SUCCESS;
+ break;
+ case 32:
+ *mask = 0xffffffff;
+ return IPACM_SUCCESS;
+ break;
+ default:
+ return IPACM_FAILURE;
+ break;
+
+ }
+}
+
+