Merge from vendor branch GCC:
[dragonfly.git] / contrib / libpcap-0.8.3 / fad-glifc.c
1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2 /*
3  * Copyright (c) 1994, 1995, 1996, 1997, 1998
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by the Computer Systems
17  *      Engineering Group at Lawrence Berkeley Laboratory.
18  * 4. Neither the name of the University nor of the Laboratory may be used
19  *    to endorse or promote products derived from this software without
20  *    specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #ifndef lint
36 static const char rcsid[] _U_ =
37     "@(#) $Header: /tcpdump/master/libpcap/fad-glifc.c,v 1.2.2.1 2003/11/15 23:26:39 guy Exp $ (LBL)";
38 #endif
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #include <sys/param.h>
45 #include <sys/file.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
48 #ifdef HAVE_SYS_SOCKIO_H
49 #include <sys/sockio.h>
50 #endif
51 #include <sys/time.h>                           /* concession to AIX */
52
53 struct mbuf;            /* Squelch compiler warnings on some platforms for */
54 struct rtentry;         /* declarations in <net/if.h> */
55 #include <net/if.h>
56 #include <netinet/in.h>
57
58 #include <ctype.h>
59 #include <errno.h>
60 #include <memory.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65
66 #include "pcap-int.h"
67
68 #ifdef HAVE_OS_PROTO_H
69 #include "os-proto.h"
70 #endif
71
72 /*
73  * Get a list of all interfaces that are up and that we can open.
74  * Returns -1 on error, 0 otherwise.
75  * The list, as returned through "alldevsp", may be null if no interfaces
76  * were up and could be opened.
77  *
78  * This is the implementation used on platforms that have SIOCLGIFCONF
79  * but don't have "getifaddrs()".  (Solaris 8 and later; we use
80  * SIOCLGIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
81  */
82 int
83 pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
84 {
85         pcap_if_t *devlist = NULL;
86         register int fd4, fd6, fd;
87         register struct lifreq *ifrp, *ifend;
88         struct lifnum ifn;
89         struct lifconf ifc;
90         char *buf = NULL;
91         unsigned buf_size;
92         struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
93         struct sockaddr *netmask, *broadaddr, *dstaddr;
94         int ret = 0;
95
96         /*
97          * Create a socket from which to fetch the list of interfaces,
98          * and from which to fetch IPv4 information.
99          */
100         fd4 = socket(AF_INET, SOCK_DGRAM, 0);
101         if (fd4 < 0) {
102                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
103                     "socket: %s", pcap_strerror(errno));
104                 return (-1);
105         }
106
107         /*
108          * Create a socket from which to fetch IPv6 information.
109          */
110         fd6 = socket(AF_INET6, SOCK_DGRAM, 0);
111         if (fd6 < 0) {
112                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
113                     "socket: %s", pcap_strerror(errno));
114                 (void)close(fd4);
115                 return (-1);
116         }
117
118         /*
119          * How many entries will SIOCGLIFCONF return?
120          */
121         ifn.lifn_family = AF_UNSPEC;
122         ifn.lifn_flags = 0;
123         ifn.lifn_count = 0;
124         if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) {
125                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
126                     "SIOCGLIFNUM: %s", pcap_strerror(errno));
127                 (void)close(fd6);
128                 (void)close(fd4);
129                 return (-1);
130         }
131
132         /*
133          * Allocate a buffer for those entries.
134          */
135         buf_size = ifn.lifn_count * sizeof (struct lifreq);
136         buf = malloc(buf_size);
137         if (buf == NULL) {
138                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
139                     "malloc: %s", pcap_strerror(errno));
140                 (void)close(fd6);
141                 (void)close(fd4);
142                 return (-1);
143         }
144
145         /*
146          * Get the entries.
147          */
148         ifc.lifc_len = buf_size;
149         ifc.lifc_buf = buf;
150         ifc.lifc_family = AF_UNSPEC;
151         ifc.lifc_flags = 0;
152         memset(buf, 0, buf_size);
153         if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) {
154                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
155                     "SIOCGLIFCONF: %s", pcap_strerror(errno));
156                 (void)close(fd6);
157                 (void)close(fd4);
158                 free(buf);
159                 return (-1);
160         }
161
162         /*
163          * Loop over the entries.
164          */
165         ifrp = (struct lifreq *)buf;
166         ifend = (struct lifreq *)(buf + ifc.lifc_len);
167
168         for (; ifrp < ifend; ifrp++) {
169                 /*
170                  * IPv6 or not?
171                  */
172                 if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
173                         fd = fd6;
174                 else
175                         fd = fd4;
176
177                 /*
178                  * Get the flags for this interface, and skip it if it's
179                  * not up.
180                  */
181                 strncpy(ifrflags.lifr_name, ifrp->lifr_name,
182                     sizeof(ifrflags.lifr_name));
183                 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
184                         if (errno == ENXIO)
185                                 continue;
186                         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
187                             "SIOCGLIFFLAGS: %.*s: %s",
188                             (int)sizeof(ifrflags.lifr_name),
189                             ifrflags.lifr_name,
190                             pcap_strerror(errno));
191                         ret = -1;
192                         break;
193                 }
194                 if (!(ifrflags.lifr_flags & IFF_UP))
195                         continue;
196
197                 /*
198                  * Get the netmask for this address on this interface.
199                  */
200                 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
201                     sizeof(ifrnetmask.lifr_name));
202                 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
203                     sizeof(ifrnetmask.lifr_addr));
204                 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
205                         if (errno == EADDRNOTAVAIL) {
206                                 /*
207                                  * Not available.
208                                  */
209                                 netmask = NULL;
210                         } else {
211                                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
212                                     "SIOCGLIFNETMASK: %.*s: %s",
213                                     (int)sizeof(ifrnetmask.lifr_name),
214                                     ifrnetmask.lifr_name,
215                                     pcap_strerror(errno));
216                                 ret = -1;
217                                 break;
218                         }
219                 } else
220                         netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
221
222                 /*
223                  * Get the broadcast address for this address on this
224                  * interface (if any).
225                  */
226                 if (ifrflags.lifr_flags & IFF_BROADCAST) {
227                         strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
228                             sizeof(ifrbroadaddr.lifr_name));
229                         memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
230                             sizeof(ifrbroadaddr.lifr_addr));
231                         if (ioctl(fd, SIOCGLIFBRDADDR,
232                             (char *)&ifrbroadaddr) < 0) {
233                                 if (errno == EADDRNOTAVAIL) {
234                                         /*
235                                          * Not available.
236                                          */
237                                         broadaddr = NULL;
238                                 } else {
239                                         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
240                                             "SIOCGLIFBRDADDR: %.*s: %s",
241                                             (int)sizeof(ifrbroadaddr.lifr_name),
242                                             ifrbroadaddr.lifr_name,
243                                             pcap_strerror(errno));
244                                         ret = -1;
245                                         break;
246                                 }
247                         } else
248                                 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
249                 } else {
250                         /*
251                          * Not a broadcast interface, so no broadcast
252                          * address.
253                          */
254                         broadaddr = NULL;
255                 }
256
257                 /*
258                  * Get the destination address for this address on this
259                  * interface (if any).
260                  */
261                 if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
262                         strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
263                             sizeof(ifrdstaddr.lifr_name));
264                         memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
265                             sizeof(ifrdstaddr.lifr_addr));
266                         if (ioctl(fd, SIOCGLIFDSTADDR,
267                             (char *)&ifrdstaddr) < 0) {
268                                 if (errno == EADDRNOTAVAIL) {
269                                         /*
270                                          * Not available.
271                                          */
272                                         dstaddr = NULL;
273                                 } else {
274                                         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
275                                             "SIOCGLIFDSTADDR: %.*s: %s",
276                                             (int)sizeof(ifrdstaddr.lifr_name),
277                                             ifrdstaddr.lifr_name,
278                                             pcap_strerror(errno));
279                                         ret = -1;
280                                         break;
281                                 }
282                         } else
283                                 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
284                 } else
285                         dstaddr = NULL;
286
287                 /*
288                  * Add information for this address to the list.
289                  */
290                 if (add_addr_to_iflist(&devlist, ifrp->lifr_name,
291                     ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr,
292                     sizeof (struct sockaddr_storage),
293                     netmask, sizeof (struct sockaddr_storage),
294                     broadaddr, sizeof (struct sockaddr_storage),
295                     dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
296                         ret = -1;
297                         break;
298                 }
299         }
300         free(buf);
301         (void)close(fd6);
302         (void)close(fd4);
303
304         if (ret != -1) {
305                 /*
306                  * We haven't had any errors yet; do any platform-specific
307                  * operations to add devices.
308                  */
309                 if (pcap_platform_finddevs(&devlist, errbuf) < 0)
310                         ret = -1;
311         }
312
313         if (ret == -1) {
314                 /*
315                  * We had an error; free the list we've been constructing.
316                  */
317                 if (devlist != NULL) {
318                         pcap_freealldevs(devlist);
319                         devlist = NULL;
320                 }
321         }
322
323         *alldevsp = devlist;
324         return (ret);
325 }