xref: /onnv-gate/usr/src/lib/libinetutil/common/ifaddrlist.c (revision 8485:633e5b5eb268)
11254Smeem /*
2*8485SPeter.Memishian@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
31254Smeem  * Use is subject to license terms.
41254Smeem  */
51254Smeem 
61254Smeem /*
71254Smeem  * Copyright (c) 1997
81254Smeem  *	The Regents of the University of California.  All rights reserved.
91254Smeem  *
101254Smeem  * Redistribution and use in source and binary forms, with or without
111254Smeem  * modification, are permitted provided that the following conditions
121254Smeem  * are met:
131254Smeem  * 1. Redistributions of source code must retain the above copyright
141254Smeem  *    notice, this list of conditions and the following disclaimer.
151254Smeem  * 2. Redistributions in binary form must reproduce the above copyright
161254Smeem  *    notice, this list of conditions and the following disclaimer in the
171254Smeem  *    documentation and/or other materials provided with the distribution.
181254Smeem  * 3. All advertising materials mentioning features or use of this software
191254Smeem  *    must display the following acknowledgement:
201254Smeem  *	This product includes software developed by the Computer Systems
211254Smeem  *	Engineering Group at Lawrence Berkeley Laboratory.
221254Smeem  * 4. Neither the name of the University nor of the Laboratory may be used
231254Smeem  *    to endorse or promote products derived from this software without
241254Smeem  *    specific prior written permission.
251254Smeem  *
261254Smeem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271254Smeem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281254Smeem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291254Smeem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301254Smeem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311254Smeem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321254Smeem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331254Smeem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341254Smeem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351254Smeem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361254Smeem  * SUCH DAMAGE.
371254Smeem  *
381254Smeem  * @(#) $Header: ifaddrlist.c,v 1.2 97/04/22 13:31:05 leres Exp $ (LBL)
391254Smeem  */
401254Smeem 
411254Smeem #include <errno.h>
421254Smeem #include <libinetutil.h>
431254Smeem #include <stdio.h>
441254Smeem #include <stdlib.h>
451254Smeem #include <string.h>
461254Smeem #include <unistd.h>
471254Smeem #include <sys/socket.h>
481254Smeem #include <sys/sockio.h>
491254Smeem 
501254Smeem /*
511254Smeem  * See <libinetutil.h> for a description of the programming interface.
521254Smeem  */
531254Smeem int
ifaddrlist(struct ifaddrlist ** ipaddrp,int family,uint_t flags,char * errbuf)54*8485SPeter.Memishian@Sun.COM ifaddrlist(struct ifaddrlist **ipaddrp, int family, uint_t flags, char *errbuf)
551254Smeem {
56*8485SPeter.Memishian@Sun.COM 	struct ifaddrlist	*ifaddrlist = NULL, *al = NULL;
571254Smeem 	struct sockaddr_in	*sin;
581254Smeem 	struct sockaddr_in6	*sin6;
591254Smeem 	struct lifconf		lifc;
601254Smeem 	struct lifnum		lifn;
611254Smeem 	struct lifreq		*lifrp;
621254Smeem 	int			i, count, nlifr;
631254Smeem 	int			fd;
64*8485SPeter.Memishian@Sun.COM 	const char		*opstr;
651254Smeem 
66*8485SPeter.Memishian@Sun.COM 	(void) memset(&lifc, 0, sizeof (lifc));
671254Smeem 	if (family != AF_INET && family != AF_INET6) {
681254Smeem 		(void) strlcpy(errbuf, "invalid address family", ERRBUFSIZE);
691254Smeem 		return (-1);
701254Smeem 	}
711254Smeem 
72*8485SPeter.Memishian@Sun.COM 	if ((fd = socket(family, SOCK_DGRAM, 0)) == -1) {
73*8485SPeter.Memishian@Sun.COM 		opstr = "socket";
74*8485SPeter.Memishian@Sun.COM 		goto fail;
751254Smeem 	}
761254Smeem 
771254Smeem 	/*
781254Smeem 	 * Get the number of network interfaces of type `family'.
791254Smeem 	 */
801254Smeem 	lifn.lifn_family = family;
81*8485SPeter.Memishian@Sun.COM 	lifn.lifn_flags = flags;
821254Smeem again:
831254Smeem 	if (ioctl(fd, SIOCGLIFNUM, &lifn) == -1) {
84*8485SPeter.Memishian@Sun.COM 		opstr = "SIOCGLIFNUM";
85*8485SPeter.Memishian@Sun.COM 		goto fail;
861254Smeem 	}
871254Smeem 
881254Smeem 	/*
891254Smeem 	 * Pad the interface count to detect when additional interfaces have
901254Smeem 	 * been configured between SIOCGLIFNUM and SIOCGLIFCONF.
911254Smeem 	 */
921254Smeem 	lifn.lifn_count += 4;
931254Smeem 
94*8485SPeter.Memishian@Sun.COM 	lifc.lifc_flags = flags;
951254Smeem 	lifc.lifc_family = family;
961254Smeem 	lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
97*8485SPeter.Memishian@Sun.COM 	if ((lifc.lifc_buf = realloc(lifc.lifc_buf, lifc.lifc_len)) == NULL) {
98*8485SPeter.Memishian@Sun.COM 		opstr = "realloc";
99*8485SPeter.Memishian@Sun.COM 		goto fail;
100*8485SPeter.Memishian@Sun.COM 	}
1011254Smeem 
1021254Smeem 	if (ioctl(fd, SIOCGLIFCONF, &lifc) == -1) {
103*8485SPeter.Memishian@Sun.COM 		opstr = "SIOCGLIFCONF";
104*8485SPeter.Memishian@Sun.COM 		goto fail;
1051254Smeem 	}
1061254Smeem 
1071254Smeem 	/*
1081254Smeem 	 * If every lifr_req slot is taken, then additional interfaces must
1091254Smeem 	 * have been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
1101254Smeem 	 * Recalculate to make sure we didn't miss any interfaces.
1111254Smeem 	 */
1121254Smeem 	nlifr = lifc.lifc_len / sizeof (struct lifreq);
1131254Smeem 	if (nlifr >= lifn.lifn_count)
1141254Smeem 		goto again;
1151254Smeem 
1161254Smeem 	/*
1171254Smeem 	 * Allocate the address list to return.
1181254Smeem 	 */
119*8485SPeter.Memishian@Sun.COM 	if ((ifaddrlist = calloc(nlifr, sizeof (struct ifaddrlist))) == NULL) {
120*8485SPeter.Memishian@Sun.COM 		opstr = "calloc";
121*8485SPeter.Memishian@Sun.COM 		goto fail;
1221254Smeem 	}
1231254Smeem 
1241254Smeem 	/*
1251254Smeem 	 * Populate the address list by querying each underlying interface.
1261254Smeem 	 * If a query ioctl returns ENXIO, then the interface must have been
1271254Smeem 	 * removed after the SIOCGLIFCONF completed -- so we just ignore it.
1281254Smeem 	 */
1291254Smeem 	al = ifaddrlist;
1301254Smeem 	count = 0;
1311254Smeem 	for (lifrp = lifc.lifc_req, i = 0; i < nlifr; i++, lifrp++) {
1321254Smeem 		(void) strlcpy(al->device, lifrp->lifr_name, LIFNAMSIZ);
1331254Smeem 
1341254Smeem 		if (ioctl(fd, SIOCGLIFFLAGS, lifrp) == -1) {
1351254Smeem 			if (errno == ENXIO)
1361254Smeem 				continue;
137*8485SPeter.Memishian@Sun.COM 			opstr = "SIOCGLIFFLAGS";
1381254Smeem 			goto fail;
1391254Smeem 		}
1401254Smeem 		al->flags = lifrp->lifr_flags;
1411254Smeem 
1421254Smeem 		if (ioctl(fd, SIOCGLIFINDEX, lifrp) == -1) {
1431254Smeem 			if (errno == ENXIO)
1441254Smeem 				continue;
145*8485SPeter.Memishian@Sun.COM 			opstr = "SIOCGLIFINDEX";
1461254Smeem 			goto fail;
1471254Smeem 		}
1481254Smeem 		al->index = lifrp->lifr_index;
1491254Smeem 
1501254Smeem 		if (ioctl(fd, SIOCGLIFADDR, lifrp) == -1) {
1511254Smeem 			if (errno == ENXIO)
1521254Smeem 				continue;
153*8485SPeter.Memishian@Sun.COM 			opstr = "SIOCGLIFADDR";
1541254Smeem 			goto fail;
1551254Smeem 		}
1561254Smeem 
1571254Smeem 		if (family == AF_INET) {
1581254Smeem 			sin = (struct sockaddr_in *)&lifrp->lifr_addr;
1591254Smeem 			al->addr.addr = sin->sin_addr;
1601254Smeem 		} else {
1611254Smeem 			sin6 = (struct sockaddr_in6 *)&lifrp->lifr_addr;
1621254Smeem 			al->addr.addr6 = sin6->sin6_addr;
1631254Smeem 		}
1641254Smeem 		al++;
1651254Smeem 		count++;
1661254Smeem 	}
1671254Smeem 
1681254Smeem 	(void) close(fd);
169*8485SPeter.Memishian@Sun.COM 	free(lifc.lifc_buf);
1701254Smeem 	if (count == 0) {
1711254Smeem 		free(ifaddrlist);
1721254Smeem 		*ipaddrp = NULL;
1731254Smeem 		return (0);
1741254Smeem 	}
1751254Smeem 
1761254Smeem 	*ipaddrp = ifaddrlist;
1771254Smeem 	return (count);
1781254Smeem fail:
179*8485SPeter.Memishian@Sun.COM 	if (al == NULL) {
180*8485SPeter.Memishian@Sun.COM 		(void) snprintf(errbuf, ERRBUFSIZE, "%s: %s", opstr,
181*8485SPeter.Memishian@Sun.COM 		    strerror(errno));
182*8485SPeter.Memishian@Sun.COM 	} else {
183*8485SPeter.Memishian@Sun.COM 		(void) snprintf(errbuf, ERRBUFSIZE, "%s: %s: %s", opstr,
184*8485SPeter.Memishian@Sun.COM 		    al->device, strerror(errno));
185*8485SPeter.Memishian@Sun.COM 	}
186*8485SPeter.Memishian@Sun.COM 	free(lifc.lifc_buf);
1871254Smeem 	free(ifaddrlist);
1881254Smeem 	(void) close(fd);
1891254Smeem 	return (-1);
1901254Smeem }
191