xref: /titanic_52/usr/src/lib/libinetutil/common/ifaddrlist.c (revision e11c3f44f531fdff80941ce57c065d2ae861cefc)
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