diff options
Diffstat (limited to 'contrib/libpcap/fad-helpers.c')
-rw-r--r-- | contrib/libpcap/fad-helpers.c | 884 |
1 files changed, 884 insertions, 0 deletions
diff --git a/contrib/libpcap/fad-helpers.c b/contrib/libpcap/fad-helpers.c new file mode 100644 index 0000000..4860bc5 --- /dev/null +++ b/contrib/libpcap/fad-helpers.c @@ -0,0 +1,884 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef _WIN32 +#include <pcap-stdinc.h> +#else /* _WIN32 */ + +#include <sys/param.h> +#ifndef MSDOS +#include <sys/file.h> +#endif +#include <sys/ioctl.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif + +struct mbuf; /* Squelch compiler warnings on some platforms for */ +struct rtentry; /* declarations in <net/if.h> */ +#include <net/if.h> +#include <netinet/in.h> +#endif /* _WIN32 */ + +#include <ctype.h> +#include <errno.h> +#include <memory.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if !defined(_WIN32) && !defined(__BORLANDC__) +#include <unistd.h> +#endif /* !_WIN32 && !__BORLANDC__ */ +#ifdef HAVE_LIMITS_H +#include <limits.h> +#else +#define INT_MAX 2147483647 +#endif + +#include "pcap-int.h" + +#ifdef HAVE_OS_PROTO_H +#include "os-proto.h" +#endif + +#ifndef _WIN32 +/* Not all systems have IFF_LOOPBACK */ +#ifdef IFF_LOOPBACK +#define ISLOOPBACK(name, flags) ((flags) & IFF_LOOPBACK) +#else +#define ISLOOPBACK(name, flags) ((name)[0] == 'l' && (name)[1] == 'o' && \ + (isdigit((unsigned char)((name)[2])) || (name)[2] == '\0')) +#endif + +#ifdef IFF_UP +#define ISUP(flags) ((flags) & IFF_UP) +#else +#define ISUP(flags) 0 +#endif + +#ifdef IFF_RUNNING +#define ISRUNNING(flags) ((flags) & IFF_RUNNING) +#else +#define ISRUNNING(flags) 0 +#endif + +/* + * Map UN*X-style interface flags to libpcap flags. + */ +bpf_u_int32 +if_flags_to_pcap_flags(const char *name _U_, u_int if_flags) +{ + bpf_u_int32 pcap_flags; + + pcap_flags = 0; + if (ISLOOPBACK(name, if_flags)) + pcap_flags |= PCAP_IF_LOOPBACK; + if (ISUP(if_flags)) + pcap_flags |= PCAP_IF_UP; + if (ISRUNNING(if_flags)) + pcap_flags |= PCAP_IF_RUNNING; + return (pcap_flags); +} +#endif + +static struct sockaddr * +dup_sockaddr(struct sockaddr *sa, size_t sa_length) +{ + struct sockaddr *newsa; + + if ((newsa = malloc(sa_length)) == NULL) + return (NULL); + return (memcpy(newsa, sa, sa_length)); +} + +/* + * Construct a "figure of merit" for an interface, for use when sorting + * the list of interfaces, in which interfaces that are up are superior + * to interfaces that aren't up, interfaces that are up and running are + * superior to interfaces that are up but not running, and non-loopback + * interfaces that are up and running are superior to loopback interfaces, + * and interfaces with the same flags have a figure of merit that's higher + * the lower the instance number. + * + * The goal is to try to put the interfaces most likely to be useful for + * capture at the beginning of the list. + * + * The figure of merit, which is lower the "better" the interface is, + * has the uppermost bit set if the interface isn't running, the bit + * below that set if the interface isn't up, the bit below that set + * if the interface is a loopback interface, and the interface index + * in the 29 bits below that. (Yes, we assume u_int is 32 bits.) + */ +static u_int +get_figure_of_merit(pcap_if_t *dev) +{ + const char *cp; + u_int n; + + if (strcmp(dev->name, "any") == 0) { + /* + * Give the "any" device an artificially high instance + * number, so it shows up after all other non-loopback + * interfaces. + */ + n = 0x1FFFFFFF; /* 29 all-1 bits */ + } else { + /* + * A number at the end of the device name string is + * assumed to be a unit number. + */ + cp = dev->name + strlen(dev->name) - 1; + while (cp-1 >= dev->name && *(cp-1) >= '0' && *(cp-1) <= '9') + cp--; + if (*cp >= '0' && *cp <= '9') + n = atoi(cp); + else + n = 0; + } + if (!(dev->flags & PCAP_IF_RUNNING)) + n |= 0x80000000; + if (!(dev->flags & PCAP_IF_UP)) + n |= 0x40000000; + if (dev->flags & PCAP_IF_LOOPBACK) + n |= 0x20000000; + return (n); +} + +/* + * Try to get a description for a given device. + * Returns a mallocated description if it could and NULL if it couldn't. + * + * XXX - on FreeBSDs that support it, should it get the sysctl named + * "dev.{adapter family name}.{adapter unit}.%desc" to get a description + * of the adapter? Note that "dev.an.0.%desc" is "Aironet PC4500/PC4800" + * with my Cisco 350 card, so the name isn't entirely descriptive. The + * "dev.an.0.%pnpinfo" has a better description, although one might argue + * that the problem is really a driver bug - if it can find out that it's + * a Cisco 340 or 350, rather than an old Aironet card, it should use + * that in the description. + * + * Do NetBSD, DragonflyBSD, or OpenBSD support this as well? FreeBSD + * and OpenBSD let you get a description, but it's not generated by the OS, + * it's set with another ioctl that ifconfig supports; we use that to get + * a description in FreeBSD and OpenBSD, but if there is no such + * description available, it still might be nice to get some description + * string based on the device type or something such as that. + * + * In OS X, the System Configuration framework can apparently return + * names in 10.4 and later. + * + * It also appears that freedesktop.org's HAL offers an "info.product" + * string, but the HAL specification says it "should not be used in any + * UI" and "subsystem/capability specific properties" should be used + * instead and, in any case, I think HAL is being deprecated in + * favor of other stuff such as DeviceKit. DeviceKit doesn't appear + * to have any obvious product information for devices, but maybe + * I haven't looked hard enough. + * + * Using the System Configuration framework, or HAL, or DeviceKit, or + * whatever, would require that libpcap applications be linked with + * the frameworks/libraries in question. That shouldn't be a problem + * for programs linking with the shared version of libpcap (unless + * you're running on AIX - which I think is the only UN*X that doesn't + * support linking a shared library with other libraries on which it + * depends, and having an executable linked only with the first shared + * library automatically pick up the other libraries when started - + * and using HAL or whatever). Programs linked with the static + * version of libpcap would have to use pcap-config with the --static + * flag in order to get the right linker flags in order to pick up + * the additional libraries/frameworks; those programs need that anyway + * for libpcap 1.1 and beyond on Linux, as, by default, it requires + * -lnl. + * + * Do any other UN*Xes, or desktop environments support getting a + * description? + */ +static char * +get_if_description(const char *name) +{ +#ifdef SIOCGIFDESCR + char *description = NULL; + int s; + struct ifreq ifrdesc; +#ifndef IFDESCRSIZE + size_t descrlen = 64; +#else + size_t descrlen = IFDESCRSIZE; +#endif /* IFDESCRSIZE */ + + /* + * Get the description for the interface. + */ + memset(&ifrdesc, 0, sizeof ifrdesc); + strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name); + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s >= 0) { +#ifdef __FreeBSD__ + /* + * On FreeBSD, if the buffer isn't big enough for the + * description, the ioctl succeeds, but the description + * isn't copied, ifr_buffer.length is set to the description + * length, and ifr_buffer.buffer is set to NULL. + */ + for (;;) { + free(description); + if ((description = malloc(descrlen)) != NULL) { + ifrdesc.ifr_buffer.buffer = description; + ifrdesc.ifr_buffer.length = descrlen; + if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) { + if (ifrdesc.ifr_buffer.buffer == + description) + break; + else + descrlen = ifrdesc.ifr_buffer.length; + } else { + /* + * Failed to get interface description. + */ + free(description); + description = NULL; + break; + } + } else + break; + } +#else /* __FreeBSD__ */ + /* + * The only other OS that currently supports + * SIOCGIFDESCR is OpenBSD, and it has no way + * to get the description length - it's clamped + * to a maximum of IFDESCRSIZE. + */ + if ((description = malloc(descrlen)) != NULL) { + ifrdesc.ifr_data = (caddr_t)description; + if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) { + /* + * Failed to get interface description. + */ + free(description); + description = NULL; + } + } +#endif /* __FreeBSD__ */ + close(s); + if (description != NULL && strlen(description) == 0) { + /* + * Description is empty, so discard it. + */ + free(description); + description = NULL; + } + } + +#ifdef __FreeBSD__ + /* + * For FreeBSD, if we didn't get a description, and this is + * a device with a name of the form usbusN, label it as a USB + * bus. + */ + if (description == NULL) { + if (strncmp(name, "usbus", 5) == 0) { + /* + * OK, it begins with "usbus". + */ + long busnum; + char *p; + + errno = 0; + busnum = strtol(name + 5, &p, 10); + if (errno == 0 && p != name + 5 && *p == '\0' && + busnum >= 0 && busnum <= INT_MAX) { + /* + * OK, it's a valid number that's not + * bigger than INT_MAX. Construct + * a description from it. + */ + static const char descr_prefix[] = "USB bus number "; + size_t descr_size; + + /* + * Allow enough room for a 32-bit bus number. + * sizeof (descr_prefix) includes the + * terminating NUL. + */ + descr_size = sizeof (descr_prefix) + 10; + description = malloc(descr_size); + if (description != NULL) { + pcap_snprintf(description, descr_size, + "%s%ld", descr_prefix, busnum); + } + } + } + } +#endif + return (description); +#else /* SIOCGIFDESCR */ + return (NULL); +#endif /* SIOCGIFDESCR */ +} + +/* + * Look for a given device in the specified list of devices. + * + * If we find it, return 0 and set *curdev_ret to point to it. + * + * If we don't find it, check whether we can open it: + * + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. + * + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags and description, and, if that succeeds, return 0 + * and set *curdev_ret to point to the new entry, otherwise + * return PCAP_ERROR and set errbuf to an error message. If we + * weren't given a description, try to get one. + */ +int +add_or_find_if(pcap_if_t **curdev_ret, pcap_if_t **alldevs, const char *name, + bpf_u_int32 flags, const char *description, char *errbuf) +{ + pcap_t *p; + pcap_if_t *curdev, *prevdev, *nextdev; + u_int this_figure_of_merit, nextdev_figure_of_merit; + char open_errbuf[PCAP_ERRBUF_SIZE]; + int ret; + + /* + * Is there already an entry in the list for this interface? + */ + for (curdev = *alldevs; curdev != NULL; curdev = curdev->next) { + if (strcmp(name, curdev->name) == 0) + break; /* yes, we found it */ + } + + if (curdev == NULL) { + /* + * No, we didn't find it. + * + * Can we open this interface for live capture? + * + * We do this check so that interfaces that are + * supplied by the interface enumeration mechanism + * we're using but that don't support packet capture + * aren't included in the list. Loopback interfaces + * on Solaris are an example of this; we don't just + * omit loopback interfaces on all platforms because + * you *can* capture on loopback interfaces on some + * OSes. + * + * On OS X, we don't do this check if the device + * name begins with "wlt"; at least some versions + * of OS X offer monitor mode capturing by having + * a separate "monitor mode" device for each wireless + * adapter, rather than by implementing the ioctls + * that {Free,Net,Open,DragonFly}BSD provide. + * Opening that device puts the adapter into monitor + * mode, which, at least for some adapters, causes + * them to deassociate from the network with which + * they're associated. + * + * Instead, we try to open the corresponding "en" + * device (so that we don't end up with, for users + * without sufficient privilege to open capture + * devices, a list of adapters that only includes + * the wlt devices). + */ +#ifdef __APPLE__ + if (strncmp(name, "wlt", 3) == 0) { + char *en_name; + size_t en_name_len; + + /* + * Try to allocate a buffer for the "en" + * device's name. + */ + en_name_len = strlen(name) - 1; + en_name = malloc(en_name_len + 1); + if (en_name == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + strcpy(en_name, "en"); + strcat(en_name, name + 3); + p = pcap_create(en_name, open_errbuf); + free(en_name); + } else +#endif /* __APPLE */ + p = pcap_create(name, open_errbuf); + if (p == NULL) { + /* + * The attempt to create the pcap_t failed; + * that's probably an indication that we're + * out of memory. + * + * Don't bother including this interface, + * but don't treat it as an error. + */ + *curdev_ret = NULL; + return (0); + } + /* Small snaplen, so we don't try to allocate much memory. */ + pcap_set_snaplen(p, 68); + ret = pcap_activate(p); + pcap_close(p); + switch (ret) { + + case PCAP_ERROR_NO_SUCH_DEVICE: + case PCAP_ERROR_IFACE_NOT_UP: + /* + * We expect these two errors - they're the + * reason we try to open the device. + * + * PCAP_ERROR_NO_SUCH_DEVICE typically means + * "there's no such device *known to the + * OS's capture mechanism*", so, even though + * it might be a valid network interface, you + * can't capture on it (e.g., the loopback + * device in Solaris up to Solaris 10, or + * the vmnet devices in OS X with VMware + * Fusion). We don't include those devices + * in our list of devices, as there's no + * point in doing so - they're not available + * for capture. + * + * PCAP_ERROR_IFACE_NOT_UP means that the + * OS's capture mechanism doesn't work on + * interfaces not marked as up; some capture + * mechanisms *do* support that, so we no + * longer reject those interfaces out of hand, + * but we *do* want to reject them if they + * can't be opened for capture. + */ + *curdev_ret = NULL; + return (0); + } + + /* + * Yes, we can open it, or we can't, for some other + * reason. + * + * If we can open it, we want to offer it for + * capture, as you can capture on it. If we can't, + * we want to offer it for capture, so that, if + * the user tries to capture on it, they'll get + * an error and they'll know why they can't + * capture on it (e.g., insufficient permissions) + * or they'll report it as a problem (and then + * have the error message to provide as information). + * + * Allocate a new entry. + */ + curdev = malloc(sizeof(pcap_if_t)); + if (curdev == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + + /* + * Fill in the entry. + */ + curdev->next = NULL; + curdev->name = strdup(name); + if (curdev->name == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curdev); + return (-1); + } + if (description == NULL) { + /* + * We weren't handed a description for the + * interface, so see if we can generate one + * ourselves. + */ + curdev->description = get_if_description(name); + } else { + /* + * We were handed a description; make a copy. + */ + curdev->description = strdup(description); + if (curdev->description == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curdev->name); + free(curdev); + return (-1); + } + } + curdev->addresses = NULL; /* list starts out as empty */ + curdev->flags = flags; + + /* + * Add it to the list, in the appropriate location. + * First, get the "figure of merit" for this + * interface. + */ + this_figure_of_merit = get_figure_of_merit(curdev); + + /* + * Now look for the last interface with an figure of merit + * less than or equal to the new interface's figure of + * merit. + * + * We start with "prevdev" being NULL, meaning we're before + * the first element in the list. + */ + prevdev = NULL; + for (;;) { + /* + * Get the interface after this one. + */ + if (prevdev == NULL) { + /* + * The next element is the first element. + */ + nextdev = *alldevs; + } else + nextdev = prevdev->next; + + /* + * Are we at the end of the list? + */ + if (nextdev == NULL) { + /* + * Yes - we have to put the new entry + * after "prevdev". + */ + break; + } + + /* + * Is the new interface's figure of merit less + * than the next interface's figure of merit, + * meaning that the new interface is better + * than the next interface? + */ + nextdev_figure_of_merit = get_figure_of_merit(nextdev); + if (this_figure_of_merit < nextdev_figure_of_merit) { + /* + * Yes - we should put the new entry + * before "nextdev", i.e. after "prevdev". + */ + break; + } + + prevdev = nextdev; + } + + /* + * Insert before "nextdev". + */ + curdev->next = nextdev; + + /* + * Insert after "prevdev" - unless "prevdev" is null, + * in which case this is the first interface. + */ + if (prevdev == NULL) { + /* + * This is the first interface. Pass back a + * pointer to it, and put "curdev" before + * "nextdev". + */ + *alldevs = curdev; + } else + prevdev->next = curdev; + } + + *curdev_ret = curdev; + return (0); +} + +/* + * Try to get a description for a given device, and then look for that + * device in the specified list of devices. + * + * If we find it, then, if the specified address isn't null, add it to + * the list of addresses for the device and return 0. + * + * If we don't find it, check whether we can open it: + * + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. + * + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags, and, if that succeeds, add the specified address + * to its list of addresses if that address is non-null, set + * *curdev_ret to point to the new entry, and return 0, otherwise + * return PCAP_ERROR and set errbuf to an error message. + * + * (We can get called with a null address because we might get a list + * of interface name/address combinations from the underlying OS, with + * the address being absent in some cases, rather than a list of + * interfaces with each interface having a list of addresses, so this + * call may be the only call made to add to the list, and we want to + * add interfaces even if they have no addresses.) + */ +int +add_addr_to_iflist(pcap_if_t **alldevs, const char *name, bpf_u_int32 flags, + struct sockaddr *addr, size_t addr_size, + struct sockaddr *netmask, size_t netmask_size, + struct sockaddr *broadaddr, size_t broadaddr_size, + struct sockaddr *dstaddr, size_t dstaddr_size, + char *errbuf) +{ + pcap_if_t *curdev; + + if (add_or_find_if(&curdev, alldevs, name, flags, NULL, errbuf) == -1) { + /* + * Error - give up. + */ + return (-1); + } + if (curdev == NULL) { + /* + * Device wasn't added because it can't be opened. + * Not a fatal error. + */ + return (0); + } + + if (addr == NULL) { + /* + * There's no address to add; this entry just meant + * "here's a new interface". + */ + return (0); + } + + /* + * "curdev" is an entry for this interface, and we have an + * address for it; add an entry for that address to the + * interface's list of addresses. + * + * Allocate the new entry and fill it in. + */ + return (add_addr_to_dev(curdev, addr, addr_size, netmask, + netmask_size, broadaddr, broadaddr_size, dstaddr, + dstaddr_size, errbuf)); +} + +/* + * Add an entry to the list of addresses for an interface. + * "curdev" is the entry for that interface. + * If this is the first IP address added to the interface, move it + * in the list as appropriate. + */ +int +add_addr_to_dev(pcap_if_t *curdev, + struct sockaddr *addr, size_t addr_size, + struct sockaddr *netmask, size_t netmask_size, + struct sockaddr *broadaddr, size_t broadaddr_size, + struct sockaddr *dstaddr, size_t dstaddr_size, + char *errbuf) +{ + pcap_addr_t *curaddr, *prevaddr, *nextaddr; + + curaddr = malloc(sizeof(pcap_addr_t)); + if (curaddr == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + return (-1); + } + + curaddr->next = NULL; + if (addr != NULL) { + curaddr->addr = dup_sockaddr(addr, addr_size); + if (curaddr->addr == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + free(curaddr); + return (-1); + } + } else + curaddr->addr = NULL; + + if (netmask != NULL) { + curaddr->netmask = dup_sockaddr(netmask, netmask_size); + if (curaddr->netmask == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->netmask = NULL; + + if (broadaddr != NULL) { + curaddr->broadaddr = dup_sockaddr(broadaddr, broadaddr_size); + if (curaddr->broadaddr == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + if (curaddr->netmask != NULL) + free(curaddr->netmask); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->broadaddr = NULL; + + if (dstaddr != NULL) { + curaddr->dstaddr = dup_sockaddr(dstaddr, dstaddr_size); + if (curaddr->dstaddr == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc: %s", pcap_strerror(errno)); + if (curaddr->broadaddr != NULL) + free(curaddr->broadaddr); + if (curaddr->netmask != NULL) + free(curaddr->netmask); + if (curaddr->addr != NULL) + free(curaddr->addr); + free(curaddr); + return (-1); + } + } else + curaddr->dstaddr = NULL; + + /* + * Find the end of the list of addresses. + */ + for (prevaddr = curdev->addresses; prevaddr != NULL; prevaddr = nextaddr) { + nextaddr = prevaddr->next; + if (nextaddr == NULL) { + /* + * This is the end of the list. + */ + break; + } + } + + if (prevaddr == NULL) { + /* + * The list was empty; this is the first member. + */ + curdev->addresses = curaddr; + } else { + /* + * "prevaddr" is the last member of the list; append + * this member to it. + */ + prevaddr->next = curaddr; + } + + return (0); +} + +/* + * Look for a given device in the specified list of devices. + * + * If we find it, return 0. + * + * If we don't find it, check whether we can open it: + * + * If that fails with PCAP_ERROR_NO_SUCH_DEVICE or + * PCAP_ERROR_IFACE_NOT_UP, don't attempt to add an entry for + * it, as that probably means it exists but doesn't support + * packet capture. + * + * Otherwise, attempt to add an entry for it, with the specified + * ifnet flags and description, and, if that succeeds, return 0 + * and set *curdev_ret to point to the new entry, otherwise + * return PCAP_ERROR and set errbuf to an error message. + */ +int +pcap_add_if(pcap_if_t **devlist, const char *name, u_int flags, + const char *description, char *errbuf) +{ + pcap_if_t *curdev; + + return (add_or_find_if(&curdev, devlist, name, flags, description, + errbuf)); +} + + +/* + * Free a list of interfaces. + */ +void +pcap_freealldevs(pcap_if_t *alldevs) +{ + pcap_if_t *curdev, *nextdev; + pcap_addr_t *curaddr, *nextaddr; + + for (curdev = alldevs; curdev != NULL; curdev = nextdev) { + nextdev = curdev->next; + + /* + * Free all addresses. + */ + for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) { + nextaddr = curaddr->next; + if (curaddr->addr) + free(curaddr->addr); + if (curaddr->netmask) + free(curaddr->netmask); + if (curaddr->broadaddr) + free(curaddr->broadaddr); + if (curaddr->dstaddr) + free(curaddr->dstaddr); + free(curaddr); + } + + /* + * Free the name string. + */ + free(curdev->name); + + /* + * Free the description string, if any. + */ + if (curdev->description != NULL) + free(curdev->description); + + /* + * Free the interface. + */ + free(curdev); + } +} |