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