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
get_interface(const char * name,sa_family_t family)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
getifaddrs(struct ifaddrs ** ifap)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
freeifaddrs(struct ifaddrs * ifa)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