1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 1997
8 * The Regents of the University of California. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the Computer Systems
21 * Engineering Group at Lawrence Berkeley Laboratory.
22 * 4. Neither the name of the University nor of the Laboratory may be used
23 * to endorse or promote products derived from this software without
24 * specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#) $Header: ifaddrlist.c,v 1.2 97/04/22 13:31:05 leres Exp $ (LBL)
39 */
40
41 #include <errno.h>
42 #include <libinetutil.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49
50 /*
51 * See <libinetutil.h> for a description of the programming interface.
52 */
53 int
ifaddrlist(struct ifaddrlist ** ipaddrp,int family,uint_t flags,char * errbuf)54 ifaddrlist(struct ifaddrlist **ipaddrp, int family, uint_t flags, char *errbuf)
55 {
56 struct ifaddrlist *ifaddrlist = NULL, *al = NULL;
57 struct sockaddr_in *sin;
58 struct sockaddr_in6 *sin6;
59 struct lifconf lifc;
60 struct lifnum lifn;
61 struct lifreq *lifrp;
62 int i, count, nlifr;
63 int fd;
64 const char *opstr;
65
66 (void) memset(&lifc, 0, sizeof (lifc));
67 if (family != AF_INET && family != AF_INET6) {
68 (void) strlcpy(errbuf, "invalid address family", ERRBUFSIZE);
69 return (-1);
70 }
71
72 if ((fd = socket(family, SOCK_DGRAM, 0)) == -1) {
73 opstr = "socket";
74 goto fail;
75 }
76
77 /*
78 * Get the number of network interfaces of type `family'.
79 */
80 lifn.lifn_family = family;
81 lifn.lifn_flags = flags;
82 again:
83 if (ioctl(fd, SIOCGLIFNUM, &lifn) == -1) {
84 opstr = "SIOCGLIFNUM";
85 goto fail;
86 }
87
88 /*
89 * Pad the interface count to detect when additional interfaces have
90 * been configured between SIOCGLIFNUM and SIOCGLIFCONF.
91 */
92 lifn.lifn_count += 4;
93
94 lifc.lifc_flags = flags;
95 lifc.lifc_family = family;
96 lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
97 if ((lifc.lifc_buf = realloc(lifc.lifc_buf, lifc.lifc_len)) == NULL) {
98 opstr = "realloc";
99 goto fail;
100 }
101
102 if (ioctl(fd, SIOCGLIFCONF, &lifc) == -1) {
103 opstr = "SIOCGLIFCONF";
104 goto fail;
105 }
106
107 /*
108 * If every lifr_req slot is taken, then additional interfaces must
109 * have been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
110 * Recalculate to make sure we didn't miss any interfaces.
111 */
112 nlifr = lifc.lifc_len / sizeof (struct lifreq);
113 if (nlifr >= lifn.lifn_count)
114 goto again;
115
116 /*
117 * Allocate the address list to return.
118 */
119 if ((ifaddrlist = calloc(nlifr, sizeof (struct ifaddrlist))) == NULL) {
120 opstr = "calloc";
121 goto fail;
122 }
123
124 /*
125 * Populate the address list by querying each underlying interface.
126 * If a query ioctl returns ENXIO, then the interface must have been
127 * removed after the SIOCGLIFCONF completed -- so we just ignore it.
128 */
129 al = ifaddrlist;
130 count = 0;
131 for (lifrp = lifc.lifc_req, i = 0; i < nlifr; i++, lifrp++) {
132 (void) strlcpy(al->device, lifrp->lifr_name, LIFNAMSIZ);
133
134 if (ioctl(fd, SIOCGLIFFLAGS, lifrp) == -1) {
135 if (errno == ENXIO)
136 continue;
137 opstr = "SIOCGLIFFLAGS";
138 goto fail;
139 }
140 al->flags = lifrp->lifr_flags;
141
142 if (ioctl(fd, SIOCGLIFINDEX, lifrp) == -1) {
143 if (errno == ENXIO)
144 continue;
145 opstr = "SIOCGLIFINDEX";
146 goto fail;
147 }
148 al->index = lifrp->lifr_index;
149
150 if (ioctl(fd, SIOCGLIFADDR, lifrp) == -1) {
151 if (errno == ENXIO)
152 continue;
153 opstr = "SIOCGLIFADDR";
154 goto fail;
155 }
156
157 if (family == AF_INET) {
158 sin = (struct sockaddr_in *)&lifrp->lifr_addr;
159 al->addr.addr = sin->sin_addr;
160 } else {
161 sin6 = (struct sockaddr_in6 *)&lifrp->lifr_addr;
162 al->addr.addr6 = sin6->sin6_addr;
163 }
164 al++;
165 count++;
166 }
167
168 (void) close(fd);
169 free(lifc.lifc_buf);
170 if (count == 0) {
171 free(ifaddrlist);
172 *ipaddrp = NULL;
173 return (0);
174 }
175
176 *ipaddrp = ifaddrlist;
177 return (count);
178 fail:
179 if (al == NULL) {
180 (void) snprintf(errbuf, ERRBUFSIZE, "%s: %s", opstr,
181 strerror(errno));
182 } else {
183 (void) snprintf(errbuf, ERRBUFSIZE, "%s: %s: %s", opstr,
184 al->device, strerror(errno));
185 }
186 free(lifc.lifc_buf);
187 free(ifaddrlist);
188 (void) close(fd);
189 return (-1);
190 }
191