Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef IFADDRS_ANDROID_H_included
     18 #define IFADDRS_ANDROID_H_included
     19 
     20 #include <cstring>
     21 #include <new>
     22 #include <sys/types.h>
     23 #include <sys/socket.h>
     24 #include <stdio.h>
     25 #include <linux/netlink.h>
     26 #include <linux/rtnetlink.h>
     27 
     28 #include "LocalArray.h"
     29 #include "ScopedFd.h"
     30 
     31 // Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3).
     32 // We fake it here, so java_net_NetworkInterface.cpp can use that API
     33 // with all the non-portable code being in this file.
     34 
     35 // Source-compatible subset of the BSD struct.
     36 struct ifaddrs {
     37     // Pointer to next struct in list, or NULL at end.
     38     ifaddrs* ifa_next;
     39 
     40     // Interface name.
     41     char* ifa_name;
     42 
     43     // Interface flags.
     44     unsigned int ifa_flags;
     45 
     46     // Interface address.
     47     sockaddr* ifa_addr;
     48 
     49     ifaddrs(ifaddrs* next)
     50     : ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL)
     51     {
     52     }
     53 
     54     ~ifaddrs() {
     55         delete ifa_next;
     56         delete[] ifa_name;
     57         delete ifa_addr;
     58     }
     59 
     60     // Sadly, we can't keep the interface index for portability with BSD.
     61     // We'll have to keep the name instead, and re-query the index when
     62     // we need it later.
     63     bool setNameAndFlagsByIndex(int interfaceIndex) {
     64         // Get the name.
     65         char buf[IFNAMSIZ];
     66         char* name = if_indextoname(interfaceIndex, buf);
     67         if (name == NULL) {
     68             return false;
     69         }
     70         ifa_name = new char[strlen(name) + 1];
     71         strcpy(ifa_name, name);
     72 
     73         // Get the flags.
     74         ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0));
     75         if (fd.get() == -1) {
     76             return false;
     77         }
     78         ifreq ifr;
     79         memset(&ifr, 0, sizeof(ifr));
     80         strcpy(ifr.ifr_name, name);
     81         int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr);
     82         if (rc == -1) {
     83             return false;
     84         }
     85         ifa_flags = ifr.ifr_flags;
     86         return true;
     87     }
     88 
     89     // Netlink gives us the address family in the header, and the
     90     // sockaddr_in or sockaddr_in6 bytes as the payload. We need to
     91     // stitch the two bits together into the sockaddr that's part of
     92     // our portable interface.
     93     void setAddress(int family, void* data, size_t byteCount) {
     94         sockaddr_storage* ss = new sockaddr_storage;
     95         ss->ss_family = family;
     96         if (family == AF_INET) {
     97             void* dst = &reinterpret_cast<sockaddr_in*>(ss)->sin_addr;
     98             memcpy(dst, data, byteCount);
     99         } else if (family == AF_INET6) {
    100             void* dst = &reinterpret_cast<sockaddr_in6*>(ss)->sin6_addr;
    101             memcpy(dst, data, byteCount);
    102         }
    103         ifa_addr = reinterpret_cast<sockaddr*>(ss);
    104     }
    105 };
    106 
    107 // FIXME: use iovec instead.
    108 struct addrReq_struct {
    109     nlmsghdr netlinkHeader;
    110     ifaddrmsg msg;
    111 };
    112 
    113 inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) {
    114     ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0));
    115     return (sentByteCount == static_cast<ssize_t>(byteCount));
    116 }
    117 
    118 inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) {
    119     return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0));
    120 }
    121 
    122 // Source-compatible with the BSD function.
    123 inline int getifaddrs(ifaddrs** result) {
    124     // Simplify cleanup for callers.
    125     *result = NULL;
    126 
    127     // Create a netlink socket.
    128     ScopedFd fd(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));
    129     if (fd.get() < 0) {
    130         return -1;
    131     }
    132 
    133     // Ask for the address information.
    134     addrReq_struct addrRequest;
    135     memset(&addrRequest, 0, sizeof(addrRequest));
    136     addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
    137     addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR;
    138     addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest)));
    139     addrRequest.msg.ifa_family = AF_UNSPEC; // All families.
    140     addrRequest.msg.ifa_index = 0; // All interfaces.
    141     if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) {
    142         return -1;
    143     }
    144 
    145     // Read the responses.
    146     LocalArray<0> buf(65536); // We don't necessarily have std::vector.
    147     ssize_t bytesRead;
    148     while ((bytesRead  = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) {
    149         nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]);
    150         for (; NLMSG_OK(hdr, bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) {
    151             switch (hdr->nlmsg_type) {
    152             case NLMSG_DONE:
    153                 return 0;
    154             case NLMSG_ERROR:
    155                 return -1;
    156             case RTM_NEWADDR:
    157                 {
    158                     ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
    159                     rtattr* rta = IFA_RTA(address);
    160                     size_t ifaPayloadLength = IFA_PAYLOAD(hdr);
    161                     while (RTA_OK(rta, ifaPayloadLength)) {
    162                         if (rta->rta_type == IFA_LOCAL) {
    163                             int family = address->ifa_family;
    164                             if (family == AF_INET || family == AF_INET6) {
    165                                 *result = new ifaddrs(*result);
    166                                 if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) {
    167                                     return -1;
    168                                 }
    169                                 (*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta));
    170                             }
    171                         }
    172                         rta = RTA_NEXT(rta, ifaPayloadLength);
    173                     }
    174                 }
    175                 break;
    176             }
    177         }
    178     }
    179     // We only get here if recv fails before we see a NLMSG_DONE.
    180     return -1;
    181 }
    182 
    183 // Source-compatible with the BSD function.
    184 inline void freeifaddrs(ifaddrs* addresses) {
    185     delete addresses;
    186 }
    187 
    188 #endif  // IFADDRS_ANDROID_H_included
    189