10406ceaaSmeem /*
2*e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
30406ceaaSmeem * Use is subject to license terms.
40406ceaaSmeem */
50406ceaaSmeem
60406ceaaSmeem /*
70406ceaaSmeem * Copyright (c) 1997
80406ceaaSmeem * The Regents of the University of California. All rights reserved.
90406ceaaSmeem *
100406ceaaSmeem * Redistribution and use in source and binary forms, with or without
110406ceaaSmeem * modification, are permitted provided that the following conditions
120406ceaaSmeem * are met:
130406ceaaSmeem * 1. Redistributions of source code must retain the above copyright
140406ceaaSmeem * notice, this list of conditions and the following disclaimer.
150406ceaaSmeem * 2. Redistributions in binary form must reproduce the above copyright
160406ceaaSmeem * notice, this list of conditions and the following disclaimer in the
170406ceaaSmeem * documentation and/or other materials provided with the distribution.
180406ceaaSmeem * 3. All advertising materials mentioning features or use of this software
190406ceaaSmeem * must display the following acknowledgement:
200406ceaaSmeem * This product includes software developed by the Computer Systems
210406ceaaSmeem * Engineering Group at Lawrence Berkeley Laboratory.
220406ceaaSmeem * 4. Neither the name of the University nor of the Laboratory may be used
230406ceaaSmeem * to endorse or promote products derived from this software without
240406ceaaSmeem * specific prior written permission.
250406ceaaSmeem *
260406ceaaSmeem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
270406ceaaSmeem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
280406ceaaSmeem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
290406ceaaSmeem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
300406ceaaSmeem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
310406ceaaSmeem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
320406ceaaSmeem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
330406ceaaSmeem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
340406ceaaSmeem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
350406ceaaSmeem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
360406ceaaSmeem * SUCH DAMAGE.
370406ceaaSmeem *
380406ceaaSmeem * @(#) $Header: ifaddrlist.c,v 1.2 97/04/22 13:31:05 leres Exp $ (LBL)
390406ceaaSmeem */
400406ceaaSmeem
410406ceaaSmeem #include <errno.h>
420406ceaaSmeem #include <libinetutil.h>
430406ceaaSmeem #include <stdio.h>
440406ceaaSmeem #include <stdlib.h>
450406ceaaSmeem #include <string.h>
460406ceaaSmeem #include <unistd.h>
470406ceaaSmeem #include <sys/socket.h>
480406ceaaSmeem #include <sys/sockio.h>
490406ceaaSmeem
500406ceaaSmeem /*
510406ceaaSmeem * See <libinetutil.h> for a description of the programming interface.
520406ceaaSmeem */
530406ceaaSmeem int
ifaddrlist(struct ifaddrlist ** ipaddrp,int family,uint_t flags,char * errbuf)54*e11c3f44Smeem ifaddrlist(struct ifaddrlist **ipaddrp, int family, uint_t flags, char *errbuf)
550406ceaaSmeem {
56*e11c3f44Smeem struct ifaddrlist *ifaddrlist = NULL, *al = NULL;
570406ceaaSmeem struct sockaddr_in *sin;
580406ceaaSmeem struct sockaddr_in6 *sin6;
590406ceaaSmeem struct lifconf lifc;
600406ceaaSmeem struct lifnum lifn;
610406ceaaSmeem struct lifreq *lifrp;
620406ceaaSmeem int i, count, nlifr;
630406ceaaSmeem int fd;
64*e11c3f44Smeem const char *opstr;
650406ceaaSmeem
66*e11c3f44Smeem (void) memset(&lifc, 0, sizeof (lifc));
670406ceaaSmeem if (family != AF_INET && family != AF_INET6) {
680406ceaaSmeem (void) strlcpy(errbuf, "invalid address family", ERRBUFSIZE);
690406ceaaSmeem return (-1);
700406ceaaSmeem }
710406ceaaSmeem
72*e11c3f44Smeem if ((fd = socket(family, SOCK_DGRAM, 0)) == -1) {
73*e11c3f44Smeem opstr = "socket";
74*e11c3f44Smeem goto fail;
750406ceaaSmeem }
760406ceaaSmeem
770406ceaaSmeem /*
780406ceaaSmeem * Get the number of network interfaces of type `family'.
790406ceaaSmeem */
800406ceaaSmeem lifn.lifn_family = family;
81*e11c3f44Smeem lifn.lifn_flags = flags;
820406ceaaSmeem again:
830406ceaaSmeem if (ioctl(fd, SIOCGLIFNUM, &lifn) == -1) {
84*e11c3f44Smeem opstr = "SIOCGLIFNUM";
85*e11c3f44Smeem goto fail;
860406ceaaSmeem }
870406ceaaSmeem
880406ceaaSmeem /*
890406ceaaSmeem * Pad the interface count to detect when additional interfaces have
900406ceaaSmeem * been configured between SIOCGLIFNUM and SIOCGLIFCONF.
910406ceaaSmeem */
920406ceaaSmeem lifn.lifn_count += 4;
930406ceaaSmeem
94*e11c3f44Smeem lifc.lifc_flags = flags;
950406ceaaSmeem lifc.lifc_family = family;
960406ceaaSmeem lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
97*e11c3f44Smeem if ((lifc.lifc_buf = realloc(lifc.lifc_buf, lifc.lifc_len)) == NULL) {
98*e11c3f44Smeem opstr = "realloc";
99*e11c3f44Smeem goto fail;
100*e11c3f44Smeem }
1010406ceaaSmeem
1020406ceaaSmeem if (ioctl(fd, SIOCGLIFCONF, &lifc) == -1) {
103*e11c3f44Smeem opstr = "SIOCGLIFCONF";
104*e11c3f44Smeem goto fail;
1050406ceaaSmeem }
1060406ceaaSmeem
1070406ceaaSmeem /*
1080406ceaaSmeem * If every lifr_req slot is taken, then additional interfaces must
1090406ceaaSmeem * have been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
1100406ceaaSmeem * Recalculate to make sure we didn't miss any interfaces.
1110406ceaaSmeem */
1120406ceaaSmeem nlifr = lifc.lifc_len / sizeof (struct lifreq);
1130406ceaaSmeem if (nlifr >= lifn.lifn_count)
1140406ceaaSmeem goto again;
1150406ceaaSmeem
1160406ceaaSmeem /*
1170406ceaaSmeem * Allocate the address list to return.
1180406ceaaSmeem */
119*e11c3f44Smeem if ((ifaddrlist = calloc(nlifr, sizeof (struct ifaddrlist))) == NULL) {
120*e11c3f44Smeem opstr = "calloc";
121*e11c3f44Smeem goto fail;
1220406ceaaSmeem }
1230406ceaaSmeem
1240406ceaaSmeem /*
1250406ceaaSmeem * Populate the address list by querying each underlying interface.
1260406ceaaSmeem * If a query ioctl returns ENXIO, then the interface must have been
1270406ceaaSmeem * removed after the SIOCGLIFCONF completed -- so we just ignore it.
1280406ceaaSmeem */
1290406ceaaSmeem al = ifaddrlist;
1300406ceaaSmeem count = 0;
1310406ceaaSmeem for (lifrp = lifc.lifc_req, i = 0; i < nlifr; i++, lifrp++) {
1320406ceaaSmeem (void) strlcpy(al->device, lifrp->lifr_name, LIFNAMSIZ);
1330406ceaaSmeem
1340406ceaaSmeem if (ioctl(fd, SIOCGLIFFLAGS, lifrp) == -1) {
1350406ceaaSmeem if (errno == ENXIO)
1360406ceaaSmeem continue;
137*e11c3f44Smeem opstr = "SIOCGLIFFLAGS";
1380406ceaaSmeem goto fail;
1390406ceaaSmeem }
1400406ceaaSmeem al->flags = lifrp->lifr_flags;
1410406ceaaSmeem
1420406ceaaSmeem if (ioctl(fd, SIOCGLIFINDEX, lifrp) == -1) {
1430406ceaaSmeem if (errno == ENXIO)
1440406ceaaSmeem continue;
145*e11c3f44Smeem opstr = "SIOCGLIFINDEX";
1460406ceaaSmeem goto fail;
1470406ceaaSmeem }
1480406ceaaSmeem al->index = lifrp->lifr_index;
1490406ceaaSmeem
1500406ceaaSmeem if (ioctl(fd, SIOCGLIFADDR, lifrp) == -1) {
1510406ceaaSmeem if (errno == ENXIO)
1520406ceaaSmeem continue;
153*e11c3f44Smeem opstr = "SIOCGLIFADDR";
1540406ceaaSmeem goto fail;
1550406ceaaSmeem }
1560406ceaaSmeem
1570406ceaaSmeem if (family == AF_INET) {
1580406ceaaSmeem sin = (struct sockaddr_in *)&lifrp->lifr_addr;
1590406ceaaSmeem al->addr.addr = sin->sin_addr;
1600406ceaaSmeem } else {
1610406ceaaSmeem sin6 = (struct sockaddr_in6 *)&lifrp->lifr_addr;
1620406ceaaSmeem al->addr.addr6 = sin6->sin6_addr;
1630406ceaaSmeem }
1640406ceaaSmeem al++;
1650406ceaaSmeem count++;
1660406ceaaSmeem }
1670406ceaaSmeem
1680406ceaaSmeem (void) close(fd);
169*e11c3f44Smeem free(lifc.lifc_buf);
1700406ceaaSmeem if (count == 0) {
1710406ceaaSmeem free(ifaddrlist);
1720406ceaaSmeem *ipaddrp = NULL;
1730406ceaaSmeem return (0);
1740406ceaaSmeem }
1750406ceaaSmeem
1760406ceaaSmeem *ipaddrp = ifaddrlist;
1770406ceaaSmeem return (count);
1780406ceaaSmeem fail:
179*e11c3f44Smeem if (al == NULL) {
180*e11c3f44Smeem (void) snprintf(errbuf, ERRBUFSIZE, "%s: %s", opstr,
1810406ceaaSmeem strerror(errno));
182*e11c3f44Smeem } else {
183*e11c3f44Smeem (void) snprintf(errbuf, ERRBUFSIZE, "%s: %s: %s", opstr,
184*e11c3f44Smeem al->device, strerror(errno));
185*e11c3f44Smeem }
186*e11c3f44Smeem free(lifc.lifc_buf);
1870406ceaaSmeem free(ifaddrlist);
1880406ceaaSmeem (void) close(fd);
1890406ceaaSmeem return (-1);
1900406ceaaSmeem }
191