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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
27 #include <nss_dbdefs.h>
28 #include <netinet/in.h>
29 #include <sys/socket.h>
32 #include <sys/sockio.h>
33 #include <sys/types.h>
37 #include <libsocket_priv.h>
40 * Create a linked list of `struct ifaddrs' structures, one for each
41 * address that is UP. If successful, store the list in *ifap and
42 * return 0. On errors, return -1 and set `errno'.
44 * The storage returned in *ifap is allocated dynamically and can
45 * only be properly freed by passing it to `freeifaddrs'.
48 getifaddrs(struct ifaddrs
**ifap
)
59 err
= getallifaddrs(AF_UNSPEC
, ifap
, LIFC_ENABLED
);
61 for (curr
= *ifap
; curr
!= NULL
; curr
= curr
->ifa_next
) {
62 if ((cp
= strchr(curr
->ifa_name
, ':')) != NULL
)
70 freeifaddrs(struct ifaddrs
*ifa
)
79 free(curr
->ifa_netmask
);
80 free(curr
->ifa_dstaddr
);
86 * Returns all addresses configured on the system. If flags contain
87 * LIFC_ENABLED, only the addresses that are UP are returned.
88 * Address list that is returned by this function must be freed
89 * using freeifaddrs().
92 getallifaddrs(sa_family_t af
, struct ifaddrs
**ifap
, int64_t flags
)
94 struct lifreq
*buf
= NULL
;
99 struct ifaddrs
*curr
, *prev
;
105 if ((sock4
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
107 if ((sock6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
115 /* Get all interfaces from SIOCGLIFCONF */
116 ret
= getallifs(sock4
, af
, &buf
, &numifs
, (flags
& ~LIFC_ENABLED
));
121 * Loop through the interfaces obtained from SIOCGLIFCOMF
122 * and retrieve the addresses, netmask and flags.
127 for (n
= 0; n
< numifs
; n
++, lifrp
++) {
129 /* Prepare for the ioctl call */
130 (void) strncpy(lifrl
.lifr_name
, lifrp
->lifr_name
,
131 sizeof (lifrl
.lifr_name
));
132 lifr_af
= lifrp
->lifr_addr
.ss_family
;
133 if (af
!= AF_UNSPEC
&& lifr_af
!= af
)
136 s
= (lifr_af
== AF_INET
? sock4
: sock6
);
138 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifrl
) < 0)
140 if ((flags
& LIFC_ENABLED
) && !(lifrl
.lifr_flags
& IFF_UP
))
144 * Allocate the current list node. Each node contains data
145 * for one ifaddrs structure.
147 curr
= calloc(1, sizeof (struct ifaddrs
));
152 prev
->ifa_next
= curr
;
154 /* First node in the linked list */
159 curr
->ifa_flags
= lifrl
.lifr_flags
;
160 if ((curr
->ifa_name
= strdup(lifrp
->lifr_name
)) == NULL
)
163 curr
->ifa_addr
= malloc(sizeof (struct sockaddr_storage
));
164 if (curr
->ifa_addr
== NULL
)
166 (void) memcpy(curr
->ifa_addr
, &lifrp
->lifr_addr
,
167 sizeof (struct sockaddr_storage
));
169 /* Get the netmask */
170 if (ioctl(s
, SIOCGLIFNETMASK
, (caddr_t
)&lifrl
) < 0)
172 curr
->ifa_netmask
= malloc(sizeof (struct sockaddr_storage
));
173 if (curr
->ifa_netmask
== NULL
)
175 (void) memcpy(curr
->ifa_netmask
, &lifrl
.lifr_addr
,
176 sizeof (struct sockaddr_storage
));
178 /* Get the destination for a pt-pt interface */
179 if (curr
->ifa_flags
& IFF_POINTOPOINT
) {
180 if (ioctl(s
, SIOCGLIFDSTADDR
, (caddr_t
)&lifrl
) < 0)
182 curr
->ifa_dstaddr
= malloc(
183 sizeof (struct sockaddr_storage
));
184 if (curr
->ifa_dstaddr
== NULL
)
186 (void) memcpy(curr
->ifa_dstaddr
, &lifrl
.lifr_addr
,
187 sizeof (struct sockaddr_storage
));
188 } else if (curr
->ifa_flags
& IFF_BROADCAST
) {
189 if (ioctl(s
, SIOCGLIFBRDADDR
, (caddr_t
)&lifrl
) < 0)
191 curr
->ifa_broadaddr
= malloc(
192 sizeof (struct sockaddr_storage
));
193 if (curr
->ifa_broadaddr
== NULL
)
195 (void) memcpy(curr
->ifa_broadaddr
, &lifrl
.lifr_addr
,
196 sizeof (struct sockaddr_storage
));
218 * Do a SIOCGLIFCONF and store all the interfaces in `buf'.
221 getallifs(int s
, sa_family_t af
, struct lifreq
**lifr
, int *numifs
,
228 caddr_t
*buf
= (caddr_t
*)lifr
;
230 lifn
.lifn_family
= af
;
231 lifn
.lifn_flags
= lifc_flags
;
235 if (ioctl(s
, SIOCGLIFNUM
, &lifn
) < 0)
239 * When calculating the buffer size needed, add a small number
240 * of interfaces to those we counted. We do this to capture
241 * the interface status of potential interfaces which may have
242 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
244 bufsize
= (lifn
.lifn_count
+ 4) * sizeof (struct lifreq
);
246 if ((tmp
= realloc(*buf
, bufsize
)) == NULL
)
250 lifc
.lifc_family
= af
;
251 lifc
.lifc_flags
= lifc_flags
;
252 lifc
.lifc_len
= bufsize
;
253 lifc
.lifc_buf
= *buf
;
254 if (ioctl(s
, SIOCGLIFCONF
, (char *)&lifc
) < 0)
257 *numifs
= lifc
.lifc_len
/ sizeof (struct lifreq
);
258 if (*numifs
>= (lifn
.lifn_count
+ 4)) {
260 * If every entry was filled, there are probably
261 * more interfaces than (lifn.lifn_count + 4).
262 * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to
263 * get all the interfaces.