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 <unistd.h> 24#include <sys/types.h> 25#include <dirent.h> 26#include <netinet/ether.h> 27#include <netdb.h> 28#include <linux/if_packet.h> 29#include <netinet/if_ether.h> 30#include <linux/if_arp.h> 31#include <netutils/ifc.h> 32 33struct ifaddrs *get_interface(const char *name, sa_family_t family) 34{ 35 unsigned addr, mask, flags; 36 struct ifaddrs *ifa; 37 struct sockaddr_in *saddr = NULL; 38 struct sockaddr_in *smask = NULL; 39 struct sockaddr_ll *hwaddr = NULL; 40 unsigned char hwbuf[ETH_ALEN]; 41 42 if(ifc_get_info(name, &addr, &mask, &flags)) 43 return NULL; 44 45 if ((family == AF_INET) && (addr == 0)) 46 return NULL; 47 48 ifa = malloc(sizeof(struct ifaddrs)); 49 if (!ifa) 50 return NULL; 51 memset(ifa, 0, sizeof(struct ifaddrs)); 52 53 ifa->ifa_name = malloc(strlen(name)+1); 54 if (!ifa->ifa_name) { 55 free(ifa); 56 return NULL; 57 } 58 strcpy(ifa->ifa_name, name); 59 ifa->ifa_flags = flags; 60 61 if (family == AF_INET) { 62 saddr = malloc(sizeof(struct sockaddr_in)); 63 if (saddr) { 64 saddr->sin_addr.s_addr = addr; 65 saddr->sin_family = family; 66 } 67 ifa->ifa_addr = (struct sockaddr *)saddr; 68 69 if (mask != 0) { 70 smask = malloc(sizeof(struct sockaddr_in)); 71 if (smask) { 72 smask->sin_addr.s_addr = mask; 73 smask->sin_family = family; 74 } 75 } 76 ifa->ifa_netmask = (struct sockaddr *)smask; 77 } else if (family == AF_PACKET) { 78 if (!ifc_get_hwaddr(name, hwbuf)) { 79 hwaddr = malloc(sizeof(struct sockaddr_ll)); 80 if (hwaddr) { 81 memset(hwaddr, 0, sizeof(struct sockaddr_ll)); 82 hwaddr->sll_family = family; 83 /* hwaddr->sll_protocol = ETHERTYPE_IP; */ 84 hwaddr->sll_hatype = ARPHRD_ETHER; 85 hwaddr->sll_halen = ETH_ALEN; 86 memcpy(hwaddr->sll_addr, hwbuf, ETH_ALEN); 87 } 88 } 89 ifa->ifa_addr = (struct sockaddr *)hwaddr; 90 ifa->ifa_netmask = (struct sockaddr *)smask; 91 } 92 return ifa; 93} 94 95int getifaddrs(struct ifaddrs **ifap) 96{ 97 DIR *d; 98 struct dirent *de; 99 struct ifaddrs *ifa; 100 struct ifaddrs *ifah = NULL; 101 102 if (!ifap) 103 return -1; 104 *ifap = NULL; 105 106 if (ifc_init()) 107 return -1; 108 109 d = opendir("/sys/class/net"); 110 if (d == 0) 111 return -1; 112 while ((de = readdir(d))) { 113 if (de->d_name[0] == '.') 114 continue; 115 ifa = get_interface(de->d_name, AF_INET); 116 if (ifa != NULL) { 117 ifa->ifa_next = ifah; 118 ifah = ifa; 119 } 120 ifa = get_interface(de->d_name, AF_PACKET); 121 if (ifa != NULL) { 122 ifa->ifa_next = ifah; 123 ifah = ifa; 124 } 125 } 126 *ifap = ifah; 127 closedir(d); 128 ifc_close(); 129 return 0; 130} 131 132void freeifaddrs(struct ifaddrs *ifa) 133{ 134 struct ifaddrs *ifp; 135 136 while (ifa) { 137 ifp = ifa; 138 free(ifp->ifa_name); 139 if (ifp->ifa_addr) 140 free(ifp->ifa_addr); 141 if (ifp->ifa_netmask) 142 free(ifp->ifa_netmask); 143 ifa = ifa->ifa_next; 144 free(ifp); 145 } 146} 147