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