Blame src/unix/android-ifaddrs.c

Packit b5b901
/*
Packit b5b901
Copyright (c) 2013, Kenneth MacKay
Packit b5b901
Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
Packit b5b901
All rights reserved.
Packit b5b901
Packit b5b901
Redistribution and use in source and binary forms, with or without modification,
Packit b5b901
are permitted provided that the following conditions are met:
Packit b5b901
 * Redistributions of source code must retain the above copyright notice, this
Packit b5b901
   list of conditions and the following disclaimer.
Packit b5b901
 * Redistributions in binary form must reproduce the above copyright notice,
Packit b5b901
   this list of conditions and the following disclaimer in the documentation
Packit b5b901
   and/or other materials provided with the distribution.
Packit b5b901
Packit b5b901
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
Packit b5b901
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Packit b5b901
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit b5b901
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
Packit b5b901
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit b5b901
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Packit b5b901
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
Packit b5b901
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit b5b901
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Packit b5b901
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit b5b901
*/
Packit b5b901
Packit b5b901
#include "uv/android-ifaddrs.h"
Packit b5b901
#include "uv-common.h"
Packit b5b901
Packit b5b901
#include <string.h>
Packit b5b901
#include <stdlib.h>
Packit b5b901
#include <errno.h>
Packit b5b901
#include <unistd.h>
Packit b5b901
#include <sys/socket.h>
Packit b5b901
#include <net/if_arp.h>
Packit b5b901
#include <netinet/in.h>
Packit b5b901
#include <linux/netlink.h>
Packit b5b901
#include <linux/rtnetlink.h>
Packit Service e08953
#include <linux/if_packet.h>
Packit b5b901
Packit b5b901
typedef struct NetlinkList
Packit b5b901
{
Packit b5b901
    struct NetlinkList *m_next;
Packit b5b901
    struct nlmsghdr *m_data;
Packit b5b901
    unsigned int m_size;
Packit b5b901
} NetlinkList;
Packit b5b901
Packit b5b901
static int netlink_socket(pid_t *p_pid)
Packit b5b901
{
Packit b5b901
    struct sockaddr_nl l_addr;
Packit b5b901
    socklen_t l_len;
Packit b5b901
Packit b5b901
    int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
Packit b5b901
    if(l_socket < 0)
Packit b5b901
    {
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    memset(&l_addr, 0, sizeof(l_addr));
Packit b5b901
    l_addr.nl_family = AF_NETLINK;
Packit b5b901
    if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
Packit b5b901
    {
Packit b5b901
        close(l_socket);
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_len = sizeof(l_addr);
Packit b5b901
    if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
Packit b5b901
    {
Packit b5b901
        close(l_socket);
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
    *p_pid = l_addr.nl_pid;
Packit b5b901
Packit b5b901
    return l_socket;
Packit b5b901
}
Packit b5b901
Packit b5b901
static int netlink_send(int p_socket, int p_request)
Packit b5b901
{
Packit b5b901
    char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
Packit b5b901
Packit b5b901
    struct nlmsghdr *l_hdr;
Packit b5b901
    struct rtgenmsg *l_msg;
Packit b5b901
    struct sockaddr_nl l_addr;
Packit b5b901
Packit b5b901
    memset(l_buffer, 0, sizeof(l_buffer));
Packit b5b901
Packit b5b901
    l_hdr = (struct nlmsghdr *)l_buffer;
Packit b5b901
    l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
Packit b5b901
Packit b5b901
    l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
Packit b5b901
    l_hdr->nlmsg_type = p_request;
Packit b5b901
    l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
Packit b5b901
    l_hdr->nlmsg_pid = 0;
Packit b5b901
    l_hdr->nlmsg_seq = p_socket;
Packit b5b901
    l_msg->rtgen_family = AF_UNSPEC;
Packit b5b901
Packit b5b901
    memset(&l_addr, 0, sizeof(l_addr));
Packit b5b901
    l_addr.nl_family = AF_NETLINK;
Packit b5b901
    return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
Packit b5b901
}
Packit b5b901
Packit b5b901
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
Packit b5b901
{
Packit b5b901
    struct sockaddr_nl l_addr;
Packit b5b901
    struct msghdr l_msg;
Packit b5b901
Packit b5b901
    struct iovec l_iov;
Packit b5b901
    l_iov.iov_base = p_buffer;
Packit b5b901
    l_iov.iov_len = p_len;
Packit b5b901
Packit b5b901
    for(;;)
Packit b5b901
    {
Packit b5b901
        int l_result;
Packit b5b901
        l_msg.msg_name = (void *)&l_addr;
Packit b5b901
        l_msg.msg_namelen = sizeof(l_addr);
Packit b5b901
        l_msg.msg_iov = &l_iov;
Packit b5b901
        l_msg.msg_iovlen = 1;
Packit b5b901
        l_msg.msg_control = NULL;
Packit b5b901
        l_msg.msg_controllen = 0;
Packit b5b901
        l_msg.msg_flags = 0;
Packit b5b901
        l_result = recvmsg(p_socket, &l_msg, 0);
Packit b5b901
Packit b5b901
        if(l_result < 0)
Packit b5b901
        {
Packit b5b901
            if(errno == EINTR)
Packit b5b901
            {
Packit b5b901
                continue;
Packit b5b901
            }
Packit b5b901
            return -2;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        /* Buffer was too small */
Packit b5b901
        if(l_msg.msg_flags & MSG_TRUNC)
Packit b5b901
        {
Packit b5b901
            return -1;
Packit b5b901
        }
Packit b5b901
        return l_result;
Packit b5b901
    }
Packit b5b901
}
Packit b5b901
Packit b5b901
static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
Packit b5b901
{
Packit b5b901
    size_t l_size = 4096;
Packit b5b901
    void *l_buffer = NULL;
Packit b5b901
Packit b5b901
    for(;;)
Packit b5b901
    {
Packit b5b901
        int l_read;
Packit b5b901
Packit b5b901
        uv__free(l_buffer);
Packit b5b901
        l_buffer = uv__malloc(l_size);
Packit b5b901
        if (l_buffer == NULL)
Packit b5b901
        {
Packit b5b901
            return NULL;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        l_read = netlink_recv(p_socket, l_buffer, l_size);
Packit b5b901
        *p_size = l_read;
Packit b5b901
        if(l_read == -2)
Packit b5b901
        {
Packit b5b901
            uv__free(l_buffer);
Packit b5b901
            return NULL;
Packit b5b901
        }
Packit b5b901
        if(l_read >= 0)
Packit b5b901
        {
Packit b5b901
            struct nlmsghdr *l_hdr;
Packit b5b901
            for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
Packit b5b901
            {
Packit b5b901
                if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
Packit b5b901
                {
Packit b5b901
                    continue;
Packit b5b901
                }
Packit b5b901
Packit b5b901
                if(l_hdr->nlmsg_type == NLMSG_DONE)
Packit b5b901
                {
Packit b5b901
                    *p_done = 1;
Packit b5b901
                    break;
Packit b5b901
                }
Packit b5b901
Packit b5b901
                if(l_hdr->nlmsg_type == NLMSG_ERROR)
Packit b5b901
                {
Packit b5b901
                    uv__free(l_buffer);
Packit b5b901
                    return NULL;
Packit b5b901
                }
Packit b5b901
            }
Packit b5b901
            return l_buffer;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        l_size *= 2;
Packit b5b901
    }
Packit b5b901
}
Packit b5b901
Packit b5b901
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
Packit b5b901
{
Packit b5b901
    NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
Packit b5b901
    if (l_item == NULL)
Packit b5b901
    {
Packit b5b901
        return NULL;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_item->m_next = NULL;
Packit b5b901
    l_item->m_data = p_data;
Packit b5b901
    l_item->m_size = p_size;
Packit b5b901
    return l_item;
Packit b5b901
}
Packit b5b901
Packit b5b901
static void freeResultList(NetlinkList *p_list)
Packit b5b901
{
Packit b5b901
    NetlinkList *l_cur;
Packit b5b901
    while(p_list)
Packit b5b901
    {
Packit b5b901
        l_cur = p_list;
Packit b5b901
        p_list = p_list->m_next;
Packit b5b901
        uv__free(l_cur->m_data);
Packit b5b901
        uv__free(l_cur);
Packit b5b901
    }
Packit b5b901
}
Packit b5b901
Packit b5b901
static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
Packit b5b901
{
Packit b5b901
    int l_size;
Packit b5b901
    int l_done;
Packit b5b901
    NetlinkList *l_list;
Packit b5b901
    NetlinkList *l_end;
Packit b5b901
Packit b5b901
    if(netlink_send(p_socket, p_request) < 0)
Packit b5b901
    {
Packit b5b901
        return NULL;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_list = NULL;
Packit b5b901
    l_end = NULL;
Packit b5b901
Packit b5b901
    l_done = 0;
Packit b5b901
    while(!l_done)
Packit b5b901
    {
Packit b5b901
        NetlinkList *l_item;
Packit b5b901
Packit b5b901
        struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
Packit b5b901
        /* Error */
Packit b5b901
        if(!l_hdr)
Packit b5b901
        {
Packit b5b901
            freeResultList(l_list);
Packit b5b901
            return NULL;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        l_item = newListItem(l_hdr, l_size);
Packit b5b901
        if (!l_item)
Packit b5b901
        {
Packit b5b901
            freeResultList(l_list);
Packit b5b901
            return NULL;
Packit b5b901
        }
Packit b5b901
        if(!l_list)
Packit b5b901
        {
Packit b5b901
            l_list = l_item;
Packit b5b901
        }
Packit b5b901
        else
Packit b5b901
        {
Packit b5b901
            l_end->m_next = l_item;
Packit b5b901
        }
Packit b5b901
        l_end = l_item;
Packit b5b901
    }
Packit b5b901
    return l_list;
Packit b5b901
}
Packit b5b901
Packit b5b901
static size_t maxSize(size_t a, size_t b)
Packit b5b901
{
Packit b5b901
    return (a > b ? a : b);
Packit b5b901
}
Packit b5b901
Packit b5b901
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
Packit b5b901
{
Packit b5b901
    switch(p_family)
Packit b5b901
    {
Packit b5b901
        case AF_INET:
Packit b5b901
            return sizeof(struct sockaddr_in);
Packit b5b901
        case AF_INET6:
Packit b5b901
            return sizeof(struct sockaddr_in6);
Packit b5b901
        case AF_PACKET:
Packit b5b901
            return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
Packit b5b901
        default:
Packit b5b901
            return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
Packit b5b901
    }
Packit b5b901
}
Packit b5b901
Packit b5b901
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
Packit b5b901
{
Packit b5b901
    switch(p_family)
Packit b5b901
    {
Packit b5b901
        case AF_INET:
Packit b5b901
            memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
Packit b5b901
            break;
Packit b5b901
        case AF_INET6:
Packit b5b901
            memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
Packit b5b901
            break;
Packit b5b901
        case AF_PACKET:
Packit b5b901
            memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
Packit b5b901
            ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
Packit b5b901
            break;
Packit b5b901
        default:
Packit b5b901
            memcpy(p_dest->sa_data, p_data, p_size);
Packit b5b901
            break;
Packit b5b901
    }
Packit b5b901
    p_dest->sa_family = p_family;
Packit b5b901
}
Packit b5b901
Packit b5b901
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
Packit b5b901
{
Packit b5b901
    if(!*p_resultList)
Packit b5b901
    {
Packit b5b901
        *p_resultList = p_entry;
Packit b5b901
    }
Packit b5b901
    else
Packit b5b901
    {
Packit b5b901
        struct ifaddrs *l_cur = *p_resultList;
Packit b5b901
        while(l_cur->ifa_next)
Packit b5b901
        {
Packit b5b901
            l_cur = l_cur->ifa_next;
Packit b5b901
        }
Packit b5b901
        l_cur->ifa_next = p_entry;
Packit b5b901
    }
Packit b5b901
}
Packit b5b901
Packit b5b901
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
Packit b5b901
{
Packit b5b901
    struct ifaddrs *l_entry;
Packit b5b901
Packit b5b901
    char *l_index;
Packit b5b901
    char *l_name;
Packit b5b901
    char *l_addr;
Packit b5b901
    char *l_data;
Packit b5b901
Packit b5b901
    struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
Packit b5b901
Packit b5b901
    size_t l_nameSize = 0;
Packit b5b901
    size_t l_addrSize = 0;
Packit b5b901
    size_t l_dataSize = 0;
Packit b5b901
Packit b5b901
    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
Packit b5b901
    struct rtattr *l_rta;
Packit b5b901
    for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
Packit b5b901
    {
Packit b5b901
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
Packit b5b901
        switch(l_rta->rta_type)
Packit b5b901
        {
Packit b5b901
            case IFLA_ADDRESS:
Packit b5b901
            case IFLA_BROADCAST:
Packit b5b901
                l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
Packit b5b901
                break;
Packit b5b901
            case IFLA_IFNAME:
Packit b5b901
                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
Packit b5b901
                break;
Packit b5b901
            case IFLA_STATS:
Packit b5b901
                l_dataSize += NLMSG_ALIGN(l_rtaSize);
Packit b5b901
                break;
Packit b5b901
            default:
Packit b5b901
                break;
Packit b5b901
        }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
Packit b5b901
    if (l_entry == NULL)
Packit b5b901
    {
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
    memset(l_entry, 0, sizeof(struct ifaddrs));
Packit b5b901
    l_entry->ifa_name = "";
Packit b5b901
Packit b5b901
    l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
Packit b5b901
    l_name = l_index + sizeof(int);
Packit b5b901
    l_addr = l_name + l_nameSize;
Packit b5b901
    l_data = l_addr + l_addrSize;
Packit b5b901
Packit b5b901
    /* Save the interface index so we can look it up when handling the
Packit b5b901
     * addresses.
Packit b5b901
     */
Packit b5b901
    memcpy(l_index, &l_info->ifi_index, sizeof(int));
Packit b5b901
Packit b5b901
    l_entry->ifa_flags = l_info->ifi_flags;
Packit b5b901
Packit b5b901
    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
Packit b5b901
    for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
Packit b5b901
    {
Packit b5b901
        void *l_rtaData = RTA_DATA(l_rta);
Packit b5b901
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
Packit b5b901
        switch(l_rta->rta_type)
Packit b5b901
        {
Packit b5b901
            case IFLA_ADDRESS:
Packit b5b901
            case IFLA_BROADCAST:
Packit b5b901
            {
Packit b5b901
                size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
Packit b5b901
                makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
Packit b5b901
                ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
Packit b5b901
                ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
Packit b5b901
                if(l_rta->rta_type == IFLA_ADDRESS)
Packit b5b901
                {
Packit b5b901
                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
Packit b5b901
                }
Packit b5b901
                else
Packit b5b901
                {
Packit b5b901
                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
Packit b5b901
                }
Packit b5b901
                l_addr += NLMSG_ALIGN(l_addrLen);
Packit b5b901
                break;
Packit b5b901
            }
Packit b5b901
            case IFLA_IFNAME:
Packit b5b901
                strncpy(l_name, l_rtaData, l_rtaDataSize);
Packit b5b901
                l_name[l_rtaDataSize] = '\0';
Packit b5b901
                l_entry->ifa_name = l_name;
Packit b5b901
                break;
Packit b5b901
            case IFLA_STATS:
Packit b5b901
                memcpy(l_data, l_rtaData, l_rtaDataSize);
Packit b5b901
                l_entry->ifa_data = l_data;
Packit b5b901
                break;
Packit b5b901
            default:
Packit b5b901
                break;
Packit b5b901
        }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    addToEnd(p_resultList, l_entry);
Packit b5b901
    return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
Packit b5b901
{
Packit b5b901
    int l_num = 0;
Packit b5b901
    struct ifaddrs *l_cur = *p_links;
Packit b5b901
    while(l_cur && l_num < p_numLinks)
Packit b5b901
    {
Packit b5b901
        char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
Packit b5b901
        int l_index;
Packit b5b901
        memcpy(&l_index, l_indexPtr, sizeof(int));
Packit b5b901
        if(l_index == p_index)
Packit b5b901
        {
Packit b5b901
            return l_cur;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        l_cur = l_cur->ifa_next;
Packit b5b901
        ++l_num;
Packit b5b901
    }
Packit b5b901
    return NULL;
Packit b5b901
}
Packit b5b901
Packit b5b901
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
Packit b5b901
{
Packit b5b901
    struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
Packit b5b901
    struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
Packit b5b901
Packit b5b901
    size_t l_nameSize = 0;
Packit b5b901
    size_t l_addrSize = 0;
Packit b5b901
Packit b5b901
    int l_addedNetmask = 0;
Packit b5b901
Packit b5b901
    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
Packit b5b901
    struct rtattr *l_rta;
Packit b5b901
    struct ifaddrs *l_entry;
Packit b5b901
Packit b5b901
    char *l_name;
Packit b5b901
    char *l_addr;
Packit b5b901
Packit b5b901
    for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
Packit b5b901
    {
Packit b5b901
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
Packit b5b901
        if(l_info->ifa_family == AF_PACKET)
Packit b5b901
        {
Packit b5b901
            continue;
Packit b5b901
        }
Packit b5b901
Packit b5b901
        switch(l_rta->rta_type)
Packit b5b901
        {
Packit b5b901
            case IFA_ADDRESS:
Packit b5b901
            case IFA_LOCAL:
Packit Service e08953
                l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
Packit b5b901
                if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
Packit b5b901
                {
Packit b5b901
                    /* Make room for netmask */
Packit b5b901
                    l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
Packit b5b901
                    l_addedNetmask = 1;
Packit b5b901
                }
Packit Service e08953
                break;
Packit b5b901
            case IFA_BROADCAST:
Packit b5b901
                l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
Packit b5b901
                break;
Packit b5b901
            case IFA_LABEL:
Packit b5b901
                l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
Packit b5b901
                break;
Packit b5b901
            default:
Packit b5b901
                break;
Packit b5b901
        }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
Packit b5b901
    if (l_entry == NULL)
Packit b5b901
    {
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
    memset(l_entry, 0, sizeof(struct ifaddrs));
Packit b5b901
    l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
Packit b5b901
Packit b5b901
    l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
Packit b5b901
    l_addr = l_name + l_nameSize;
Packit b5b901
Packit b5b901
    l_entry->ifa_flags = l_info->ifa_flags;
Packit b5b901
    if(l_interface)
Packit b5b901
    {
Packit b5b901
        l_entry->ifa_flags |= l_interface->ifa_flags;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
Packit b5b901
    for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
Packit b5b901
    {
Packit b5b901
        void *l_rtaData = RTA_DATA(l_rta);
Packit b5b901
        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
Packit b5b901
        switch(l_rta->rta_type)
Packit b5b901
        {
Packit b5b901
            case IFA_ADDRESS:
Packit b5b901
            case IFA_BROADCAST:
Packit b5b901
            case IFA_LOCAL:
Packit b5b901
            {
Packit b5b901
                size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
Packit b5b901
                makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
Packit b5b901
                if(l_info->ifa_family == AF_INET6)
Packit b5b901
                {
Packit b5b901
                    if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
Packit b5b901
                    {
Packit b5b901
                        ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
Packit b5b901
                    }
Packit b5b901
                }
Packit b5b901
Packit b5b901
                /* Apparently in a point-to-point network IFA_ADDRESS contains
Packit b5b901
                 * the dest address and IFA_LOCAL contains the local address
Packit b5b901
                 */
Packit b5b901
                if(l_rta->rta_type == IFA_ADDRESS)
Packit b5b901
                {
Packit b5b901
                    if(l_entry->ifa_addr)
Packit b5b901
                    {
Packit b5b901
                        l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
Packit b5b901
                    }
Packit b5b901
                    else
Packit b5b901
                    {
Packit b5b901
                        l_entry->ifa_addr = (struct sockaddr *)l_addr;
Packit b5b901
                    }
Packit b5b901
                }
Packit b5b901
                else if(l_rta->rta_type == IFA_LOCAL)
Packit b5b901
                {
Packit b5b901
                    if(l_entry->ifa_addr)
Packit b5b901
                    {
Packit b5b901
                        l_entry->ifa_dstaddr = l_entry->ifa_addr;
Packit b5b901
                    }
Packit b5b901
                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
Packit b5b901
                }
Packit b5b901
                else
Packit b5b901
                {
Packit b5b901
                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
Packit b5b901
                }
Packit b5b901
                l_addr += NLMSG_ALIGN(l_addrLen);
Packit b5b901
                break;
Packit b5b901
            }
Packit b5b901
            case IFA_LABEL:
Packit b5b901
                strncpy(l_name, l_rtaData, l_rtaDataSize);
Packit b5b901
                l_name[l_rtaDataSize] = '\0';
Packit b5b901
                l_entry->ifa_name = l_name;
Packit b5b901
                break;
Packit b5b901
            default:
Packit b5b901
                break;
Packit b5b901
        }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
Packit b5b901
    {
Packit b5b901
        unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
Packit b5b901
        unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
Packit b5b901
        unsigned char l_mask[16] = {0};
Packit b5b901
        unsigned i;
Packit b5b901
        for(i=0; i<(l_prefix/8); ++i)
Packit b5b901
        {
Packit b5b901
            l_mask[i] = 0xff;
Packit b5b901
        }
Packit b5b901
        if(l_prefix % 8)
Packit b5b901
        {
Packit b5b901
            l_mask[i] = 0xff << (8 - (l_prefix % 8));
Packit b5b901
        }
Packit b5b901
Packit b5b901
        makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
Packit b5b901
        l_entry->ifa_netmask = (struct sockaddr *)l_addr;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    addToEnd(p_resultList, l_entry);
Packit b5b901
    return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
Packit b5b901
{
Packit b5b901
Packit b5b901
    int l_numLinks = 0;
Packit b5b901
    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
Packit b5b901
    {
Packit b5b901
        unsigned int l_nlsize = p_netlinkList->m_size;
Packit b5b901
        struct nlmsghdr *l_hdr;
Packit b5b901
        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
Packit b5b901
        {
Packit b5b901
            if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
Packit b5b901
            {
Packit b5b901
                continue;
Packit b5b901
            }
Packit b5b901
Packit b5b901
            if(l_hdr->nlmsg_type == NLMSG_DONE)
Packit b5b901
            {
Packit b5b901
                break;
Packit b5b901
            }
Packit b5b901
Packit b5b901
            if(l_hdr->nlmsg_type == RTM_NEWLINK)
Packit b5b901
            {
Packit b5b901
                if(interpretLink(l_hdr, p_resultList) == -1)
Packit b5b901
                {
Packit b5b901
                    return -1;
Packit b5b901
                }
Packit b5b901
                ++l_numLinks;
Packit b5b901
            }
Packit b5b901
        }
Packit b5b901
    }
Packit b5b901
    return l_numLinks;
Packit b5b901
}
Packit b5b901
Packit b5b901
static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
Packit b5b901
{
Packit b5b901
    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
Packit b5b901
    {
Packit b5b901
        unsigned int l_nlsize = p_netlinkList->m_size;
Packit b5b901
        struct nlmsghdr *l_hdr;
Packit b5b901
        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
Packit b5b901
        {
Packit b5b901
            if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
Packit b5b901
            {
Packit b5b901
                continue;
Packit b5b901
            }
Packit b5b901
Packit b5b901
            if(l_hdr->nlmsg_type == NLMSG_DONE)
Packit b5b901
            {
Packit b5b901
                break;
Packit b5b901
            }
Packit b5b901
Packit b5b901
            if(l_hdr->nlmsg_type == RTM_NEWADDR)
Packit b5b901
            {
Packit b5b901
                if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
Packit b5b901
                {
Packit b5b901
                    return -1;
Packit b5b901
                }
Packit b5b901
            }
Packit b5b901
        }
Packit b5b901
    }
Packit b5b901
    return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
int getifaddrs(struct ifaddrs **ifap)
Packit b5b901
{
Packit b5b901
    int l_socket;
Packit b5b901
    int l_result;
Packit b5b901
    int l_numLinks;
Packit b5b901
    pid_t l_pid;
Packit b5b901
    NetlinkList *l_linkResults;
Packit b5b901
    NetlinkList *l_addrResults;
Packit b5b901
Packit b5b901
    if(!ifap)
Packit b5b901
    {
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
    *ifap = NULL;
Packit b5b901
Packit b5b901
    l_socket = netlink_socket(&l_pid);
Packit b5b901
    if(l_socket < 0)
Packit b5b901
    {
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
Packit b5b901
    if(!l_linkResults)
Packit b5b901
    {
Packit b5b901
        close(l_socket);
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
Packit b5b901
    if(!l_addrResults)
Packit b5b901
    {
Packit b5b901
        close(l_socket);
Packit b5b901
        freeResultList(l_linkResults);
Packit b5b901
        return -1;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    l_result = 0;
Packit b5b901
    l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
Packit b5b901
    if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
Packit b5b901
    {
Packit b5b901
        l_result = -1;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    freeResultList(l_linkResults);
Packit b5b901
    freeResultList(l_addrResults);
Packit b5b901
    close(l_socket);
Packit b5b901
    return l_result;
Packit b5b901
}
Packit b5b901
Packit b5b901
void freeifaddrs(struct ifaddrs *ifa)
Packit b5b901
{
Packit b5b901
    struct ifaddrs *l_cur;
Packit b5b901
    while(ifa)
Packit b5b901
    {
Packit b5b901
        l_cur = ifa;
Packit b5b901
        ifa = ifa->ifa_next;
Packit b5b901
        uv__free(l_cur);
Packit b5b901
    }
Packit b5b901
}