aboutsummaryrefslogtreecommitdiffstats
path: root/pcap-bpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'pcap-bpf.c')
-rw-r--r--pcap-bpf.c1279
1 files changed, 1089 insertions, 190 deletions
diff --git a/pcap-bpf.c b/pcap-bpf.c
index f298b10..6e311f4 100644
--- a/pcap-bpf.c
+++ b/pcap-bpf.c
@@ -20,7 +20,7 @@
*/
#ifndef lint
static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.103 2008-01-29 10:12:55 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.104 2008-04-04 19:37:45 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@@ -92,6 +92,10 @@ static int odmlockid = 0;
#include <string.h>
#include <unistd.h>
+#ifdef HAVE_NET_IF_MEDIA_H
+# include <net/if_media.h>
+#endif
+
#include "pcap-int.h"
#ifdef HAVE_DAG_API
@@ -102,10 +106,346 @@ static int odmlockid = 0;
#include "os-proto.h"
#endif
+#ifdef BIOCGDLTLIST
+# if (defined(HAVE_NET_IF_MEDIA_H) && defined(IFM_IEEE80211)) && !defined(__APPLE__)
+#define HAVE_BSD_IEEE80211
+# endif
+
+# if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)
+static int find_802_11(struct bpf_dltlist *);
+
+# ifdef HAVE_BSD_IEEE80211
+static int monitor_mode(pcap_t *, int);
+# endif
+
+# if defined(__APPLE__)
+static void remove_en(pcap_t *);
+static void remove_802_11(pcap_t *);
+# endif
+
+# endif /* defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) */
+
+#endif /* BIOCGDLTLIST */
+
+/*
+ * We include the OS's <net/bpf.h>, not our "pcap/bpf.h", so we probably
+ * don't get DLT_DOCSIS defined.
+ */
+#ifndef DLT_DOCSIS
+#define DLT_DOCSIS 143
+#endif
+
+/*
+ * On OS X, we don't even get any of the 802.11-plus-radio-header DLT_'s
+ * defined, even though some of them are used by various Airport drivers.
+ */
+#ifndef DLT_PRISM_HEADER
+#define DLT_PRISM_HEADER 119
+#endif
+#ifndef DLT_AIRONET_HEADER
+#define DLT_AIRONET_HEADER 120
+#endif
+#ifndef DLT_IEEE802_11_RADIO
+#define DLT_IEEE802_11_RADIO 127
+#endif
+#ifndef DLT_IEEE802_11_RADIO_AVS
+#define DLT_IEEE802_11_RADIO_AVS 163
+#endif
+
+static int pcap_can_set_rfmon_bpf(pcap_t *p);
+static int pcap_activate_bpf(pcap_t *p);
static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp);
static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t);
static int pcap_set_datalink_bpf(pcap_t *p, int dlt);
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+ pcap_t *p;
+
+#ifdef HAVE_DAG_API
+ if (strstr(device, "dag"))
+ return (dag_create(device, ebuf));
+#endif /* HAVE_DAG_API */
+
+ p = pcap_create_common(device, ebuf);
+ if (p == NULL)
+ return (NULL);
+
+ p->activate_op = pcap_activate_bpf;
+ p->can_set_rfmon_op = pcap_can_set_rfmon_bpf;
+ return (p);
+}
+
+static int
+bpf_open(pcap_t *p)
+{
+ int fd;
+#ifdef HAVE_CLONING_BPF
+ static const char device[] = "/dev/bpf";
+#else
+ int n = 0;
+ char device[sizeof "/dev/bpf0000000000"];
+#endif
+
+#ifdef _AIX
+ /*
+ * Load the bpf driver, if it isn't already loaded,
+ * and create the BPF device entries, if they don't
+ * already exist.
+ */
+ if (bpf_load(p->errbuf) == -1)
+ return (-1);
+#endif
+
+#ifdef HAVE_CLONING_BPF
+ if ((fd = open(device, O_RDWR)) == -1 &&
+ (errno != EACCES || (fd = open(device, O_RDONLY)) == -1))
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "(cannot open device) %s: %s", device, pcap_strerror(errno));
+#else
+ /*
+ * Go through all the minors and find one that isn't in use.
+ */
+ do {
+ (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+ /*
+ * Initially try a read/write open (to allow the inject
+ * method to work). If that fails due to permission
+ * issues, fall back to read-only. This allows a
+ * non-root user to be granted specific access to pcap
+ * capabilities via file permissions.
+ *
+ * XXX - we should have an API that has a flag that
+ * controls whether to open read-only or read-write,
+ * so that denial of permission to send (or inability
+ * to send, if sending packets isn't supported on
+ * the device in question) can be indicated at open
+ * time.
+ */
+ fd = open(device, O_RDWR);
+ if (fd == -1 && errno == EACCES)
+ fd = open(device, O_RDONLY);
+ } while (fd < 0 && errno == EBUSY);
+
+ /*
+ * XXX better message for all minors used
+ */
+ if (fd < 0)
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
+ device, pcap_strerror(errno));
+#endif
+
+ return (fd);
+}
+
+#ifdef BIOCGDLTLIST
+static int
+get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf)
+{
+ memset(bdlp, 0, sizeof(*bdlp));
+ if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) == 0) {
+ u_int i;
+ int is_ethernet;
+
+ bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1));
+ if (bdlp->bfl_list == NULL) {
+ (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+ pcap_strerror(errno));
+ return (-1);
+ }
+
+ if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) {
+ (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "BIOCGDLTLIST: %s", pcap_strerror(errno));
+ free(bdlp->bfl_list);
+ return (-1);
+ }
+
+ /*
+ * OK, for real Ethernet devices, add DLT_DOCSIS to the
+ * list, so that an application can let you choose it,
+ * in case you're capturing DOCSIS traffic that a Cisco
+ * Cable Modem Termination System is putting out onto
+ * an Ethernet (it doesn't put an Ethernet header onto
+ * the wire, it puts raw DOCSIS frames out on the wire
+ * inside the low-level Ethernet framing).
+ *
+ * A "real Ethernet device" is defined here as a device
+ * that has a link-layer type of DLT_EN10MB and that has
+ * no alternate link-layer types; that's done to exclude
+ * 802.11 interfaces (which might or might not be the
+ * right thing to do, but I suspect it is - Ethernet <->
+ * 802.11 bridges would probably badly mishandle frames
+ * that don't have Ethernet headers).
+ */
+ if (v == DLT_EN10MB) {
+ is_ethernet = 1;
+ for (i = 0; i < bdlp->bfl_len; i++) {
+ if (bdlp->bfl_list[i] != DLT_EN10MB) {
+ is_ethernet = 0;
+ break;
+ }
+ }
+ if (is_ethernet) {
+ /*
+ * We reserved one more slot at the end of
+ * the list.
+ */
+ bdlp->bfl_list[bdlp->bfl_len] = DLT_DOCSIS;
+ bdlp->bfl_len++;
+ }
+ }
+ } else {
+ /*
+ * EINVAL just means "we don't support this ioctl on
+ * this device"; don't treat it as an error.
+ */
+ if (errno != EINVAL) {
+ (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "BIOCGDLTLIST: %s", pcap_strerror(errno));
+ return (-1);
+ }
+ }
+ return (0);
+}
+#endif
+
+static int
+pcap_can_set_rfmon_bpf(pcap_t *p)
+{
+#if defined(__APPLE__)
+ struct utsname osinfo;
+ struct ifreq ifr;
+ int fd;
+#ifdef BIOCGDLTLIST
+ struct bpf_dltlist bdl;
+#endif
+
+ /*
+ * The joys of monitor mode on OS X.
+ *
+ * Prior to 10.4, it's not supported at all.
+ *
+ * In 10.4, if adapter enN supports monitor mode, there's a
+ * wltN adapter corresponding to it; you open it, instead of
+ * enN, to get monitor mode. You get whatever link-layer
+ * headers it supplies.
+ *
+ * In 10.5, and, we assume, later releases, if adapter enN
+ * supports monitor mode, it offers, among its selectable
+ * DLT_ values, values that let you get the 802.11 header;
+ * selecting one of those values puts the adapter into monitor
+ * mode (i.e., you can't get 802.11 headers except in monitor
+ * mode, and you can't get Ethernet headers in monitor mode).
+ */
+ if (uname(&osinfo) == -1) {
+ /*
+ * Can't get the OS version; just say "no".
+ */
+ return (0);
+ }
+ /*
+ * We assume osinfo.sysname is "Darwin", because
+ * __APPLE__ is defined. We just check the version.
+ */
+ if (osinfo.release[0] < '8' && osinfo.release[1] == '.') {
+ /*
+ * 10.3 (Darwin 7.x) or earlier.
+ * Monitor mode not supported.
+ */
+ return (0);
+ }
+ if (osinfo.release[0] == '8' && osinfo.release[1] == '.') {
+ /*
+ * 10.4 (Darwin 8.x). s/en/wlt/, and check
+ * whether the device exists.
+ */
+ if (strncmp(p->opt.source, "en", 2) != 0) {
+ /*
+ * Not an enN device; no monitor mode.
+ */
+ return (0);
+ }
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1) {
+ (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "socket: %s", pcap_strerror(errno));
+ return (PCAP_ERROR);
+ }
+ strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name));
+ strlcat(ifr.ifr_name, p->opt.source + 2, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+ /*
+ * No such device?
+ */
+ close(fd);
+ return (0);
+ }
+ close(fd);
+ return (1);
+ }
+
+#ifdef BIOCGDLTLIST
+ /*
+ * Everything else is 10.5 or later; for those,
+ * we just open the enN device, and check whether
+ * we have any 802.11 devices.
+ *
+ * First, open a BPF device.
+ */
+ fd = bpf_open(p);
+ if (fd < 0)
+ return (PCAP_ERROR);
+
+ /*
+ * Now bind to the device.
+ */
+ (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "BIOCSETIF: %s: %s",
+ p->opt.source, pcap_strerror(errno));
+ close(fd);
+ return (PCAP_ERROR);
+ }
+
+ /*
+ * We know the default link type -- now determine all the DLTs
+ * this interface supports. If this fails with EINVAL, it's
+ * not fatal; we just don't get to use the feature later.
+ * (We don't care about DLT_DOCSIS, so we pass DLT_NULL
+ * as the default DLT for this adapter.)
+ */
+ if (get_dlt_list(fd, DLT_NULL, &bdl, p->errbuf) == -1) {
+ close(fd);
+ return (PCAP_ERROR);
+ }
+ if (find_802_11(&bdl) != -1) {
+ /*
+ * We have an 802.11 DLT, so we can set monitor mode.
+ */
+ free(bdl.bfl_list);
+ close(fd);
+ return (1);
+ }
+ free(bdl.bfl_list);
+#endif /* BIOCGDLTLIST */
+ return (0);
+#elif defined(HAVE_BSD_IEEE80211)
+ int ret;
+
+ ret = monitor_mode(p, 0);
+ if (ret == PCAP_ERROR_RFMON_NOTSUP)
+ return (0); /* not an error, just a "can't do" */
+ if (ret == 0)
+ return (1); /* success */
+ return (ret);
+#else
+ return (0);
+#endif
+}
+
static int
pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps)
{
@@ -516,169 +856,348 @@ bpf_load(char *errbuf)
}
#endif
-static inline int
-bpf_open(pcap_t *p, char *errbuf)
+/*
+ * Turn off rfmon mode if necessary.
+ */
+static void
+pcap_close_bpf(pcap_t *p)
{
- int fd;
-#ifdef HAVE_CLONING_BPF
- static const char device[] = "/dev/bpf";
-#else
- int n = 0;
- char device[sizeof "/dev/bpf0000000000"];
-#endif
-
-#ifdef _AIX
- /*
- * Load the bpf driver, if it isn't already loaded,
- * and create the BPF device entries, if they don't
- * already exist.
- */
- if (bpf_load(errbuf) == -1)
- return (-1);
+#ifdef HAVE_BSD_IEEE80211
+ int sock;
+ struct ifmediareq req;
+ struct ifreq ifr;
#endif
-#ifdef HAVE_CLONING_BPF
- if ((fd = open(device, O_RDWR)) == -1 &&
- (errno != EACCES || (fd = open(device, O_RDONLY)) == -1))
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "(cannot open device) %s: %s", device, pcap_strerror(errno));
-#else
- /*
- * Go through all the minors and find one that isn't in use.
- */
- do {
- (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+ if (p->md.must_clear != 0) {
/*
- * Initially try a read/write open (to allow the inject
- * method to work). If that fails due to permission
- * issues, fall back to read-only. This allows a
- * non-root user to be granted specific access to pcap
- * capabilities via file permissions.
- *
- * XXX - we should have an API that has a flag that
- * controls whether to open read-only or read-write,
- * so that denial of permission to send (or inability
- * to send, if sending packets isn't supported on
- * the device in question) can be indicated at open
- * time.
+ * There's something we have to do when closing this
+ * pcap_t.
*/
- fd = open(device, O_RDWR);
- if (fd == -1 && errno == EACCES)
- fd = open(device, O_RDONLY);
- } while (fd < 0 && errno == EBUSY);
+#ifdef HAVE_BSD_IEEE80211
+ if (p->md.must_clear & MUST_CLEAR_RFMON) {
+ /*
+ * We put the interface into rfmon mode;
+ * take it out of rfmon mode.
+ *
+ * XXX - if somebody else wants it in rfmon
+ * mode, this code cannot know that, so it'll take
+ * it out of rfmon mode.
+ */
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == -1) {
+ fprintf(stderr,
+ "Can't restore interface flags (socket() failed: %s).\n"
+ "Please adjust manually.\n",
+ strerror(errno));
+ } else {
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifm_name, p->md.device,
+ sizeof(req.ifm_name));
+ if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
+ fprintf(stderr,
+ "Can't restore interface flags (SIOCGIFMEDIA failed: %s).\n"
+ "Please adjust manually.\n",
+ strerror(errno));
+ } else {
+ if (req.ifm_current & IFM_IEEE80211_MONITOR) {
+ /*
+ * Rfmon mode is currently on;
+ * turn it off.
+ */
+ memset(&ifr, 0, sizeof(ifr));
+ (void)strncpy(ifr.ifr_name,
+ p->md.device,
+ sizeof(ifr.ifr_name));
+ ifr.ifr_media =
+ req.ifm_current & ~IFM_IEEE80211_MONITOR;
+ if (ioctl(sock, SIOCSIFMEDIA,
+ &ifr) == -1) {
+ fprintf(stderr,
+ "Can't restore interface flags (SIOCSIFMEDIA failed: %s).\n"
+ "Please adjust manually.\n",
+ strerror(errno));
+ }
+ }
+ }
+ close(sock);
+ }
+ }
+#endif /* HAVE_BSD_IEEE80211 */
- /*
- * XXX better message for all minors used
- */
- if (fd < 0)
- snprintf(errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
- device, pcap_strerror(errno));
-#endif
+ /*
+ * Take this pcap out of the list of pcaps for which we
+ * have to take the interface out of some mode.
+ */
+ pcap_remove_from_pcaps_to_close(p);
+ }
- return (fd);
+ if (p->md.device != NULL)
+ free(p->md.device);
+ p->md.device = NULL;
+ pcap_close_common(p);
}
-/*
- * We include the OS's <net/bpf.h>, not our "pcap/bpf.h", so we probably
- * don't get DLT_DOCSIS defined.
- */
-#ifndef DLT_DOCSIS
-#define DLT_DOCSIS 143
+static int
+check_setif_failure(pcap_t *p, int error)
+{
+#ifdef __APPLE__
+ int fd;
+ struct ifreq ifr;
+ int err;
#endif
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
- char *ebuf)
+ if (error == ENXIO) {
+ /*
+ * No such device exists.
+ */
+#ifdef __APPLE__
+ if (p->opt.rfmon && strncmp(p->opt.source, "wlt", 3) == 0) {
+ /*
+ * Monitor mode was requested, and we're trying
+ * to open a "wltN" device. Assume that this
+ * is 10.4 and that we were asked to open an
+ * "enN" device; if that device exists, return
+ * "monitor mode not supported on the device".
+ */
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd != -1) {
+ strlcpy(ifr.ifr_name, "en",
+ sizeof(ifr.ifr_name));
+ strlcat(ifr.ifr_name, p->opt.source + 3,
+ sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+ /*
+ * We assume this failed because
+ * the underlying device doesn't
+ * exist.
+ */
+ err = PCAP_ERROR_NO_SUCH_DEVICE;
+ } else {
+ /*
+ * The underlying "enN" device
+ * exists, but there's no
+ * corresponding "wltN" device;
+ * that means that the "enN"
+ * device doesn't support
+ * monitor mode, probably because
+ * it's an Ethernet device rather
+ * than a wireless device.
+ */
+ err = PCAP_ERROR_RFMON_NOTSUP;
+ }
+ close(fd);
+ } else {
+ /*
+ * We can't find out whether there's
+ * an underlying "enN" device, so
+ * just report "no such device".
+ */
+ err = PCAP_ERROR_NO_SUCH_DEVICE;
+ }
+ return (err);
+ }
+#endif
+ /*
+ * No such device.
+ */
+ return (PCAP_ERROR_NO_SUCH_DEVICE);
+ } else {
+ /*
+ * Some other error; fill in the error string, and
+ * return PCAP_ERROR.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
+ p->opt.source, pcap_strerror(errno));
+ return (PCAP_ERROR);
+ }
+}
+
+static int
+pcap_activate_bpf(pcap_t *p)
{
+ int err;
int fd;
struct ifreq ifr;
struct bpf_version bv;
+#ifdef __APPLE__
+ char *wltdev = NULL;
+#endif
#ifdef BIOCGDLTLIST
struct bpf_dltlist bdl;
+#if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)
+ int new_dlt;
#endif
+#endif /* BIOCGDLTLIST */
#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
u_int spoof_eth_src = 1;
#endif
u_int v;
- pcap_t *p;
struct bpf_insn total_insn;
struct bpf_program total_prog;
struct utsname osinfo;
+ int have_osinfo = 0;
-#ifdef HAVE_DAG_API
- if (strstr(device, "dag")) {
- return dag_open_live(device, snaplen, promisc, to_ms, ebuf);
- }
-#endif /* HAVE_DAG_API */
-
- p = (pcap_t *)malloc(sizeof(*p));
- if (p == NULL) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
- pcap_strerror(errno));
- return (NULL);
- }
- memset(p, 0, sizeof(*p));
- fd = bpf_open(p, ebuf);
- if (fd < 0)
+ fd = bpf_open(p);
+ if (fd < 0) {
+ err = PCAP_ERROR;
goto bad;
+ }
p->fd = fd;
- p->snapshot = snaplen;
if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
if (bv.bv_major != BPF_MAJOR_VERSION ||
bv.bv_minor < BPF_MINOR_VERSION) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"kernel bpf filter out of date");
+ err = PCAP_ERROR;
goto bad;
}
+ p->md.device = strdup(p->opt.source);
+ if (p->md.device == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s",
+ pcap_strerror(errno));
+ return PCAP_ERROR;
+ }
+
/*
- * Try finding a good size for the buffer; 32768 may be too
- * big, so keep cutting it in half until we find a size
- * that works, or run out of sizes to try. If the default
- * is larger, don't make it smaller.
- *
- * XXX - there should be a user-accessible hook to set the
- * initial buffer size.
+ * Attempt to find out the version of the OS on which we're running.
*/
- if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 32768)
- v = 32768;
- for ( ; v != 0; v >>= 1) {
- /* Ignore the return value - this is because the call fails
- * on BPF systems that don't have kernel malloc. And if
- * the call fails, it's no big deal, we just continue to
- * use the standard buffer size.
- */
- (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
+ if (uname(&osinfo) == 0)
+ have_osinfo = 1;
- (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
- if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
- break; /* that size worked; we're done */
+#ifdef __APPLE__
+ /*
+ * See comment in pcap_can_set_rfmon_bpf() for an explanation
+ * of why we check the version number.
+ */
+ if (p->opt.rfmon) {
+ if (have_osinfo) {
+ /*
+ * We assume osinfo.sysname is "Darwin", because
+ * __APPLE__ is defined. We just check the version.
+ */
+ if (osinfo.release[0] < '8' &&
+ osinfo.release[1] == '.') {
+ /*
+ * 10.3 (Darwin 7.x) or earlier.
+ */
+ err = PCAP_ERROR_RFMON_NOTSUP;
+ goto bad;
+ }
+ if (osinfo.release[0] == '8' &&
+ osinfo.release[1] == '.') {
+ /*
+ * 10.4 (Darwin 8.x). s/en/wlt/
+ */
+ if (strncmp(p->opt.source, "en", 2) != 0) {
+ /*
+ * Not an enN device; no monitor
+ * mode.
+ */
+ err = PCAP_ERROR_RFMON_NOTSUP;
+ goto bad;
+ }
+ wltdev = malloc(strlen(p->opt.source) + 2);
+ if (wltdev == NULL) {
+ (void)snprintf(p->errbuf,
+ PCAP_ERRBUF_SIZE, "malloc: %s",
+ pcap_strerror(errno));
+ err = PCAP_ERROR;
+ goto bad;
+ }
+ strcpy(wltdev, "wlt");
+ strcat(wltdev, p->opt.source + 2);
+ free(p->opt.source);
+ p->opt.source = wltdev;
+ }
+ /*
+ * Everything else is 10.5 or later; for those,
+ * we just open the enN device, and set the DLT.
+ */
+ }
+ }
+#endif /* __APPLE__ */
- if (errno != ENOBUFS) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
- device, pcap_strerror(errno));
+ /*
+ * Set the buffer size.
+ */
+ if (p->opt.buffer_size != 0) {
+ /*
+ * A buffer size was explicitly specified; use it.
+ */
+ if (ioctl(fd, BIOCSBLEN, (caddr_t)&p->opt.buffer_size) < 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "BIOCSBLEN: %s: %s", p->opt.source,
+ pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
- }
- if (v == 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "BIOCSBLEN: %s: No buffer size worked", device);
- goto bad;
+ /*
+ * Now bind to the device.
+ */
+ (void)strncpy(ifr.ifr_name, p->opt.source,
+ sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ err = check_setif_failure(p, errno);
+ goto bad;
+ }
+ } else {
+ /*
+ * No buffer size was explicitly specified.
+ *
+ * Try finding a good size for the buffer; 32768 may
+ * be too big, so keep cutting it in half until we
+ * find a size that works, or run out of sizes to try.
+ * If the default is larger, don't make it smaller.
+ */
+ if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 32768)
+ v = 32768;
+ for ( ; v != 0; v >>= 1) {
+ /*
+ * Ignore the return value - this is because the
+ * call fails on BPF systems that don't have
+ * kernel malloc. And if the call fails, it's
+ * no big deal, we just continue to use the
+ * standard buffer size.
+ */
+ (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
+
+ (void)strncpy(ifr.ifr_name, p->opt.source,
+ sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
+ break; /* that size worked; we're done */
+
+ if (errno != ENOBUFS) {
+ err = check_setif_failure(p, errno);
+ goto bad;
+ }
+ }
+
+ if (v == 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "BIOCSBLEN: %s: No buffer size worked",
+ p->opt.source);
+ err = PCAP_ERROR;
+ goto bad;
+ }
}
/* Get the data link layer type. */
if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
+
#ifdef _AIX
/*
* AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT.
@@ -706,8 +1225,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
/*
* We don't know what to map this to yet.
*/
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
v);
+ err = PCAP_ERROR;
goto bad;
}
#endif
@@ -732,13 +1252,6 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
break;
}
#endif
-#ifdef PCAP_FDDIPAD
- if (v == DLT_FDDI)
- p->fddipad = PCAP_FDDIPAD;
- else
- p->fddipad = 0;
-#endif
- p->linktype = v;
#ifdef BIOCGDLTLIST
/*
@@ -746,69 +1259,144 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
* this interface supports. If this fails with EINVAL, it's
* not fatal; we just don't get to use the feature later.
*/
- memset(&bdl, 0, sizeof(bdl));
- if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) == 0) {
- u_int i;
- int is_ethernet;
+ if (get_dlt_list(fd, v, &bdl, p->errbuf) == -1) {
+ err = PCAP_ERROR;
+ goto bad;
+ }
+ p->dlt_count = bdl.bfl_len;
+ p->dlt_list = bdl.bfl_list;
- bdl.bfl_list = (u_int *) malloc(sizeof(u_int) * (bdl.bfl_len + 1));
- if (bdl.bfl_list == NULL) {
- (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
- pcap_strerror(errno));
- goto bad;
+#ifdef __APPLE__
+ /*
+ * Monitor mode fun, continued.
+ *
+ * For 10.5 and, we're assuming, later releases, as noted above,
+ * 802.1 adapters that support monitor mode offer both DLT_EN10MB,
+ * DLT_IEEE802_11, and possibly some 802.11-plus-radio-information
+ * DLT_ value. Choosing one of the 802.11 DLT_ values will turn
+ * monitor mode on.
+ *
+ * Therefore, if the user asked for monitor mode, we filter out
+ * the DLT_EN10MB value, as you can't get that in monitor mode,
+ * and, if the user didn't ask for monitor mode, we filter out
+ * the 802.11 DLT_ values, because selecting those will turn
+ * monitor mode on. Then, for monitor mode, if an 802.11-plus-
+ * radio DLT_ value is offered, we try to select that, otherwise
+ * we try to select DLT_IEEE802_11.
+ */
+ if (have_osinfo) {
+ if (isdigit((unsigned)osinfo.release[0]) &&
+ (osinfo.release[0] == '9' ||
+ isdigit((unsigned)osinfo.release[1]))) {
+ /*
+ * 10.5 (Darwin 9.x), or later.
+ */
+ new_dlt = find_802_11(&bdl);
+ if (new_dlt != -1) {
+ /*
+ * We have at least one 802.11 DLT_ value,
+ * so this is an 802.11 interface.
+ * new_dlt is the best of the 802.11
+ * DLT_ values in the list.
+ */
+ if (p->opt.rfmon) {
+ /*
+ * Our caller wants monitor mode.
+ * Purge DLT_EN10MB from the list
+ * of link-layer types, as selecting
+ * it will keep monitor mode off.
+ */
+ remove_en(p);
+
+ /*
+ * If the new mode we want isn't
+ * the default mode, attempt to
+ * select the new mode.
+ */
+ if (new_dlt != v) {
+ if (ioctl(p->fd, BIOCSDLT,
+ &new_dlt) != -1) {
+ /*
+ * We succeeded;
+ * make this the
+ * new DLT_ value.
+ */
+ v = new_dlt;
+ }
+ }
+ } else {
+ /*
+ * Our caller doesn't want
+ * monitor mode. Unless this
+ * is being done by pcap_open_live(),
+ * purge the 802.11 link-layer types
+ * from the list, as selecting
+ * one of them will turn monitor
+ * mode on.
+ */
+ if (!p->oldstyle)
+ remove_802_11(p);
+ }
+ } else {
+ if (p->opt.rfmon) {
+ /*
+ * The caller requested monitor
+ * mode, but we have no 802.11
+ * link-layer types, so they
+ * can't have it.
+ */
+ err = PCAP_ERROR_RFMON_NOTSUP;
+ goto bad;
+ }
+ }
}
-
- if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) < 0) {
- (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "BIOCGDLTLIST: %s", pcap_strerror(errno));
- free(bdl.bfl_list);
+ }
+#elif defined(HAVE_BSD_IEEE80211)
+ /*
+ * *BSD with the new 802.11 ioctls.
+ * Do we want monitor mode?
+ */
+ if (p->opt.rfmon) {
+ /*
+ * Try to put the interface into monitor mode.
+ */
+ err = monitor_mode(p, 1);
+ if (err != 0) {
+ /*
+ * We failed.
+ */
goto bad;
}
/*
- * OK, for real Ethernet devices, add DLT_DOCSIS to the
- * list, so that an application can let you choose it,
- * in case you're capturing DOCSIS traffic that a Cisco
- * Cable Modem Termination System is putting out onto
- * an Ethernet (it doesn't put an Ethernet header onto
- * the wire, it puts raw DOCSIS frames out on the wire
- * inside the low-level Ethernet framing).
- *
- * A "real Ethernet device" is defined here as a device
- * that has a link-layer type of DLT_EN10MB and that has
- * no alternate link-layer types; that's done to exclude
- * 802.11 interfaces (which might or might not be the
- * right thing to do, but I suspect it is - Ethernet <->
- * 802.11 bridges would probably badly mishandle frames
- * that don't have Ethernet headers).
+ * We're in monitor mode.
+ * Try to find the best 802.11 DLT_ value and, if we
+ * succeed, try to switch to that mode if we're not
+ * already in that mode.
*/
- if (p->linktype == DLT_EN10MB) {
- is_ethernet = 1;
- for (i = 0; i < bdl.bfl_len; i++) {
- if (bdl.bfl_list[i] != DLT_EN10MB) {
- is_ethernet = 0;
- break;
+ new_dlt = find_802_11(&bdl);
+ if (new_dlt != -1) {
+ /*
+ * We have at least one 802.11 DLT_ value.
+ * new_dlt is the best of the 802.11
+ * DLT_ values in the list.
+ *
+ * If the new mode we want isn't the default mode,
+ * attempt to select the new mode.
+ */
+ if (new_dlt != v) {
+ if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) {
+ /*
+ * We succeeded; make this the
+ * new DLT_ value.
+ */
+ v = new_dlt;
}
}
- if (is_ethernet) {
- /*
- * We reserved one more slot at the end of
- * the list.
- */
- bdl.bfl_list[bdl.bfl_len] = DLT_DOCSIS;
- bdl.bfl_len++;
- }
- }
- p->dlt_count = bdl.bfl_len;
- p->dlt_list = bdl.bfl_list;
- } else {
- if (errno != EINVAL) {
- (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "BIOCGDLTLIST: %s", pcap_strerror(errno));
- goto bad;
}
}
-#endif
+#endif /* various platforms */
+#endif /* BIOCGDLTLIST */
/*
* If this is an Ethernet device, and we don't have a DLT_ list,
@@ -818,7 +1406,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
* some other way of determining whether it's an Ethernet or 802.11
* device.)
*/
- if (p->linktype == DLT_EN10MB && p->dlt_count == 0) {
+ if (v == DLT_EN10MB && p->dlt_count == 0) {
p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
/*
* If that fails, just leave the list empty.
@@ -829,6 +1417,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
p->dlt_count = 2;
}
}
+#ifdef PCAP_FDDIPAD
+ if (v == DLT_FDDI)
+ p->fddipad = PCAP_FDDIPAD;
+ else
+ p->fddipad = 0;
+#endif
+ p->linktype = v;
#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
/*
@@ -841,24 +1436,26 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
* BSDs - check CVS log for "bpf.c"?
*/
if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) {
- (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"BIOCSHDRCMPLT: %s", pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
#endif
/* set timeout */
- if (to_ms != 0) {
+ if (p->md.timeout != 0) {
/*
* XXX - is this seconds/nanoseconds in AIX?
* (Treating it as such doesn't fix the timeout
* problem described below.)
*/
struct timeval to;
- to.tv_sec = to_ms / 1000;
- to.tv_usec = (to_ms * 1000) % 1000000;
+ to.tv_sec = p->md.timeout / 1000;
+ to.tv_usec = (p->md.timeout * 1000) % 1000000;
if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
}
@@ -913,31 +1510,34 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
*/
v = 1;
if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s",
pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
#endif /* BIOCIMMEDIATE */
#endif /* _AIX */
- if (promisc) {
+ if (p->opt.promisc) {
/* set promiscuous mode, okay if it fails */
if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s",
pcap_strerror(errno));
}
}
if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
p->bufsize = v;
p->buffer = (u_char *)malloc(p->bufsize);
if (p->buffer == NULL) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s",
pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
#ifdef _AIX
@@ -958,13 +1558,14 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
total_insn.code = (u_short)(BPF_RET | BPF_K);
total_insn.jt = 0;
total_insn.jf = 0;
- total_insn.k = snaplen;
+ total_insn.k = p->snapshot;
total_prog.bf_len = 1;
total_prog.bf_insns = &total_insn;
if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
pcap_strerror(errno));
+ err = PCAP_ERROR;
goto bad;
}
@@ -1005,7 +1606,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
* XXX - what about AIX?
*/
p->selectable_fd = p->fd; /* assume select() works until we know otherwise */
- if (uname(&osinfo) == 0) {
+ if (have_osinfo) {
/*
* We can check what OS this is.
*/
@@ -1024,15 +1625,16 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
p->getnonblock_op = pcap_getnonblock_fd;
p->setnonblock_op = pcap_setnonblock_fd;
p->stats_op = pcap_stats_bpf;
- p->close_op = pcap_close_common;
+ p->close_op = pcap_close_bpf;
- return (p);
+ return (0);
bad:
(void)close(fd);
- if (p->dlt_list != NULL)
- free(p->dlt_list);
- free(p);
- return (NULL);
+ if (p->buffer != NULL) {
+ free(p->buffer);
+ p->buffer = NULL;
+ }
+ return (err);
}
int
@@ -1046,6 +1648,303 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
return (0);
}
+#ifdef HAVE_BSD_IEEE80211
+static int
+monitor_mode(pcap_t *p, int set)
+{
+ int sock;
+ struct ifmediareq req;
+ int *media_list;
+ int i;
+ int can_do;
+ struct ifreq ifr;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == -1) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't open socket: %s",
+ pcap_strerror(errno));
+ return (PCAP_ERROR);
+ }
+
+ memset(&req, 0, sizeof req);
+ strncpy(req.ifm_name, p->opt.source, sizeof req.ifm_name);
+
+ /*
+ * Find out how many media types we have.
+ */
+ if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
+ /*
+ * Can't get the media types.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s",
+ pcap_strerror(errno));
+ close(sock);
+ return (PCAP_ERROR);
+ }
+ if (req.ifm_count == 0) {
+ /*
+ * No media types.
+ */
+ close(sock);
+ return (PCAP_ERROR_RFMON_NOTSUP);
+ }
+
+ /*
+ * Allocate a buffer to hold all the media types, and
+ * get the media types.
+ */
+ media_list = malloc(req.ifm_count * sizeof(int));
+ if (media_list == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+ pcap_strerror(errno));
+ close(sock);
+ return (PCAP_ERROR);
+ }
+ req.ifm_ulist = media_list;
+ if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s",
+ pcap_strerror(errno));
+ free(media_list);
+ close(sock);
+ return (PCAP_ERROR);
+ }
+
+ /*
+ * Look for an 802.11 "automatic" media type.
+ * We assume that all 802.11 adapters have that media type,
+ * and that it will carry the monitor mode supported flag.
+ */
+ can_do = 0;
+ for (i = 0; i < req.ifm_count; i++) {
+ if (IFM_TYPE(media_list[i]) == IFM_IEEE80211
+ && IFM_SUBTYPE(media_list[i]) == IFM_AUTO) {
+ /* OK, does it do monitor mode? */
+ if (media_list[i] & IFM_IEEE80211_MONITOR) {
+ can_do = 1;
+ break;
+ }
+ }
+ }
+ free(media_list);
+ if (!can_do) {
+ /*
+ * This adapter doesn't support monitor mode.
+ */
+ close(sock);
+ return (PCAP_ERROR_RFMON_NOTSUP);
+ }
+
+ if (set) {
+ /*
+ * Don't just check whether we can enable monitor mode,
+ * do so, if it's not already enabled.
+ */
+ if ((req.ifm_current & IFM_IEEE80211_MONITOR) == 0) {
+ /*
+ * Monitor mode isn't currently on, so turn it on,
+ * and remember that we should turn it off when the
+ * pcap_t is closed.
+ */
+
+ /*
+ * If we haven't already done so, arrange to have
+ * "pcap_close_all()" called when we exit.
+ */
+ if (!pcap_do_addexit(p)) {
+ /*
+ * "atexit()" failed; don't put the interface
+ * in monitor mode, just give up.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "atexit failed");
+ close(sock);
+ return (PCAP_ERROR);
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ (void)strncpy(ifr.ifr_name, p->opt.source,
+ sizeof(ifr.ifr_name));
+ ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR;
+ if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "SIOCSIFMEDIA: %s", pcap_strerror(errno));
+ close(sock);
+ return (PCAP_ERROR);
+ }
+
+ p->md.must_clear |= MUST_CLEAR_RFMON;
+
+ /*
+ * Add this to the list of pcaps to close when we exit.
+ */
+ pcap_add_to_pcaps_to_close(p);
+ }
+ }
+ return (0);
+}
+#endif /* HAVE_BSD_IEEE80211 */
+
+#if defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211))
+/*
+ * Check whether we have any 802.11 link-layer types; return the best
+ * of the 802.11 link-layer types if we find one, and return -1
+ * otherwise.
+ *
+ * DLT_IEEE802_11_RADIO, with the radiotap header, is considered the
+ * best 802.11 link-layer type; any of the other 802.11-plus-radio
+ * headers are second-best; 802.11 with no radio information is
+ * the least good.
+ */
+static int
+find_802_11(struct bpf_dltlist *bdlp)
+{
+ int new_dlt;
+ int i;
+
+ /*
+ * Scan the list of DLT_ values, looking for 802.11 values,
+ * and, if we find any, choose the best of them.
+ */
+ new_dlt = -1;
+ for (i = 0; i < bdlp->bfl_len; i++) {
+ switch (bdlp->bfl_list[i]) {
+
+ case DLT_IEEE802_11:
+ /*
+ * 802.11, but no radio.
+ *
+ * Offer this, and select it as the new mode
+ * unless we've already found an 802.11
+ * header with radio information.
+ */
+ if (new_dlt == -1)
+ new_dlt = bdlp->bfl_list[i];
+ break;
+
+ case DLT_PRISM_HEADER:
+ case DLT_AIRONET_HEADER:
+ case DLT_IEEE802_11_RADIO_AVS:
+ /*
+ * 802.11 with radio, but not radiotap.
+ *
+ * Offer this, and select it as the new mode
+ * unless we've already found the radiotap DLT_.
+ */
+ if (new_dlt != DLT_IEEE802_11_RADIO)
+ new_dlt = bdlp->bfl_list[i];
+ break;
+
+ case DLT_IEEE802_11_RADIO:
+ /*
+ * 802.11 with radiotap.
+ *
+ * Offer this, and select it as the new mode.
+ */
+ new_dlt = bdlp->bfl_list[i];
+ break;
+
+ default:
+ /*
+ * Not 802.11.
+ */
+ break;
+ }
+ }
+
+ return (new_dlt);
+}
+#endif /* defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) */
+
+#if defined(__APPLE__) && defined(BIOCGDLTLIST)
+/*
+ * Remove DLT_EN10MB from the list of DLT_ values.
+ */
+static void
+remove_en(pcap_t *p)
+{
+ int i, j;
+
+ /*
+ * Scan the list of DLT_ values and discard DLT_EN10MB.
+ */
+ j = 0;
+ for (i = 0; i < p->dlt_count; i++) {
+ switch (p->dlt_list[i]) {
+
+ case DLT_EN10MB:
+ /*
+ * Don't offer this one.
+ */
+ continue;
+
+ default:
+ /*
+ * Just copy this mode over.
+ */
+ break;
+ }
+
+ /*
+ * Copy this DLT_ value to its new position.
+ */
+ p->dlt_list[j] = p->dlt_list[i];
+ j++;
+ }
+
+ /*
+ * Set the DLT_ count to the number of entries we copied.
+ */
+ p->dlt_count = j;
+}
+
+/*
+ * Remove DLT_EN10MB from the list of DLT_ values, and look for the
+ * best 802.11 link-layer type in that list and return it.
+ * Radiotap is better than anything else; 802.11 with any other radio
+ * header is better than 802.11 with no radio header.
+ */
+static void
+remove_802_11(pcap_t *p)
+{
+ int i, j;
+
+ /*
+ * Scan the list of DLT_ values and discard 802.11 values.
+ */
+ j = 0;
+ for (i = 0; i < p->dlt_count; i++) {
+ switch (p->dlt_list[i]) {
+
+ case DLT_IEEE802_11:
+ case DLT_PRISM_HEADER:
+ case DLT_AIRONET_HEADER:
+ case DLT_IEEE802_11_RADIO:
+ case DLT_IEEE802_11_RADIO_AVS:
+ /*
+ * 802.11. Don't offer this one.
+ */
+ continue;
+
+ default:
+ /*
+ * Just copy this mode over.
+ */
+ break;
+ }
+
+ /*
+ * Copy this DLT_ value to its new position.
+ */
+ p->dlt_list[j] = p->dlt_list[i];
+ j++;
+ }
+
+ /*
+ * Set the DLT_ count to the number of entries we copied.
+ */
+ p->dlt_count = j;
+}
+#endif /* defined(__APPLE__) && defined(BIOCGDLTLIST) */
+
static int
pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp)
{