16e91bba0SGirish Moodalbail /*
26e91bba0SGirish Moodalbail  * CDDL HEADER START
36e91bba0SGirish Moodalbail  *
46e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
56e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
66e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
76e91bba0SGirish Moodalbail  *
86e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
106e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
116e91bba0SGirish Moodalbail  * and limitations under the License.
126e91bba0SGirish Moodalbail  *
136e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
146e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
166e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
176e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
186e91bba0SGirish Moodalbail  *
196e91bba0SGirish Moodalbail  * CDDL HEADER END
206e91bba0SGirish Moodalbail  */
216e91bba0SGirish Moodalbail 
226e91bba0SGirish Moodalbail /*
2364639aafSDarren Reed  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2451c62b7bSAndrew Stormont  * Copyright 2017 RackTop Systems.
253ee59242SSebastian Wiedenroth  * Copyright 2022 Sebastian Wiedenroth
266e91bba0SGirish Moodalbail  */
276e91bba0SGirish Moodalbail 
286e91bba0SGirish Moodalbail #include <netdb.h>
296e91bba0SGirish Moodalbail #include <nss_dbdefs.h>
306e91bba0SGirish Moodalbail #include <netinet/in.h>
316e91bba0SGirish Moodalbail #include <sys/socket.h>
326e91bba0SGirish Moodalbail #include <string.h>
333ee59242SSebastian Wiedenroth #include <strings.h>
346e91bba0SGirish Moodalbail #include <stdio.h>
356e91bba0SGirish Moodalbail #include <sys/sockio.h>
366e91bba0SGirish Moodalbail #include <sys/types.h>
376e91bba0SGirish Moodalbail #include <stdlib.h>
386e91bba0SGirish Moodalbail #include <net/if.h>
393ee59242SSebastian Wiedenroth #include <door.h>
403ee59242SSebastian Wiedenroth #include <fcntl.h>
413ee59242SSebastian Wiedenroth #include <sys/mman.h>
423ee59242SSebastian Wiedenroth #include <sys/dld_ioc.h>
433ee59242SSebastian Wiedenroth #include <sys/dld.h>
443ee59242SSebastian Wiedenroth #include <sys/dls_mgmt.h>
453ee59242SSebastian Wiedenroth #include <sys/mac.h>
463ee59242SSebastian Wiedenroth #include <sys/dlpi.h>
473ee59242SSebastian Wiedenroth #include <net/if_types.h>
486e91bba0SGirish Moodalbail #include <ifaddrs.h>
496e91bba0SGirish Moodalbail #include <libsocket_priv.h>
506e91bba0SGirish Moodalbail 
513ee59242SSebastian Wiedenroth /*
523ee59242SSebastian Wiedenroth  * <ifaddrs.h> directs folks towards our internal symbol, __getifaddrs. This
533ee59242SSebastian Wiedenroth  * means we cannot name the original symbol 'getifaddrs' here or it will be
543ee59242SSebastian Wiedenroth  * renamed. Instead, we use another redefine_extname to take care of this. Note,
553ee59242SSebastian Wiedenroth  * the extern declaration is required as gcc and others will only apply this for
563ee59242SSebastian Wiedenroth  * things they see an extern declaration for.
573ee59242SSebastian Wiedenroth  */
583ee59242SSebastian Wiedenroth #pragma redefine_extname getifaddrs_old getifaddrs
593ee59242SSebastian Wiedenroth extern int getifaddrs_old(struct ifaddrs **);
603ee59242SSebastian Wiedenroth 
616e91bba0SGirish Moodalbail /*
626e91bba0SGirish Moodalbail  * Create a linked list of `struct ifaddrs' structures, one for each
636e91bba0SGirish Moodalbail  * address that is UP. If successful, store the list in *ifap and
646e91bba0SGirish Moodalbail  * return 0.  On errors, return -1 and set `errno'.
656e91bba0SGirish Moodalbail  *
666e91bba0SGirish Moodalbail  * The storage returned in *ifap is allocated dynamically and can
676e91bba0SGirish Moodalbail  * only be properly freed by passing it to `freeifaddrs'.
686e91bba0SGirish Moodalbail  */
696e91bba0SGirish Moodalbail int
_getifaddrs(struct ifaddrs ** ifap,boolean_t can_handle_links)703ee59242SSebastian Wiedenroth _getifaddrs(struct ifaddrs **ifap, boolean_t can_handle_links)
716e91bba0SGirish Moodalbail {
726e91bba0SGirish Moodalbail 	int		err;
736e91bba0SGirish Moodalbail 	char		*cp;
746e91bba0SGirish Moodalbail 	struct ifaddrs	*curr;
756e91bba0SGirish Moodalbail 
766e91bba0SGirish Moodalbail 	if (ifap == NULL) {
776e91bba0SGirish Moodalbail 		errno = EINVAL;
786e91bba0SGirish Moodalbail 		return (-1);
796e91bba0SGirish Moodalbail 	}
806e91bba0SGirish Moodalbail 	*ifap = NULL;
813ee59242SSebastian Wiedenroth 
823ee59242SSebastian Wiedenroth 	if (can_handle_links) {
833ee59242SSebastian Wiedenroth 		err = getallifaddrs(AF_UNSPEC, ifap, LIFC_ENABLED);
843ee59242SSebastian Wiedenroth 	} else {
853ee59242SSebastian Wiedenroth 		err = getallifaddrs(AF_INET, ifap, LIFC_ENABLED);
863ee59242SSebastian Wiedenroth 		if (err != 0)
873ee59242SSebastian Wiedenroth 			return (err);
883ee59242SSebastian Wiedenroth 
893ee59242SSebastian Wiedenroth 		/* Find end of the list to append to */
903ee59242SSebastian Wiedenroth 		curr = *ifap;
913ee59242SSebastian Wiedenroth 		while (curr && curr->ifa_next) {
923ee59242SSebastian Wiedenroth 			curr = curr->ifa_next;
936e91bba0SGirish Moodalbail 		}
943ee59242SSebastian Wiedenroth 
953ee59242SSebastian Wiedenroth 		err = getallifaddrs(AF_INET6, curr ? &curr->ifa_next : ifap,
963ee59242SSebastian Wiedenroth 		    LIFC_ENABLED);
973ee59242SSebastian Wiedenroth 	}
983ee59242SSebastian Wiedenroth 
993ee59242SSebastian Wiedenroth 	if (err != 0)
1003ee59242SSebastian Wiedenroth 		return (err);
1013ee59242SSebastian Wiedenroth 
1023ee59242SSebastian Wiedenroth 	for (curr = *ifap; curr != NULL; curr = curr->ifa_next) {
1033ee59242SSebastian Wiedenroth 		if ((cp = strchr(curr->ifa_name, ':')) != NULL)
1043ee59242SSebastian Wiedenroth 			*cp = '\0';
1056e91bba0SGirish Moodalbail 	}
1063ee59242SSebastian Wiedenroth 
1073ee59242SSebastian Wiedenroth 	return (0);
1083ee59242SSebastian Wiedenroth }
1093ee59242SSebastian Wiedenroth 
1103ee59242SSebastian Wiedenroth /*
1113ee59242SSebastian Wiedenroth  * Legacy symbol
1123ee59242SSebastian Wiedenroth  * For a long time getifaddrs() only returned AF_INET and AF_INET6 entries.
1133ee59242SSebastian Wiedenroth  * Some consumers came to expect that no other address family may be returned.
1143ee59242SSebastian Wiedenroth  * To prevent existing binaries that can't handle AF_LINK entries from breaking
1153ee59242SSebastian Wiedenroth  * this symbol is kept around. Consumers that want the fixed behaviour need to
1163ee59242SSebastian Wiedenroth  * recompile and link to the fixed symbol.
1173ee59242SSebastian Wiedenroth  */
1183ee59242SSebastian Wiedenroth int
getifaddrs_old(struct ifaddrs ** ifap)1193ee59242SSebastian Wiedenroth getifaddrs_old(struct ifaddrs **ifap)
1203ee59242SSebastian Wiedenroth {
1213ee59242SSebastian Wiedenroth 	return (_getifaddrs(ifap, B_FALSE));
1223ee59242SSebastian Wiedenroth }
1233ee59242SSebastian Wiedenroth 
1243ee59242SSebastian Wiedenroth /*
1253ee59242SSebastian Wiedenroth  * Current symbol
1263ee59242SSebastian Wiedenroth  * May return AF_INET, AF_INET6 and AF_LINK entries
1273ee59242SSebastian Wiedenroth  */
1283ee59242SSebastian Wiedenroth int
__getifaddrs(struct ifaddrs ** ifap)1293ee59242SSebastian Wiedenroth __getifaddrs(struct ifaddrs **ifap)
1303ee59242SSebastian Wiedenroth {
1313ee59242SSebastian Wiedenroth 	return (_getifaddrs(ifap, B_TRUE));
1326e91bba0SGirish Moodalbail }
1336e91bba0SGirish Moodalbail 
1346e91bba0SGirish Moodalbail void
freeifaddrs(struct ifaddrs * ifa)1356e91bba0SGirish Moodalbail freeifaddrs(struct ifaddrs *ifa)
1366e91bba0SGirish Moodalbail {
1376e91bba0SGirish Moodalbail 	struct ifaddrs *curr;
1386e91bba0SGirish Moodalbail 
1396e91bba0SGirish Moodalbail 	while (ifa != NULL) {
1406e91bba0SGirish Moodalbail 		curr = ifa;
1416e91bba0SGirish Moodalbail 		ifa = ifa->ifa_next;
1426e91bba0SGirish Moodalbail 		free(curr->ifa_name);
1436e91bba0SGirish Moodalbail 		free(curr->ifa_addr);
1446e91bba0SGirish Moodalbail 		free(curr->ifa_netmask);
1456e91bba0SGirish Moodalbail 		free(curr->ifa_dstaddr);
1463ee59242SSebastian Wiedenroth 		free(curr->ifa_data);
1476e91bba0SGirish Moodalbail 		free(curr);
1486e91bba0SGirish Moodalbail 	}
1496e91bba0SGirish Moodalbail }
1506e91bba0SGirish Moodalbail 
1513ee59242SSebastian Wiedenroth static uint_t
dlpi_iftype(uint_t dlpitype)1523ee59242SSebastian Wiedenroth dlpi_iftype(uint_t dlpitype)
1533ee59242SSebastian Wiedenroth {
1543ee59242SSebastian Wiedenroth 	switch (dlpitype) {
1553ee59242SSebastian Wiedenroth 	case DL_ETHER:
1563ee59242SSebastian Wiedenroth 		return (IFT_ETHER);
1573ee59242SSebastian Wiedenroth 
1583ee59242SSebastian Wiedenroth 	case DL_ATM:
1593ee59242SSebastian Wiedenroth 		return (IFT_ATM);
1603ee59242SSebastian Wiedenroth 
1613ee59242SSebastian Wiedenroth 	case DL_CSMACD:
1623ee59242SSebastian Wiedenroth 		return (IFT_ISO88023);
1633ee59242SSebastian Wiedenroth 
1643ee59242SSebastian Wiedenroth 	case DL_TPB:
1653ee59242SSebastian Wiedenroth 		return (IFT_ISO88024);
1663ee59242SSebastian Wiedenroth 
1673ee59242SSebastian Wiedenroth 	case DL_TPR:
1683ee59242SSebastian Wiedenroth 		return (IFT_ISO88025);
1693ee59242SSebastian Wiedenroth 
1703ee59242SSebastian Wiedenroth 	case DL_FDDI:
1713ee59242SSebastian Wiedenroth 		return (IFT_FDDI);
1723ee59242SSebastian Wiedenroth 
1733ee59242SSebastian Wiedenroth 	case DL_IB:
1743ee59242SSebastian Wiedenroth 		return (IFT_IB);
1753ee59242SSebastian Wiedenroth 
1763ee59242SSebastian Wiedenroth 	case DL_OTHER:
1773ee59242SSebastian Wiedenroth 		return (IFT_OTHER);
1783ee59242SSebastian Wiedenroth 	}
1793ee59242SSebastian Wiedenroth 
1803ee59242SSebastian Wiedenroth 	return (IFT_OTHER);
1813ee59242SSebastian Wiedenroth }
1823ee59242SSebastian Wiedenroth 
1833ee59242SSebastian Wiedenroth /*
1843ee59242SSebastian Wiedenroth  * Make a door call to dlmgmtd.
1853ee59242SSebastian Wiedenroth  * If successful the result is stored in rbuf and 0 returned.
1863ee59242SSebastian Wiedenroth  * On errors, return -1 and set `errno'.
1873ee59242SSebastian Wiedenroth  */
1883ee59242SSebastian Wiedenroth static int
dl_door_call(int door_fd,void * arg,size_t asize,void * rbuf,size_t * rsizep)1893ee59242SSebastian Wiedenroth dl_door_call(int door_fd, void *arg, size_t asize, void *rbuf, size_t *rsizep)
1903ee59242SSebastian Wiedenroth {
1913ee59242SSebastian Wiedenroth 	int err;
1923ee59242SSebastian Wiedenroth 	door_arg_t	darg;
1933ee59242SSebastian Wiedenroth 	darg.data_ptr	= arg;
1943ee59242SSebastian Wiedenroth 	darg.data_size	= asize;
1953ee59242SSebastian Wiedenroth 	darg.desc_ptr	= NULL;
1963ee59242SSebastian Wiedenroth 	darg.desc_num	= 0;
1973ee59242SSebastian Wiedenroth 	darg.rbuf	= rbuf;
1983ee59242SSebastian Wiedenroth 	darg.rsize	= *rsizep;
1993ee59242SSebastian Wiedenroth 
2003ee59242SSebastian Wiedenroth 	if (door_call(door_fd, &darg) == -1) {
2013ee59242SSebastian Wiedenroth 		return (-1);
2023ee59242SSebastian Wiedenroth 	}
2033ee59242SSebastian Wiedenroth 
2043ee59242SSebastian Wiedenroth 	if (darg.rbuf != rbuf) {
2053ee59242SSebastian Wiedenroth 		/*
2063ee59242SSebastian Wiedenroth 		 * The size of the input rbuf was not big enough so that
2073ee59242SSebastian Wiedenroth 		 * the door allocated the rbuf itself. In this case, return
2083ee59242SSebastian Wiedenroth 		 * the required size to the caller.
2093ee59242SSebastian Wiedenroth 		 */
2103ee59242SSebastian Wiedenroth 		err = errno;
2113ee59242SSebastian Wiedenroth 		(void) munmap(darg.rbuf, darg.rsize);
2123ee59242SSebastian Wiedenroth 		*rsizep = darg.rsize;
2133ee59242SSebastian Wiedenroth 		errno = err;
2143ee59242SSebastian Wiedenroth 		return (-1);
2153ee59242SSebastian Wiedenroth 	} else if (darg.rsize != *rsizep) {
2163ee59242SSebastian Wiedenroth 		return (-1);
2173ee59242SSebastian Wiedenroth 	}
2183ee59242SSebastian Wiedenroth 	return (0);
2193ee59242SSebastian Wiedenroth }
2203ee59242SSebastian Wiedenroth 
2213ee59242SSebastian Wiedenroth 
2223ee59242SSebastian Wiedenroth /*
2233ee59242SSebastian Wiedenroth  * Get the name from dlmgmtd by linkid.
2243ee59242SSebastian Wiedenroth  * If successful the result is stored in name_retval and 0 returned.
2253ee59242SSebastian Wiedenroth  * On errors, return -1 and set `errno'.
2263ee59242SSebastian Wiedenroth  */
2273ee59242SSebastian Wiedenroth static int
dl_get_name(int door_fd,datalink_id_t linkid,dlmgmt_getname_retval_t * name_retval)2283ee59242SSebastian Wiedenroth dl_get_name(int door_fd, datalink_id_t linkid,
2293ee59242SSebastian Wiedenroth     dlmgmt_getname_retval_t *name_retval)
2303ee59242SSebastian Wiedenroth {
2313ee59242SSebastian Wiedenroth 	size_t name_sz = sizeof (*name_retval);
2323ee59242SSebastian Wiedenroth 	dlmgmt_door_getname_t getname;
2333ee59242SSebastian Wiedenroth 	bzero(&getname, sizeof (dlmgmt_door_getname_t));
2343ee59242SSebastian Wiedenroth 	getname.ld_cmd = DLMGMT_CMD_GETNAME;
2353ee59242SSebastian Wiedenroth 	getname.ld_linkid = linkid;
2363ee59242SSebastian Wiedenroth 
2373ee59242SSebastian Wiedenroth 	if (dl_door_call(door_fd, &getname, sizeof (getname), name_retval,
2383ee59242SSebastian Wiedenroth 	    &name_sz) < 0) {
2393ee59242SSebastian Wiedenroth 		return (-1);
2403ee59242SSebastian Wiedenroth 	}
2413ee59242SSebastian Wiedenroth 	if (name_retval->lr_err != 0) {
2423ee59242SSebastian Wiedenroth 		errno = name_retval->lr_err;
2433ee59242SSebastian Wiedenroth 		return (-1);
2443ee59242SSebastian Wiedenroth 	}
2453ee59242SSebastian Wiedenroth 	return (0);
2463ee59242SSebastian Wiedenroth }
2473ee59242SSebastian Wiedenroth 
2483ee59242SSebastian Wiedenroth /*
2493ee59242SSebastian Wiedenroth  * Get the next link from dlmgmtd.
2503ee59242SSebastian Wiedenroth  * Start iterating by passing DATALINK_INVALID_LINKID as linkid.
2513ee59242SSebastian Wiedenroth  * The end is marked by next_retval.lr_linkid set to DATALINK_INVALID_LINKID.
2523ee59242SSebastian Wiedenroth  * If successful the result is stored in next_retval and 0 returned.
2533ee59242SSebastian Wiedenroth  * On errors, return -1 and set `errno'.
2543ee59242SSebastian Wiedenroth  */
2553ee59242SSebastian Wiedenroth static int
dl_get_next(int door_fd,datalink_id_t linkid,datalink_class_t class,datalink_media_t dmedia,uint32_t flags,dlmgmt_getnext_retval_t * next_retval)2563ee59242SSebastian Wiedenroth dl_get_next(int door_fd, datalink_id_t linkid, datalink_class_t class,
2573ee59242SSebastian Wiedenroth     datalink_media_t dmedia, uint32_t flags,
2583ee59242SSebastian Wiedenroth     dlmgmt_getnext_retval_t *next_retval)
2593ee59242SSebastian Wiedenroth {
2603ee59242SSebastian Wiedenroth 	size_t next_sz = sizeof (*next_retval);
2613ee59242SSebastian Wiedenroth 	dlmgmt_door_getnext_t getnext;
2623ee59242SSebastian Wiedenroth 	bzero(&getnext, sizeof (dlmgmt_door_getnext_t));
2633ee59242SSebastian Wiedenroth 	getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
2643ee59242SSebastian Wiedenroth 	getnext.ld_class = class;
2653ee59242SSebastian Wiedenroth 	getnext.ld_dmedia = dmedia;
2663ee59242SSebastian Wiedenroth 	getnext.ld_flags = flags;
2673ee59242SSebastian Wiedenroth 	getnext.ld_linkid = linkid;
2683ee59242SSebastian Wiedenroth 
2693ee59242SSebastian Wiedenroth 	if (dl_door_call(door_fd, &getnext, sizeof (getnext), next_retval,
2703ee59242SSebastian Wiedenroth 	    &next_sz) < 0) {
2713ee59242SSebastian Wiedenroth 		return (-1);
2723ee59242SSebastian Wiedenroth 	}
2733ee59242SSebastian Wiedenroth 	if (next_retval->lr_err != 0) {
2743ee59242SSebastian Wiedenroth 		errno = next_retval->lr_err;
2753ee59242SSebastian Wiedenroth 		return (-1);
2763ee59242SSebastian Wiedenroth 	}
2773ee59242SSebastian Wiedenroth 	return (0);
2783ee59242SSebastian Wiedenroth }
2793ee59242SSebastian Wiedenroth 
2806e91bba0SGirish Moodalbail /*
2816e91bba0SGirish Moodalbail  * Returns all addresses configured on the system. If flags contain
2826e91bba0SGirish Moodalbail  * LIFC_ENABLED, only the addresses that are UP are returned.
2836e91bba0SGirish Moodalbail  * Address list that is returned by this function must be freed
2846e91bba0SGirish Moodalbail  * using freeifaddrs().
2856e91bba0SGirish Moodalbail  */
2866e91bba0SGirish Moodalbail int
getallifaddrs(sa_family_t af,struct ifaddrs ** ifap,int64_t flags)2876e91bba0SGirish Moodalbail getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags)
2886e91bba0SGirish Moodalbail {
2896e91bba0SGirish Moodalbail 	struct lifreq *buf = NULL;
2906e91bba0SGirish Moodalbail 	struct lifreq *lifrp;
2916e91bba0SGirish Moodalbail 	struct lifreq lifrl;
2926e91bba0SGirish Moodalbail 	int ret;
2936e91bba0SGirish Moodalbail 	int s, n, numifs;
2946e91bba0SGirish Moodalbail 	struct ifaddrs *curr, *prev;
2953ee59242SSebastian Wiedenroth 	struct sockaddr_dl *ifa_addr = NULL;
2963ee59242SSebastian Wiedenroth 	if_data_t *ifa_data = NULL;
2976e91bba0SGirish Moodalbail 	sa_family_t lifr_af;
2983ee59242SSebastian Wiedenroth 	datalink_id_t linkid;
2993ee59242SSebastian Wiedenroth 	dld_ioc_attr_t dia;
3003ee59242SSebastian Wiedenroth 	dld_macaddrinfo_t *dmip;
3013ee59242SSebastian Wiedenroth 	dld_ioc_macaddrget_t *iomp = NULL;
3023ee59242SSebastian Wiedenroth 	dlmgmt_getnext_retval_t next_retval;
3033ee59242SSebastian Wiedenroth 	dlmgmt_getname_retval_t	name_retval;
3043ee59242SSebastian Wiedenroth 	int bufsize;
3053ee59242SSebastian Wiedenroth 	int nmacaddr = 1024;
3063ee59242SSebastian Wiedenroth 	int sock4 = -1;
3073ee59242SSebastian Wiedenroth 	int sock6 = -1;
3083ee59242SSebastian Wiedenroth 	int door_fd = -1;
3093ee59242SSebastian Wiedenroth 	int dld_fd = -1;
3106e91bba0SGirish Moodalbail 	int err;
3116e91bba0SGirish Moodalbail 
31251c62b7bSAndrew Stormont 	/*
31351c62b7bSAndrew Stormont 	 * Initialize ifap to NULL so we can safely call freeifaddrs
31451c62b7bSAndrew Stormont 	 * on it in case of error.
31551c62b7bSAndrew Stormont 	 */
31651c62b7bSAndrew Stormont 	if (ifap == NULL)
31751c62b7bSAndrew Stormont 		return (EINVAL);
31851c62b7bSAndrew Stormont 	*ifap = NULL;
31951c62b7bSAndrew Stormont 
3203ee59242SSebastian Wiedenroth 	if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
3212ec63ffbSAndy Fiddaman 	    (sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
3223ee59242SSebastian Wiedenroth 		goto fail;
3232ec63ffbSAndy Fiddaman 	}
3243ee59242SSebastian Wiedenroth 
3253ee59242SSebastian Wiedenroth 	bufsize = sizeof (dld_ioc_macaddrget_t) + nmacaddr *
3263ee59242SSebastian Wiedenroth 	    sizeof (dld_macaddrinfo_t);
327*106b5261SToomas Soome 	if ((iomp = malloc(bufsize)) == NULL)
3283ee59242SSebastian Wiedenroth 		goto fail;
3296e91bba0SGirish Moodalbail 
3306e91bba0SGirish Moodalbail retry:
331*106b5261SToomas Soome 	bzero(iomp, bufsize);
3326e91bba0SGirish Moodalbail 	/* Get all interfaces from SIOCGLIFCONF */
3336e91bba0SGirish Moodalbail 	ret = getallifs(sock4, af, &buf, &numifs, (flags & ~LIFC_ENABLED));
3346e91bba0SGirish Moodalbail 	if (ret != 0)
3356e91bba0SGirish Moodalbail 		goto fail;
3366e91bba0SGirish Moodalbail 
3376e91bba0SGirish Moodalbail 	/*
3386e91bba0SGirish Moodalbail 	 * Loop through the interfaces obtained from SIOCGLIFCOMF
3396e91bba0SGirish Moodalbail 	 * and retrieve the addresses, netmask and flags.
3406e91bba0SGirish Moodalbail 	 */
3416e91bba0SGirish Moodalbail 	prev = NULL;
3426e91bba0SGirish Moodalbail 	lifrp = buf;
3436e91bba0SGirish Moodalbail 	for (n = 0; n < numifs; n++, lifrp++) {
3446e91bba0SGirish Moodalbail 
3456e91bba0SGirish Moodalbail 		/* Prepare for the ioctl call */
3466e91bba0SGirish Moodalbail 		(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
3476e91bba0SGirish Moodalbail 		    sizeof (lifrl.lifr_name));
3486e91bba0SGirish Moodalbail 		lifr_af = lifrp->lifr_addr.ss_family;
3496e91bba0SGirish Moodalbail 		if (af != AF_UNSPEC && lifr_af != af)
3506e91bba0SGirish Moodalbail 			continue;
3516e91bba0SGirish Moodalbail 
3526e91bba0SGirish Moodalbail 		s = (lifr_af == AF_INET ? sock4 : sock6);
3536e91bba0SGirish Moodalbail 
3546e91bba0SGirish Moodalbail 		if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
3556e91bba0SGirish Moodalbail 			goto fail;
3566e91bba0SGirish Moodalbail 		if ((flags & LIFC_ENABLED) && !(lifrl.lifr_flags & IFF_UP))
3576e91bba0SGirish Moodalbail 			continue;
3586e91bba0SGirish Moodalbail 
3596e91bba0SGirish Moodalbail 		/*
3606e91bba0SGirish Moodalbail 		 * Allocate the current list node. Each node contains data
3616e91bba0SGirish Moodalbail 		 * for one ifaddrs structure.
3626e91bba0SGirish Moodalbail 		 */
3636e91bba0SGirish Moodalbail 		curr = calloc(1, sizeof (struct ifaddrs));
3646e91bba0SGirish Moodalbail 		if (curr == NULL)
3656e91bba0SGirish Moodalbail 			goto fail;
3666e91bba0SGirish Moodalbail 
3676e91bba0SGirish Moodalbail 		if (prev != NULL) {
3686e91bba0SGirish Moodalbail 			prev->ifa_next = curr;
3696e91bba0SGirish Moodalbail 		} else {
3706e91bba0SGirish Moodalbail 			/* First node in the linked list */
3716e91bba0SGirish Moodalbail 			*ifap = curr;
3726e91bba0SGirish Moodalbail 		}
3736e91bba0SGirish Moodalbail 		prev = curr;
3746e91bba0SGirish Moodalbail 
3756e91bba0SGirish Moodalbail 		curr->ifa_flags = lifrl.lifr_flags;
3766e91bba0SGirish Moodalbail 		if ((curr->ifa_name = strdup(lifrp->lifr_name)) == NULL)
3776e91bba0SGirish Moodalbail 			goto fail;
3786e91bba0SGirish Moodalbail 
3796e91bba0SGirish Moodalbail 		curr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
3806e91bba0SGirish Moodalbail 		if (curr->ifa_addr == NULL)
3816e91bba0SGirish Moodalbail 			goto fail;
38264639aafSDarren Reed 		(void) memcpy(curr->ifa_addr, &lifrp->lifr_addr,
38364639aafSDarren Reed 		    sizeof (struct sockaddr_storage));
3846e91bba0SGirish Moodalbail 
3856e91bba0SGirish Moodalbail 		/* Get the netmask */
3866e91bba0SGirish Moodalbail 		if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifrl) < 0)
3876e91bba0SGirish Moodalbail 			goto fail;
3886e91bba0SGirish Moodalbail 		curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
3896e91bba0SGirish Moodalbail 		if (curr->ifa_netmask == NULL)
3906e91bba0SGirish Moodalbail 			goto fail;
39164639aafSDarren Reed 		(void) memcpy(curr->ifa_netmask, &lifrl.lifr_addr,
39264639aafSDarren Reed 		    sizeof (struct sockaddr_storage));
3936e91bba0SGirish Moodalbail 
3946e91bba0SGirish Moodalbail 		/* Get the destination for a pt-pt interface */
3956e91bba0SGirish Moodalbail 		if (curr->ifa_flags & IFF_POINTOPOINT) {
3966e91bba0SGirish Moodalbail 			if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifrl) < 0)
3976e91bba0SGirish Moodalbail 				goto fail;
3986e91bba0SGirish Moodalbail 			curr->ifa_dstaddr = malloc(
3996e91bba0SGirish Moodalbail 			    sizeof (struct sockaddr_storage));
4006e91bba0SGirish Moodalbail 			if (curr->ifa_dstaddr == NULL)
4016e91bba0SGirish Moodalbail 				goto fail;
40208ed54f3SVasumathi Sundaram 			(void) memcpy(curr->ifa_dstaddr, &lifrl.lifr_addr,
40364639aafSDarren Reed 			    sizeof (struct sockaddr_storage));
4046e91bba0SGirish Moodalbail 		} else if (curr->ifa_flags & IFF_BROADCAST) {
4056e91bba0SGirish Moodalbail 			if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifrl) < 0)
4066e91bba0SGirish Moodalbail 				goto fail;
4076e91bba0SGirish Moodalbail 			curr->ifa_broadaddr = malloc(
4086e91bba0SGirish Moodalbail 			    sizeof (struct sockaddr_storage));
4096e91bba0SGirish Moodalbail 			if (curr->ifa_broadaddr == NULL)
4106e91bba0SGirish Moodalbail 				goto fail;
41108ed54f3SVasumathi Sundaram 			(void) memcpy(curr->ifa_broadaddr, &lifrl.lifr_addr,
41264639aafSDarren Reed 			    sizeof (struct sockaddr_storage));
4136e91bba0SGirish Moodalbail 		}
4146e91bba0SGirish Moodalbail 
4156e91bba0SGirish Moodalbail 	}
4163ee59242SSebastian Wiedenroth 
4173ee59242SSebastian Wiedenroth 	/* add AF_LINK entries */
4183ee59242SSebastian Wiedenroth 	if (af == AF_UNSPEC || af == AF_LINK) {
4192ec63ffbSAndy Fiddaman 		/*
4202ec63ffbSAndy Fiddaman 		 * A datalink management door may not be available (for example
4212ec63ffbSAndy Fiddaman 		 * in a shared IP zone). Only enumerate AF_LINK entries if the
4222ec63ffbSAndy Fiddaman 		 * door exists.
4232ec63ffbSAndy Fiddaman 		 */
4242ec63ffbSAndy Fiddaman 		door_fd = open(DLMGMT_DOOR, O_RDONLY);
4252ec63ffbSAndy Fiddaman 		if (door_fd < 0) {
4262ec63ffbSAndy Fiddaman 			if (errno == ENOENT)
4272ec63ffbSAndy Fiddaman 				goto nolink;
4282ec63ffbSAndy Fiddaman 			goto fail;
4292ec63ffbSAndy Fiddaman 		}
4302ec63ffbSAndy Fiddaman 		if ((dld_fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
4312ec63ffbSAndy Fiddaman 			goto fail;
4323ee59242SSebastian Wiedenroth 
4333ee59242SSebastian Wiedenroth 		linkid = DATALINK_INVALID_LINKID;
4343ee59242SSebastian Wiedenroth 		for (;;) {
4353ee59242SSebastian Wiedenroth 			if (dl_get_next(door_fd, linkid, DATALINK_CLASS_ALL,
4363ee59242SSebastian Wiedenroth 			    DATALINK_ANY_MEDIATYPE, DLMGMT_ACTIVE,
4373ee59242SSebastian Wiedenroth 			    &next_retval) != 0) {
4383ee59242SSebastian Wiedenroth 				break;
4393ee59242SSebastian Wiedenroth 			}
4403ee59242SSebastian Wiedenroth 
4413ee59242SSebastian Wiedenroth 			linkid = next_retval.lr_linkid;
4423ee59242SSebastian Wiedenroth 			if (linkid == DATALINK_INVALID_LINKID)
4433ee59242SSebastian Wiedenroth 				break;
4443ee59242SSebastian Wiedenroth 
4453ee59242SSebastian Wiedenroth 			/* get mac addr */
4463ee59242SSebastian Wiedenroth 			iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t);
4473ee59242SSebastian Wiedenroth 			iomp->dig_linkid = linkid;
4483ee59242SSebastian Wiedenroth 
4493ee59242SSebastian Wiedenroth 			if (ioctl(dld_fd, DLDIOC_MACADDRGET, iomp) < 0)
4503ee59242SSebastian Wiedenroth 				continue;
4513ee59242SSebastian Wiedenroth 
4523ee59242SSebastian Wiedenroth 			dmip = (dld_macaddrinfo_t *)(iomp + 1);
4533ee59242SSebastian Wiedenroth 
4543ee59242SSebastian Wiedenroth 			/* get name */
4553ee59242SSebastian Wiedenroth 			if (dl_get_name(door_fd, linkid, &name_retval) != 0)
4563ee59242SSebastian Wiedenroth 				continue;
4573ee59242SSebastian Wiedenroth 
4583ee59242SSebastian Wiedenroth 			/* get MTU */
4593ee59242SSebastian Wiedenroth 			dia.dia_linkid = linkid;
4603ee59242SSebastian Wiedenroth 			if (ioctl(dld_fd, DLDIOC_ATTR, &dia) < 0)
4613ee59242SSebastian Wiedenroth 				continue;
4623ee59242SSebastian Wiedenroth 
4633ee59242SSebastian Wiedenroth 			curr = calloc(1, sizeof (struct ifaddrs));
4643ee59242SSebastian Wiedenroth 			if (curr == NULL)
4653ee59242SSebastian Wiedenroth 				goto fail;
4663ee59242SSebastian Wiedenroth 
4673ee59242SSebastian Wiedenroth 			if (prev != NULL) {
4683ee59242SSebastian Wiedenroth 				prev->ifa_next = curr;
4693ee59242SSebastian Wiedenroth 			} else {
4703ee59242SSebastian Wiedenroth 				/* First node in the linked list */
4713ee59242SSebastian Wiedenroth 				*ifap = curr;
4723ee59242SSebastian Wiedenroth 			}
4733ee59242SSebastian Wiedenroth 			prev = curr;
4743ee59242SSebastian Wiedenroth 
4753ee59242SSebastian Wiedenroth 			if ((curr->ifa_name = strdup(name_retval.lr_link)) ==
4763ee59242SSebastian Wiedenroth 			    NULL)
4773ee59242SSebastian Wiedenroth 				goto fail;
4783ee59242SSebastian Wiedenroth 
4793ee59242SSebastian Wiedenroth 			curr->ifa_addr =
4803ee59242SSebastian Wiedenroth 			    calloc(1, sizeof (struct sockaddr_storage));
4813ee59242SSebastian Wiedenroth 			if (curr->ifa_addr == NULL)
4823ee59242SSebastian Wiedenroth 				goto fail;
4833ee59242SSebastian Wiedenroth 
4843ee59242SSebastian Wiedenroth 			curr->ifa_data = calloc(1, sizeof (if_data_t));
4853ee59242SSebastian Wiedenroth 			if (curr->ifa_data == NULL)
4863ee59242SSebastian Wiedenroth 				goto fail;
4873ee59242SSebastian Wiedenroth 
4883ee59242SSebastian Wiedenroth 			curr->ifa_addr->sa_family = AF_LINK;
4893ee59242SSebastian Wiedenroth 			ifa_addr = (struct sockaddr_dl *)curr->ifa_addr;
4903ee59242SSebastian Wiedenroth 			ifa_data = curr->ifa_data;
4913ee59242SSebastian Wiedenroth 
4923ee59242SSebastian Wiedenroth 			(void) memcpy(ifa_addr->sdl_data, dmip->dmi_addr,
4933ee59242SSebastian Wiedenroth 			    dmip->dmi_addrlen);
4943ee59242SSebastian Wiedenroth 			ifa_addr->sdl_alen = dmip->dmi_addrlen;
4953ee59242SSebastian Wiedenroth 
4963ee59242SSebastian Wiedenroth 			ifa_data->ifi_mtu = dia.dia_max_sdu;
4973ee59242SSebastian Wiedenroth 			ifa_data->ifi_type = dlpi_iftype(next_retval.lr_media);
4983ee59242SSebastian Wiedenroth 
4993ee59242SSebastian Wiedenroth 			/*
5003ee59242SSebastian Wiedenroth 			 * get interface index
5013ee59242SSebastian Wiedenroth 			 * This is only possible if the link has been plumbed.
5023ee59242SSebastian Wiedenroth 			 */
5033ee59242SSebastian Wiedenroth 			if (strlcpy(lifrl.lifr_name, name_retval.lr_link,
5043ee59242SSebastian Wiedenroth 			    sizeof (lifrl.lifr_name)) >=
5053ee59242SSebastian Wiedenroth 			    sizeof (lifrl.lifr_name))
5063ee59242SSebastian Wiedenroth 				continue;
5073ee59242SSebastian Wiedenroth 
5083ee59242SSebastian Wiedenroth 			if (ioctl(sock4, SIOCGLIFINDEX, (caddr_t)&lifrl) >= 0) {
5093ee59242SSebastian Wiedenroth 				ifa_addr->sdl_index = lifrl.lifr_index;
5103ee59242SSebastian Wiedenroth 			} else if (ioctl(sock6, SIOCGLIFINDEX,
5113ee59242SSebastian Wiedenroth 			    (caddr_t)&lifrl) >= 0) {
5123ee59242SSebastian Wiedenroth 				/* retry for IPv6 */
5133ee59242SSebastian Wiedenroth 				ifa_addr->sdl_index = lifrl.lifr_index;
5143ee59242SSebastian Wiedenroth 			}
5153ee59242SSebastian Wiedenroth 		}
5163ee59242SSebastian Wiedenroth 	}
5172ec63ffbSAndy Fiddaman nolink:
5186e91bba0SGirish Moodalbail 	free(buf);
5193ee59242SSebastian Wiedenroth 	free(iomp);
5203ee59242SSebastian Wiedenroth 	(void) close(sock4);
5213ee59242SSebastian Wiedenroth 	(void) close(sock6);
5222ec63ffbSAndy Fiddaman 	if (door_fd >= 0)
5232ec63ffbSAndy Fiddaman 		(void) close(door_fd);
5242ec63ffbSAndy Fiddaman 	if (dld_fd >= 0)
5252ec63ffbSAndy Fiddaman 		(void) close(dld_fd);
5266e91bba0SGirish Moodalbail 	return (0);
5276e91bba0SGirish Moodalbail fail:
5286e91bba0SGirish Moodalbail 	err = errno;
5296e91bba0SGirish Moodalbail 	free(buf);
530*106b5261SToomas Soome 	buf = NULL;
5316e91bba0SGirish Moodalbail 	freeifaddrs(*ifap);
5326e91bba0SGirish Moodalbail 	*ifap = NULL;
533*106b5261SToomas Soome 	if (err == ENXIO)
5346e91bba0SGirish Moodalbail 		goto retry;
535*106b5261SToomas Soome 	free(iomp);
5363ee59242SSebastian Wiedenroth 
5372ec63ffbSAndy Fiddaman 	if (sock4 >= 0)
5383ee59242SSebastian Wiedenroth 		(void) close(sock4);
5392ec63ffbSAndy Fiddaman 	if (sock6 >= 0)
5403ee59242SSebastian Wiedenroth 		(void) close(sock6);
5412ec63ffbSAndy Fiddaman 	if (door_fd >= 0)
5423ee59242SSebastian Wiedenroth 		(void) close(door_fd);
5432ec63ffbSAndy Fiddaman 	if (dld_fd >= 0)
5443ee59242SSebastian Wiedenroth 		(void) close(dld_fd);
5456e91bba0SGirish Moodalbail 	errno = err;
5466e91bba0SGirish Moodalbail 	return (-1);
5476e91bba0SGirish Moodalbail }
5486e91bba0SGirish Moodalbail 
5496e91bba0SGirish Moodalbail /*
5506e91bba0SGirish Moodalbail  * Do a SIOCGLIFCONF and store all the interfaces in `buf'.
5516e91bba0SGirish Moodalbail  */
5526e91bba0SGirish Moodalbail int
getallifs(int s,sa_family_t af,struct lifreq ** lifr,int * numifs,int64_t lifc_flags)5536e91bba0SGirish Moodalbail getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs,
5546e91bba0SGirish Moodalbail     int64_t lifc_flags)
5556e91bba0SGirish Moodalbail {
5566e91bba0SGirish Moodalbail 	struct lifnum lifn;
5576e91bba0SGirish Moodalbail 	struct lifconf lifc;
5586e91bba0SGirish Moodalbail 	size_t bufsize;
5596e91bba0SGirish Moodalbail 	char *tmp;
5606e91bba0SGirish Moodalbail 	caddr_t *buf = (caddr_t *)lifr;
5616e91bba0SGirish Moodalbail 
5626e91bba0SGirish Moodalbail 	lifn.lifn_family = af;
5636e91bba0SGirish Moodalbail 	lifn.lifn_flags = lifc_flags;
5646e91bba0SGirish Moodalbail 
5656e91bba0SGirish Moodalbail 	*buf = NULL;
5666e91bba0SGirish Moodalbail retry:
5676e91bba0SGirish Moodalbail 	if (ioctl(s, SIOCGLIFNUM, &lifn) < 0)
5686e91bba0SGirish Moodalbail 		goto fail;
5696e91bba0SGirish Moodalbail 
5706e91bba0SGirish Moodalbail 	/*
5716e91bba0SGirish Moodalbail 	 * When calculating the buffer size needed, add a small number
5726e91bba0SGirish Moodalbail 	 * of interfaces to those we counted.  We do this to capture
5736e91bba0SGirish Moodalbail 	 * the interface status of potential interfaces which may have
5746e91bba0SGirish Moodalbail 	 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
5756e91bba0SGirish Moodalbail 	 */
5766e91bba0SGirish Moodalbail 	bufsize = (lifn.lifn_count + 4) * sizeof (struct lifreq);
5776e91bba0SGirish Moodalbail 
5786e91bba0SGirish Moodalbail 	if ((tmp = realloc(*buf, bufsize)) == NULL)
5796e91bba0SGirish Moodalbail 		goto fail;
5806e91bba0SGirish Moodalbail 
5816e91bba0SGirish Moodalbail 	*buf = tmp;
5826e91bba0SGirish Moodalbail 	lifc.lifc_family = af;
5836e91bba0SGirish Moodalbail 	lifc.lifc_flags = lifc_flags;
5846e91bba0SGirish Moodalbail 	lifc.lifc_len = bufsize;
5856e91bba0SGirish Moodalbail 	lifc.lifc_buf = *buf;
5866e91bba0SGirish Moodalbail 	if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
5876e91bba0SGirish Moodalbail 		goto fail;
5886e91bba0SGirish Moodalbail 
5896e91bba0SGirish Moodalbail 	*numifs = lifc.lifc_len / sizeof (struct lifreq);
5906e91bba0SGirish Moodalbail 	if (*numifs >= (lifn.lifn_count + 4)) {
5916e91bba0SGirish Moodalbail 		/*
5926e91bba0SGirish Moodalbail 		 * If every entry was filled, there are probably
5936e91bba0SGirish Moodalbail 		 * more interfaces than (lifn.lifn_count + 4).
5946e91bba0SGirish Moodalbail 		 * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to
5956e91bba0SGirish Moodalbail 		 * get all the interfaces.
5966e91bba0SGirish Moodalbail 		 */
5976e91bba0SGirish Moodalbail 		goto retry;
5986e91bba0SGirish Moodalbail 	}
5996e91bba0SGirish Moodalbail 	return (0);
6006e91bba0SGirish Moodalbail fail:
6016e91bba0SGirish Moodalbail 	free(*buf);
6026e91bba0SGirish Moodalbail 	*buf = NULL;
6036e91bba0SGirish Moodalbail 	return (-1);
6046e91bba0SGirish Moodalbail }
605