1 /* external/dhcpcd/ifaddrs.c 2 ** 3 ** Copyright 2011, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License");. 6 ** you may not use this file except in compliance with the License.. 7 ** You may obtain a copy of the License at. 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0. 10 ** 11 ** Unless required by applicable law or agreed to in writing, software. 12 ** distributed under the License is distributed on an "AS IS" BASIS,. 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.. 14 ** See the License for the specific language governing permissions and. 15 ** limitations under the License. 16 */ 17 18 #include <arpa/inet.h> 19 #include <sys/socket.h> 20 #include "ifaddrs.h" 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 #include <sys/types.h> 26 #include <dirent.h> 27 #include <netinet/ether.h> 28 #include <netdb.h> 29 #include <linux/if_packet.h> 30 #include <netinet/if_ether.h> 31 #include <linux/if_arp.h> 32 #include <netutils/ifc.h> 33 34 struct ifaddrs *get_interface(const char *name, sa_family_t family) 35 { 36 unsigned addr, flags; 37 int masklen; 38 struct ifaddrs *ifa; 39 struct sockaddr_in *saddr = NULL; 40 struct sockaddr_in *smask = NULL; 41 struct sockaddr_ll *hwaddr = NULL; 42 unsigned char hwbuf[ETH_ALEN]; 43 44 if (ifc_get_info(name, &addr, &masklen, &flags)) 45 return NULL; 46 47 if ((family == AF_INET) && (addr == 0)) 48 return NULL; 49 50 ifa = malloc(sizeof(struct ifaddrs)); 51 if (!ifa) 52 return NULL; 53 memset(ifa, 0, sizeof(struct ifaddrs)); 54 55 ifa->ifa_name = malloc(strlen(name)+1); 56 if (!ifa->ifa_name) { 57 free(ifa); 58 return NULL; 59 } 60 strcpy(ifa->ifa_name, name); 61 ifa->ifa_flags = flags; 62 63 if (family == AF_INET) { 64 saddr = malloc(sizeof(struct sockaddr_in)); 65 if (saddr) { 66 saddr->sin_addr.s_addr = addr; 67 saddr->sin_family = family; 68 } 69 ifa->ifa_addr = (struct sockaddr *)saddr; 70 71 if (masklen != 0) { 72 smask = malloc(sizeof(struct sockaddr_in)); 73 if (smask) { 74 smask->sin_addr.s_addr = prefixLengthToIpv4Netmask(masklen); 75 smask->sin_family = family; 76 } 77 } 78 ifa->ifa_netmask = (struct sockaddr *)smask; 79 } else if (family == AF_PACKET) { 80 if (!ifc_get_hwaddr(name, hwbuf)) { 81 hwaddr = malloc(sizeof(struct sockaddr_ll)); 82 if (hwaddr) { 83 memset(hwaddr, 0, sizeof(struct sockaddr_ll)); 84 hwaddr->sll_family = family; 85 /* hwaddr->sll_protocol = ETHERTYPE_IP; */ 86 hwaddr->sll_hatype = ARPHRD_ETHER; 87 hwaddr->sll_halen = ETH_ALEN; 88 memcpy(hwaddr->sll_addr, hwbuf, ETH_ALEN); 89 } 90 } 91 ifa->ifa_addr = (struct sockaddr *)hwaddr; 92 ifa->ifa_netmask = (struct sockaddr *)smask; 93 } 94 return ifa; 95 } 96 97 int getifaddrs(struct ifaddrs **ifap) 98 { 99 DIR *d; 100 struct dirent *de; 101 struct ifaddrs *ifa; 102 struct ifaddrs *ifah = NULL; 103 104 if (!ifap) 105 return -1; 106 *ifap = NULL; 107 108 if (ifc_init()) 109 return -1; 110 111 d = opendir("/sys/class/net"); 112 if (d == 0) 113 return -1; 114 while ((de = readdir(d))) { 115 if (de->d_name[0] == '.') 116 continue; 117 ifa = get_interface(de->d_name, AF_INET); 118 if (ifa != NULL) { 119 ifa->ifa_next = ifah; 120 ifah = ifa; 121 } 122 ifa = get_interface(de->d_name, AF_PACKET); 123 if (ifa != NULL) { 124 ifa->ifa_next = ifah; 125 ifah = ifa; 126 } 127 } 128 *ifap = ifah; 129 closedir(d); 130 ifc_close(); 131 return 0; 132 } 133 134 void freeifaddrs(struct ifaddrs *ifa) 135 { 136 struct ifaddrs *ifp; 137 138 while (ifa) { 139 ifp = ifa; 140 free(ifp->ifa_name); 141 if (ifp->ifa_addr) 142 free(ifp->ifa_addr); 143 if (ifp->ifa_netmask) 144 free(ifp->ifa_netmask); 145 ifa = ifa->ifa_next; 146 free(ifp); 147 } 148 } 149