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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <inet/common.h>
35 #include <netinet/in.h>
36 #include <sys/sockio.h>
37 #include <sys/ioctl.h>
41 #define IPIF_SEPARATOR_CHAR ":"
44 * Given an interface name, this function retrives the associated
45 * index value. Returns index value if successful, zero otherwise.
46 * The length of the supplied interface name must be at most
50 if_nametoindex(const char *ifname
)
58 /* Make sure the given name is not NULL */
59 if ((ifname
== NULL
)||(*ifname
== '\0')) {
65 * Fill up the interface name in the ioctl
66 * request message. Make sure that the length of
67 * the given interface name <= (IF_NAMESIZE-1)
69 size
= strlen(ifname
);
70 if (size
> (IF_NAMESIZE
- 1)) {
75 strncpy(lifr
.lifr_name
, ifname
, size
+1);
77 /* Check the v4 interfaces first */
78 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
80 if (ioctl(s
, SIOCGLIFINDEX
, (caddr_t
)&lifr
) >= 0) {
82 return (lifr
.lifr_index
);
87 /* Check the v6 interface list */
88 s
= socket(AF_INET6
, SOCK_DGRAM
, 0);
92 if (ioctl(s
, SIOCGLIFINDEX
, (caddr_t
)&lifr
) < 0)
98 return (lifr
.lifr_index
);
102 * Given an index, this function returns the associated interface
103 * name in the supplied buffer ifname.
104 * Returns physical interface name if successful, NULL otherwise.
105 * The interface name returned will be at most IF_NAMESIZE-1 bytes.
108 if_indextoname(uint32_t ifindex
, char *ifname
)
116 struct lifreq
*lifrp
;
122 flags
= LIFC_NOXMIT
| LIFC_TEMPORARY
| LIFC_ALLZONES
| LIFC_UNDER_IPMP
;
124 /* A interface index of 0 is invalid */
130 s
= socket(AF_INET6
, SOCK_DGRAM
, 0);
132 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
138 /* Prepare to send a SIOCGLIFNUM request message */
139 lifn
.lifn_family
= AF_UNSPEC
;
140 lifn
.lifn_flags
= flags
;
141 if (ioctl(s
, SIOCGLIFNUM
, (char *)&lifn
) < 0) {
142 int save_err
= errno
;
149 * NOTE: "+ 10" sleaze mitigates new IP interfaces showing up between
150 * the SIOCGLIFNUM and the SIOCGLIFCONF.
152 numifs
= lifn
.lifn_count
+ 10;
155 * Provide enough buffer to obtain the interface
156 * list from the kernel as response to a SIOCGLIFCONF
160 bufsize
= numifs
* sizeof (struct lifreq
);
161 buf
= malloc(bufsize
);
163 int save_err
= errno
;
168 lifc
.lifc_family
= AF_UNSPEC
;
169 lifc
.lifc_flags
= flags
;
170 lifc
.lifc_len
= bufsize
;
172 if (ioctl(s
, SIOCGLIFCONF
, (char *)&lifc
) < 0) {
173 int save_err
= errno
;
180 lifrp
= lifc
.lifc_req
;
182 for (n
= lifc
.lifc_len
/ sizeof (struct lifreq
); n
> 0; n
--, lifrp
++) {
184 * Obtain the index value of each interface, and
185 * match to see if the retrived index value matches
186 * the given one. If so we return the corresponding
187 * device name of that interface.
191 index
= if_nametoindex(lifrp
->lifr_name
);
193 /* Oops the interface just disappeared */
195 if (index
== ifindex
) {
196 size
= strcspn(lifrp
->lifr_name
,
197 (char *)IPIF_SEPARATOR_CHAR
);
198 lifrp
->lifr_name
[size
] = '\0';
200 (void) strncpy(ifname
, lifrp
->lifr_name
, size
+ 1);
214 * This function returns all the interface names and indexes
216 struct if_nameindex
*
225 struct lifreq
*lifrp
;
231 struct if_nameindex
*interface_list
;
232 struct if_nameindex
*interface_entry
;
234 s
= socket(AF_INET6
, SOCK_DGRAM
, 0);
236 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
241 lifn
.lifn_family
= AF_UNSPEC
;
242 lifn
.lifn_flags
= LIFC_NOXMIT
| LIFC_TEMPORARY
| LIFC_ALLZONES
;
243 if (ioctl(s
, SIOCGLIFNUM
, (char *)&lifn
) < 0)
245 numifs
= lifn
.lifn_count
;
247 bufsize
= numifs
* sizeof (struct lifreq
);
248 buf
= malloc(bufsize
);
250 int save_err
= errno
;
255 lifc
.lifc_family
= AF_UNSPEC
;
256 lifc
.lifc_flags
= LIFC_NOXMIT
| LIFC_TEMPORARY
| LIFC_ALLZONES
;
257 lifc
.lifc_len
= bufsize
;
259 if (ioctl(s
, SIOCGLIFCONF
, (char *)&lifc
) < 0) {
260 int save_err
= errno
;
267 lifrp
= lifc
.lifc_req
;
270 /* Allocate the array of if_nameindex structure */
271 interface_list
= malloc((numifs
+ 1) * sizeof (struct if_nameindex
));
272 if (!interface_list
) {
273 int save_err
= errno
;
279 * Make sure that terminator structure automatically
280 * happens to be all zeroes.
282 bzero(interface_list
, ((numifs
+ 1) * sizeof (struct if_nameindex
)));
283 interface_entry
= interface_list
;
285 for (n
= numifs
; n
> 0; n
--, lifrp
++) {
288 size
= strcspn(lifrp
->lifr_name
, (char *)IPIF_SEPARATOR_CHAR
);
291 * Search the current array to see if this interface
292 * already exists. Only compare the physical name.
294 for (i
= 0; i
< physinterf_num
; i
++) {
295 if (strncmp(interface_entry
[i
].if_name
,
296 lifrp
->lifr_name
, size
) == 0) {
302 /* New one. Allocate an array element and fill it */
305 * Obtain the index value for the interface
307 interface_entry
[physinterf_num
].if_index
=
308 if_nametoindex(lifrp
->lifr_name
);
310 if (interface_entry
[physinterf_num
].if_index
== 0) {
311 /* The interface went away. Skip this entry. */
316 * Truncate the name to ensure that it represents
317 * a physical interface.
319 lifrp
->lifr_name
[size
] = '\0';
320 if ((interface_entry
[physinterf_num
].if_name
=
321 strdup(lifrp
->lifr_name
)) == NULL
) {
324 if_freenameindex(interface_list
);
335 /* Create the last one of the array */
336 interface_entry
[physinterf_num
].if_name
= NULL
;
337 interface_entry
[physinterf_num
].if_index
= 0;
339 /* Free up the excess array space */
341 interface_list
= realloc(interface_list
, ((physinterf_num
+ 1) *
342 sizeof (struct if_nameindex
)));
344 return (interface_list
);
348 * This function frees the the array that is created while
349 * the if_nameindex function.
352 if_freenameindex(struct if_nameindex
*ptr
)
354 struct if_nameindex
*p
;
359 /* First free the if_name member in each array element */
360 for (p
= ptr
; p
->if_name
!= NULL
; p
++)
363 /* Now free up the array space */