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 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