1*e11c3f44Smeem /* 2*e11c3f44Smeem * CDDL HEADER START 3*e11c3f44Smeem * 4*e11c3f44Smeem * The contents of this file are subject to the terms of the 5*e11c3f44Smeem * Common Development and Distribution License (the "License"). 6*e11c3f44Smeem * You may not use this file except in compliance with the License. 7*e11c3f44Smeem * 8*e11c3f44Smeem * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*e11c3f44Smeem * or http://www.opensolaris.org/os/licensing. 10*e11c3f44Smeem * See the License for the specific language governing permissions 11*e11c3f44Smeem * and limitations under the License. 12*e11c3f44Smeem * 13*e11c3f44Smeem * When distributing Covered Code, include this CDDL HEADER in each 14*e11c3f44Smeem * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*e11c3f44Smeem * If applicable, add the following below this CDDL HEADER, with the 16*e11c3f44Smeem * fields enclosed by brackets "[]" replaced with your own identifying 17*e11c3f44Smeem * information: Portions Copyright [yyyy] [name of copyright owner] 18*e11c3f44Smeem * 19*e11c3f44Smeem * CDDL HEADER END 20*e11c3f44Smeem * 21*e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 22*e11c3f44Smeem * Use is subject to license terms. 23*e11c3f44Smeem */ 24*e11c3f44Smeem 25*e11c3f44Smeem #include <errno.h> 26*e11c3f44Smeem #include <libinetutil.h> 27*e11c3f44Smeem #include <stdio.h> 28*e11c3f44Smeem #include <stdlib.h> 29*e11c3f44Smeem #include <string.h> 30*e11c3f44Smeem #include <unistd.h> 31*e11c3f44Smeem #include <sys/socket.h> 32*e11c3f44Smeem #include <sys/sockio.h> 33*e11c3f44Smeem 34*e11c3f44Smeem /* 35*e11c3f44Smeem * Create a list of the addresses on physical interface `ifname' with at least 36*e11c3f44Smeem * one of the flags in `set' set and all of the flags in `clear' clear. 37*e11c3f44Smeem * Return the number of items in the list, or -1 on failure. 38*e11c3f44Smeem */ 39*e11c3f44Smeem int 40*e11c3f44Smeem ifaddrlistx(const char *ifname, uint64_t set, uint64_t clear, 41*e11c3f44Smeem ifaddrlistx_t **ifaddrsp) 42*e11c3f44Smeem { 43*e11c3f44Smeem struct lifconf lifc; 44*e11c3f44Smeem struct lifnum lifn; 45*e11c3f44Smeem struct lifreq *lifrp; 46*e11c3f44Smeem ifaddrlistx_t *ifaddrp, *ifaddrs = NULL; 47*e11c3f44Smeem int i, nlifr, naddr = 0; 48*e11c3f44Smeem char *cp; 49*e11c3f44Smeem uint_t flags; 50*e11c3f44Smeem int s4, s6 = -1; 51*e11c3f44Smeem boolean_t isv6; 52*e11c3f44Smeem int save_errno; 53*e11c3f44Smeem struct sockaddr_storage addr; 54*e11c3f44Smeem 55*e11c3f44Smeem (void) memset(&lifc, 0, sizeof (lifc)); 56*e11c3f44Smeem flags = LIFC_NOXMIT | LIFC_ALLZONES | LIFC_TEMPORARY | LIFC_UNDER_IPMP; 57*e11c3f44Smeem 58*e11c3f44Smeem /* 59*e11c3f44Smeem * We need both IPv4 and IPv6 sockets to query both IPv4 and IPv6 60*e11c3f44Smeem * interfaces below. 61*e11c3f44Smeem */ 62*e11c3f44Smeem if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) == -1 || 63*e11c3f44Smeem (s6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { 64*e11c3f44Smeem goto fail; 65*e11c3f44Smeem } 66*e11c3f44Smeem 67*e11c3f44Smeem /* 68*e11c3f44Smeem * Get the number of network interfaces of type `family'. 69*e11c3f44Smeem */ 70*e11c3f44Smeem lifn.lifn_family = AF_UNSPEC; 71*e11c3f44Smeem lifn.lifn_flags = flags; 72*e11c3f44Smeem again: 73*e11c3f44Smeem if (ioctl(s4, SIOCGLIFNUM, &lifn) == -1) 74*e11c3f44Smeem goto fail; 75*e11c3f44Smeem 76*e11c3f44Smeem /* 77*e11c3f44Smeem * Pad the interface count to detect when additional interfaces have 78*e11c3f44Smeem * been configured between SIOCGLIFNUM and SIOCGLIFCONF. 79*e11c3f44Smeem */ 80*e11c3f44Smeem lifn.lifn_count += 4; 81*e11c3f44Smeem 82*e11c3f44Smeem lifc.lifc_flags = flags; 83*e11c3f44Smeem lifc.lifc_family = AF_UNSPEC; 84*e11c3f44Smeem lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 85*e11c3f44Smeem if ((lifc.lifc_buf = realloc(lifc.lifc_buf, lifc.lifc_len)) == NULL) 86*e11c3f44Smeem goto fail; 87*e11c3f44Smeem 88*e11c3f44Smeem if (ioctl(s4, SIOCGLIFCONF, &lifc) == -1) 89*e11c3f44Smeem goto fail; 90*e11c3f44Smeem 91*e11c3f44Smeem /* 92*e11c3f44Smeem * If every lifr_req slot is taken, then additional interfaces must 93*e11c3f44Smeem * have been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. 94*e11c3f44Smeem * Recalculate to make sure we didn't miss any interfaces. 95*e11c3f44Smeem */ 96*e11c3f44Smeem nlifr = lifc.lifc_len / sizeof (struct lifreq); 97*e11c3f44Smeem if (nlifr >= lifn.lifn_count) 98*e11c3f44Smeem goto again; 99*e11c3f44Smeem 100*e11c3f44Smeem /* 101*e11c3f44Smeem * Populate the ifaddrlistx by querying each matching interface. If a 102*e11c3f44Smeem * query ioctl returns ENXIO, then the interface must have been 103*e11c3f44Smeem * removed after the SIOCGLIFCONF completed -- so we just ignore it. 104*e11c3f44Smeem */ 105*e11c3f44Smeem for (lifrp = lifc.lifc_req, i = 0; i < nlifr; i++, lifrp++) { 106*e11c3f44Smeem if ((cp = strchr(lifrp->lifr_name, ':')) != NULL) 107*e11c3f44Smeem *cp = '\0'; 108*e11c3f44Smeem 109*e11c3f44Smeem if (strcmp(lifrp->lifr_name, ifname) != 0) 110*e11c3f44Smeem continue; 111*e11c3f44Smeem 112*e11c3f44Smeem if (cp != NULL) 113*e11c3f44Smeem *cp = ':'; 114*e11c3f44Smeem 115*e11c3f44Smeem addr = lifrp->lifr_addr; 116*e11c3f44Smeem isv6 = addr.ss_family == AF_INET6; 117*e11c3f44Smeem if (ioctl(isv6 ? s6 : s4, SIOCGLIFFLAGS, lifrp) == -1) { 118*e11c3f44Smeem if (errno == ENXIO) 119*e11c3f44Smeem continue; 120*e11c3f44Smeem goto fail; 121*e11c3f44Smeem } 122*e11c3f44Smeem 123*e11c3f44Smeem if (set != 0 && ((lifrp->lifr_flags & set) == 0) || 124*e11c3f44Smeem (lifrp->lifr_flags & clear) != 0) 125*e11c3f44Smeem continue; 126*e11c3f44Smeem 127*e11c3f44Smeem /* 128*e11c3f44Smeem * We've got a match; allocate a new record. 129*e11c3f44Smeem */ 130*e11c3f44Smeem if ((ifaddrp = malloc(sizeof (ifaddrlistx_t))) == NULL) 131*e11c3f44Smeem goto fail; 132*e11c3f44Smeem 133*e11c3f44Smeem (void) strlcpy(ifaddrp->ia_name, lifrp->lifr_name, LIFNAMSIZ); 134*e11c3f44Smeem ifaddrp->ia_flags = lifrp->lifr_flags; 135*e11c3f44Smeem ifaddrp->ia_addr = addr; 136*e11c3f44Smeem ifaddrp->ia_next = ifaddrs; 137*e11c3f44Smeem ifaddrs = ifaddrp; 138*e11c3f44Smeem naddr++; 139*e11c3f44Smeem } 140*e11c3f44Smeem 141*e11c3f44Smeem (void) close(s4); 142*e11c3f44Smeem (void) close(s6); 143*e11c3f44Smeem free(lifc.lifc_buf); 144*e11c3f44Smeem *ifaddrsp = ifaddrs; 145*e11c3f44Smeem return (naddr); 146*e11c3f44Smeem fail: 147*e11c3f44Smeem save_errno = errno; 148*e11c3f44Smeem (void) close(s4); 149*e11c3f44Smeem (void) close(s6); 150*e11c3f44Smeem free(lifc.lifc_buf); 151*e11c3f44Smeem ifaddrlistx_free(ifaddrs); 152*e11c3f44Smeem errno = save_errno; 153*e11c3f44Smeem return (-1); 154*e11c3f44Smeem } 155*e11c3f44Smeem 156*e11c3f44Smeem /* 157*e11c3f44Smeem * Free the provided ifaddrlistx_t. 158*e11c3f44Smeem */ 159*e11c3f44Smeem void 160*e11c3f44Smeem ifaddrlistx_free(ifaddrlistx_t *ifaddrp) 161*e11c3f44Smeem { 162*e11c3f44Smeem ifaddrlistx_t *next_ifaddrp; 163*e11c3f44Smeem 164*e11c3f44Smeem for (; ifaddrp != NULL; ifaddrp = next_ifaddrp) { 165*e11c3f44Smeem next_ifaddrp = ifaddrp->ia_next; 166*e11c3f44Smeem free(ifaddrp); 167*e11c3f44Smeem } 168*e11c3f44Smeem } 169