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