import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / inet / getifaddrs.c
blob66dfedbd10d4e1496deab55114e69ec375d75151
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2017 RackTop Systems.
27 #include <netdb.h>
28 #include <nss_dbdefs.h>
29 #include <netinet/in.h>
30 #include <sys/socket.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <sys/sockio.h>
34 #include <sys/types.h>
35 #include <stdlib.h>
36 #include <net/if.h>
37 #include <ifaddrs.h>
38 #include <libsocket_priv.h>
41 * Create a linked list of `struct ifaddrs' structures, one for each
42 * address that is UP. If successful, store the list in *ifap and
43 * return 0. On errors, return -1 and set `errno'.
45 * The storage returned in *ifap is allocated dynamically and can
46 * only be properly freed by passing it to `freeifaddrs'.
48 int
49 getifaddrs(struct ifaddrs **ifap)
51 int err;
52 char *cp;
53 struct ifaddrs *curr;
55 if (ifap == NULL) {
56 errno = EINVAL;
57 return (-1);
59 *ifap = NULL;
60 err = getallifaddrs(AF_UNSPEC, ifap, LIFC_ENABLED);
61 if (err == 0) {
62 for (curr = *ifap; curr != NULL; curr = curr->ifa_next) {
63 if ((cp = strchr(curr->ifa_name, ':')) != NULL)
64 *cp = '\0';
67 return (err);
70 void
71 freeifaddrs(struct ifaddrs *ifa)
73 struct ifaddrs *curr;
75 while (ifa != NULL) {
76 curr = ifa;
77 ifa = ifa->ifa_next;
78 free(curr->ifa_name);
79 free(curr->ifa_addr);
80 free(curr->ifa_netmask);
81 free(curr->ifa_dstaddr);
82 free(curr);
87 * Returns all addresses configured on the system. If flags contain
88 * LIFC_ENABLED, only the addresses that are UP are returned.
89 * Address list that is returned by this function must be freed
90 * using freeifaddrs().
92 int
93 getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags)
95 struct lifreq *buf = NULL;
96 struct lifreq *lifrp;
97 struct lifreq lifrl;
98 int ret;
99 int s, n, numifs;
100 struct ifaddrs *curr, *prev;
101 sa_family_t lifr_af;
102 int sock4;
103 int sock6;
104 int err;
107 * Initialize ifap to NULL so we can safely call freeifaddrs
108 * on it in case of error.
110 if (ifap == NULL)
111 return (EINVAL);
112 *ifap = NULL;
114 if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
115 return (-1);
116 if ((sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
117 err = errno;
118 close(sock4);
119 errno = err;
120 return (-1);
123 retry:
124 /* Get all interfaces from SIOCGLIFCONF */
125 ret = getallifs(sock4, af, &buf, &numifs, (flags & ~LIFC_ENABLED));
126 if (ret != 0)
127 goto fail;
130 * Loop through the interfaces obtained from SIOCGLIFCOMF
131 * and retrieve the addresses, netmask and flags.
133 prev = NULL;
134 lifrp = buf;
135 for (n = 0; n < numifs; n++, lifrp++) {
137 /* Prepare for the ioctl call */
138 (void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
139 sizeof (lifrl.lifr_name));
140 lifr_af = lifrp->lifr_addr.ss_family;
141 if (af != AF_UNSPEC && lifr_af != af)
142 continue;
144 s = (lifr_af == AF_INET ? sock4 : sock6);
146 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
147 goto fail;
148 if ((flags & LIFC_ENABLED) && !(lifrl.lifr_flags & IFF_UP))
149 continue;
152 * Allocate the current list node. Each node contains data
153 * for one ifaddrs structure.
155 curr = calloc(1, sizeof (struct ifaddrs));
156 if (curr == NULL)
157 goto fail;
159 if (prev != NULL) {
160 prev->ifa_next = curr;
161 } else {
162 /* First node in the linked list */
163 *ifap = curr;
165 prev = curr;
167 curr->ifa_flags = lifrl.lifr_flags;
168 if ((curr->ifa_name = strdup(lifrp->lifr_name)) == NULL)
169 goto fail;
171 curr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
172 if (curr->ifa_addr == NULL)
173 goto fail;
174 (void) memcpy(curr->ifa_addr, &lifrp->lifr_addr,
175 sizeof (struct sockaddr_storage));
177 /* Get the netmask */
178 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifrl) < 0)
179 goto fail;
180 curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
181 if (curr->ifa_netmask == NULL)
182 goto fail;
183 (void) memcpy(curr->ifa_netmask, &lifrl.lifr_addr,
184 sizeof (struct sockaddr_storage));
186 /* Get the destination for a pt-pt interface */
187 if (curr->ifa_flags & IFF_POINTOPOINT) {
188 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifrl) < 0)
189 goto fail;
190 curr->ifa_dstaddr = malloc(
191 sizeof (struct sockaddr_storage));
192 if (curr->ifa_dstaddr == NULL)
193 goto fail;
194 (void) memcpy(curr->ifa_dstaddr, &lifrl.lifr_addr,
195 sizeof (struct sockaddr_storage));
196 } else if (curr->ifa_flags & IFF_BROADCAST) {
197 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifrl) < 0)
198 goto fail;
199 curr->ifa_broadaddr = malloc(
200 sizeof (struct sockaddr_storage));
201 if (curr->ifa_broadaddr == NULL)
202 goto fail;
203 (void) memcpy(curr->ifa_broadaddr, &lifrl.lifr_addr,
204 sizeof (struct sockaddr_storage));
208 free(buf);
209 close(sock4);
210 close(sock6);
211 return (0);
212 fail:
213 err = errno;
214 free(buf);
215 freeifaddrs(*ifap);
216 *ifap = NULL;
217 if (err == ENXIO)
218 goto retry;
219 close(sock4);
220 close(sock6);
221 errno = err;
222 return (-1);
226 * Do a SIOCGLIFCONF and store all the interfaces in `buf'.
229 getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs,
230 int64_t lifc_flags)
232 struct lifnum lifn;
233 struct lifconf lifc;
234 size_t bufsize;
235 char *tmp;
236 caddr_t *buf = (caddr_t *)lifr;
238 lifn.lifn_family = af;
239 lifn.lifn_flags = lifc_flags;
241 *buf = NULL;
242 retry:
243 if (ioctl(s, SIOCGLIFNUM, &lifn) < 0)
244 goto fail;
247 * When calculating the buffer size needed, add a small number
248 * of interfaces to those we counted. We do this to capture
249 * the interface status of potential interfaces which may have
250 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
252 bufsize = (lifn.lifn_count + 4) * sizeof (struct lifreq);
254 if ((tmp = realloc(*buf, bufsize)) == NULL)
255 goto fail;
257 *buf = tmp;
258 lifc.lifc_family = af;
259 lifc.lifc_flags = lifc_flags;
260 lifc.lifc_len = bufsize;
261 lifc.lifc_buf = *buf;
262 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
263 goto fail;
265 *numifs = lifc.lifc_len / sizeof (struct lifreq);
266 if (*numifs >= (lifn.lifn_count + 4)) {
268 * If every entry was filled, there are probably
269 * more interfaces than (lifn.lifn_count + 4).
270 * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to
271 * get all the interfaces.
273 goto retry;
275 return (0);
276 fail:
277 free(*buf);
278 *buf = NULL;
279 return (-1);