1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/sctp/src/ifaddrs_android.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,189 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* 1.7 + * Copyright (C) 2009 The Android Open Source Project 1.8 + * 1.9 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.10 + * you may not use this file except in compliance with the License. 1.11 + * You may obtain a copy of the License at 1.12 + * 1.13 + * http://www.apache.org/licenses/LICENSE-2.0 1.14 + * 1.15 + * Unless required by applicable law or agreed to in writing, software 1.16 + * distributed under the License is distributed on an "AS IS" BASIS, 1.17 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.18 + * See the License for the specific language governing permissions and 1.19 + * limitations under the License. 1.20 + */ 1.21 + 1.22 +#include "ifaddrs-android-ext.h" 1.23 + 1.24 +#include <stdlib.h> 1.25 +#include <string.h> 1.26 +#include "ScopedFd.h" 1.27 +#include "LocalArray.h" 1.28 + 1.29 +// Returns a pointer to the first byte in the address data (which is 1.30 +// stored in network byte order). 1.31 +uint8_t* sockaddrBytes(int family, sockaddr_storage* ss) { 1.32 + if (family == AF_INET) { 1.33 + sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss); 1.34 + return reinterpret_cast<uint8_t*>(&ss4->sin_addr); 1.35 + } else if (family == AF_INET6) { 1.36 + sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss); 1.37 + return reinterpret_cast<uint8_t*>(&ss6->sin6_addr); 1.38 + } 1.39 + return NULL; 1.40 +} 1.41 + 1.42 +// Sadly, we can't keep the interface index for portability with BSD. 1.43 +// We'll have to keep the name instead, and re-query the index when 1.44 +// we need it later. 1.45 +bool ifa_setNameAndFlagsByIndex(ifaddrs *self, int interfaceIndex) { 1.46 + // Get the name. 1.47 + char buf[IFNAMSIZ]; 1.48 + char* name = if_indextoname(interfaceIndex, buf); 1.49 + if (name == NULL) { 1.50 + return false; 1.51 + } 1.52 + self->ifa_name = new char[strlen(name) + 1]; 1.53 + strcpy(self->ifa_name, name); 1.54 + 1.55 + // Get the flags. 1.56 + ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0)); 1.57 + if (fd.get() == -1) { 1.58 + return false; 1.59 + } 1.60 + ifreq ifr; 1.61 + memset(&ifr, 0, sizeof(ifr)); 1.62 + strcpy(ifr.ifr_name, name); 1.63 + int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr); 1.64 + if (rc == -1) { 1.65 + return false; 1.66 + } 1.67 + self->ifa_flags = ifr.ifr_flags; 1.68 + return true; 1.69 +} 1.70 + 1.71 +// Netlink gives us the address family in the header, and the 1.72 +// sockaddr_in or sockaddr_in6 bytes as the payload. We need to 1.73 +// stitch the two bits together into the sockaddr that's part of 1.74 +// our portable interface. 1.75 +void ifa_setAddress(ifaddrs *self, int family, void* data, size_t byteCount) { 1.76 + // Set the address proper... 1.77 + sockaddr_storage* ss = new sockaddr_storage; 1.78 + memset(ss, 0, sizeof(*ss)); 1.79 + self->ifa_addr = reinterpret_cast<sockaddr*>(ss); 1.80 + ss->ss_family = family; 1.81 + uint8_t* dst = sockaddrBytes(family, ss); 1.82 + memcpy(dst, data, byteCount); 1.83 +} 1.84 + 1.85 +// Netlink gives us the prefix length as a bit count. We need to turn 1.86 +// that into a BSD-compatible netmask represented by a sockaddr*. 1.87 +void ifa_setNetmask(ifaddrs *self, int family, size_t prefixLength) { 1.88 + // ...and work out the netmask from the prefix length. 1.89 + sockaddr_storage* ss = new sockaddr_storage; 1.90 + memset(ss, 0, sizeof(*ss)); 1.91 + self->ifa_netmask = reinterpret_cast<sockaddr*>(ss); 1.92 + ss->ss_family = family; 1.93 + uint8_t* dst = sockaddrBytes(family, ss); 1.94 + memset(dst, 0xff, prefixLength / 8); 1.95 + if ((prefixLength % 8) != 0) { 1.96 + dst[prefixLength/8] = (0xff << (8 - (prefixLength % 8))); 1.97 + } 1.98 +} 1.99 + 1.100 +// FIXME: use iovec instead. 1.101 +struct addrReq_struct { 1.102 + nlmsghdr netlinkHeader; 1.103 + ifaddrmsg msg; 1.104 +}; 1.105 + 1.106 +inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) { 1.107 + ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0)); 1.108 + return (sentByteCount == static_cast<ssize_t>(byteCount)); 1.109 +} 1.110 + 1.111 +inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) { 1.112 + return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0)); 1.113 +} 1.114 + 1.115 +// Source-compatible with the BSD function. 1.116 +int getifaddrs(ifaddrs** result) 1.117 +{ 1.118 + // Simplify cleanup for callers. 1.119 + *result = NULL; 1.120 + 1.121 + // Create a netlink socket. 1.122 + ScopedFd fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)); 1.123 + if (fd.get() < 0) { 1.124 + return -1; 1.125 + } 1.126 + 1.127 + // Ask for the address information. 1.128 + addrReq_struct addrRequest; 1.129 + memset(&addrRequest, 0, sizeof(addrRequest)); 1.130 + addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH; 1.131 + addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR; 1.132 + addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest))); 1.133 + addrRequest.msg.ifa_family = AF_UNSPEC; // All families. 1.134 + addrRequest.msg.ifa_index = 0; // All interfaces. 1.135 + if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) { 1.136 + return -1; 1.137 + } 1.138 + 1.139 + // Read the responses. 1.140 + LocalArray<0> buf(65536); // We don't necessarily have std::vector. 1.141 + ssize_t bytesRead; 1.142 + while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) { 1.143 + nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]); 1.144 + for (; NLMSG_OK(hdr, (size_t)bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) { 1.145 + switch (hdr->nlmsg_type) { 1.146 + case NLMSG_DONE: 1.147 + return 0; 1.148 + case NLMSG_ERROR: 1.149 + return -1; 1.150 + case RTM_NEWADDR: 1.151 + { 1.152 + ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr)); 1.153 + rtattr* rta = IFA_RTA(address); 1.154 + size_t ifaPayloadLength = IFA_PAYLOAD(hdr); 1.155 + while (RTA_OK(rta, ifaPayloadLength)) { 1.156 + if (rta->rta_type == IFA_LOCAL) { 1.157 + int family = address->ifa_family; 1.158 + if (family == AF_INET || family == AF_INET6) { 1.159 + ifaddrs *next = *result; 1.160 + *result = new ifaddrs; 1.161 + memset(*result, 0, sizeof(ifaddrs)); 1.162 + (*result)->ifa_next = next; 1.163 + if (!ifa_setNameAndFlagsByIndex(*result, address->ifa_index)) { 1.164 + return -1; 1.165 + } 1.166 + ifa_setAddress(*result, family, RTA_DATA(rta), RTA_PAYLOAD(rta)); 1.167 + ifa_setNetmask(*result, family, address->ifa_prefixlen); 1.168 + } 1.169 + } 1.170 + rta = RTA_NEXT(rta, ifaPayloadLength); 1.171 + } 1.172 + } 1.173 + break; 1.174 + } 1.175 + } 1.176 + } 1.177 + // We only get here if recv fails before we see a NLMSG_DONE. 1.178 + return -1; 1.179 +} 1.180 + 1.181 +// Source-compatible with the BSD function. 1.182 +void freeifaddrs(ifaddrs* addresses) { 1.183 + ifaddrs* self = addresses; 1.184 + while (self != NULL) { 1.185 + delete[] self->ifa_name; 1.186 + delete self->ifa_addr; 1.187 + delete self->ifa_netmask; 1.188 + ifaddrs* next = self->ifa_next; 1.189 + delete self; 1.190 + self = next; 1.191 + } 1.192 +}