diff options
Diffstat (limited to 'freebsd/contrib/libpcap/pcap-bpf.c')
-rw-r--r-- | freebsd/contrib/libpcap/pcap-bpf.c | 626 |
1 files changed, 395 insertions, 231 deletions
diff --git a/freebsd/contrib/libpcap/pcap-bpf.c b/freebsd/contrib/libpcap/pcap-bpf.c index 60111cf5..dc2942af 100644 --- a/freebsd/contrib/libpcap/pcap-bpf.c +++ b/freebsd/contrib/libpcap/pcap-bpf.c @@ -19,25 +19,20 @@ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * $FreeBSD$ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include <config.h> #endif #include <sys/param.h> /* optionally get BSD define */ -#ifdef HAVE_ZEROCOPY_BPF -#include <sys/mman.h> -#endif #include <sys/socket.h> #include <time.h> /* * <net/bpf.h> defines ioctls, but doesn't include <sys/ioccom.h>. * * We include <sys/ioctl.h> as it might be necessary to declare ioctl(); - * at least on *BSD and Mac OS X, it also defines various SIOC ioctls - + * at least on *BSD and macOS, it also defines various SIOC ioctls - * we could include <sys/sockio.h>, but if we're already including * <sys/ioctl.h>, which includes <sys/sockio.h> on those platforms, * there's not much point in doing so. @@ -61,10 +56,6 @@ static const char usbus_prefix[] = "usbus"; #include <dirent.h> #endif -#ifdef HAVE_ZEROCOPY_BPF -#include <machine/atomic.h> -#endif - #include <net/if.h> #ifdef _AIX @@ -86,6 +77,16 @@ static const char usbus_prefix[] = "usbus"; #include <net/bpf.h> #define _AIX +/* + * If both BIOCROTZBUF and BPF_BUFMODE_ZBUF are defined, we have + * zero-copy BPF. + */ +#if defined(BIOCROTZBUF) && defined(BPF_BUFMODE_ZBUF) + #define HAVE_ZEROCOPY_BPF + #include <sys/mman.h> + #include <machine/atomic.h> +#endif + #include <net/if_types.h> /* for IFT_ values */ #include <sys/sysconfig.h> #include <sys/device.h> @@ -125,7 +126,7 @@ static int bpf_load(char *errbuf); #include <string.h> #include <unistd.h> -#ifdef HAVE_NET_IF_MEDIA_H +#ifdef SIOCGIFMEDIA # include <net/if_media.h> #endif @@ -228,8 +229,9 @@ static void remove_802_11(pcap_t *); #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. + * In some versions of macOS, we might not even get any of the + * 802.11-plus-radio-header DLT_'s defined, even though some + * of them are used by various Airport drivers in those versions. */ #ifndef DLT_PRISM_HEADER #define DLT_PRISM_HEADER 119 @@ -256,7 +258,7 @@ static int pcap_set_datalink_bpf(pcap_t *p, int dlt); * blocking mode. */ static int -pcap_getnonblock_bpf(pcap_t *p, char *errbuf) +pcap_getnonblock_bpf(pcap_t *p) { #ifdef HAVE_ZEROCOPY_BPF struct pcap_bpf *pb = p->priv; @@ -264,11 +266,11 @@ pcap_getnonblock_bpf(pcap_t *p, char *errbuf) if (pb->zerocopy) return (pb->nonblock); #endif - return (pcap_getnonblock_fd(p, errbuf)); + return (pcap_getnonblock_fd(p)); } static int -pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf) +pcap_setnonblock_bpf(pcap_t *p, int nonblock) { #ifdef HAVE_ZEROCOPY_BPF struct pcap_bpf *pb = p->priv; @@ -278,7 +280,7 @@ pcap_setnonblock_bpf(pcap_t *p, int nonblock, char *errbuf) return (0); } #endif - return (pcap_setnonblock_fd(p, nonblock, errbuf)); + return (pcap_setnonblock_fd(p, nonblock)); } #ifdef HAVE_ZEROCOPY_BPF @@ -369,8 +371,8 @@ pcap_next_zbuf(pcap_t *p, int *cc) if (data) return (data); if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { - (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCROTZBUF: %s", strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, "BIOCROTZBUF"); return (PCAP_ERROR); } return (pcap_next_zbuf_shm(p, cc)); @@ -397,8 +399,8 @@ pcap_next_zbuf(pcap_t *p, int *cc) } return (0); } else if (r < 0) { - (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "select: %s", strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "select"); return (PCAP_ERROR); } } @@ -416,8 +418,8 @@ pcap_next_zbuf(pcap_t *p, int *cc) * data. */ if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { - (void) pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCROTZBUF: %s", strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCROTZBUF"); return (PCAP_ERROR); } return (pcap_next_zbuf_shm(p, cc)); @@ -459,8 +461,8 @@ pcap_create_interface(const char *device _U_, char *ebuf) p->tstamp_precision_count = 2; p->tstamp_precision_list = malloc(2 * sizeof(u_int)); if (p->tstamp_precision_list == NULL) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, + "malloc"); free(p); return (NULL); } @@ -477,13 +479,11 @@ pcap_create_interface(const char *device _U_, char *ebuf) static int bpf_open(char *errbuf) { - int fd; -#ifdef HAVE_CLONING_BPF - static const char device[] = "/dev/bpf"; -#else + int fd = -1; + static const char cloning_device[] = "/dev/bpf"; int n = 0; char device[sizeof "/dev/bpf0000000000"]; -#endif + static int no_cloning_bpf = 0; #ifdef _AIX /* @@ -495,40 +495,55 @@ bpf_open(char *errbuf) return (PCAP_ERROR); #endif -#ifdef HAVE_CLONING_BPF - if ((fd = open(device, O_RDWR)) == -1 && - (errno != EACCES || (fd = open(device, O_RDONLY)) == -1)) { - if (errno == EACCES) - fd = PCAP_ERROR_PERM_DENIED; - else - fd = PCAP_ERROR; - pcap_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. + * First, unless we've already tried opening /dev/bpf and + * gotten ENOENT, try opening /dev/bpf. + * If it fails with ENOENT, remember that, so we don't try + * again, and try /dev/bpfN. */ - do { - (void)pcap_snprintf(device, sizeof(device), "/dev/bpf%d", n++); + if (!no_cloning_bpf && + (fd = open(cloning_device, O_RDWR)) == -1 && + ((errno != EACCES && errno != ENOENT) || + (fd = open(cloning_device, O_RDONLY)) == -1)) { + if (errno != ENOENT) { + if (errno == EACCES) + fd = PCAP_ERROR_PERM_DENIED; + else + fd = PCAP_ERROR; + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "(cannot open device) %s", cloning_device); + return (fd); + } + no_cloning_bpf = 1; + } + + if (no_cloning_bpf) { /* - * 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. + * We don't have /dev/bpf. + * Go through all the /dev/bpfN minors and find one + * that isn't in use. */ - fd = open(device, O_RDWR); - if (fd == -1 && errno == EACCES) - fd = open(device, O_RDONLY); - } while (fd < 0 && errno == EBUSY); + do { + (void)pcap_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 @@ -565,9 +580,8 @@ bpf_open(char *errbuf) * if any. */ fd = PCAP_ERROR_PERM_DENIED; - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "(cannot open BPF device) %s: %s", device, - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "(cannot open BPF device) %s", device); break; default: @@ -575,13 +589,11 @@ bpf_open(char *errbuf) * Some other problem. */ fd = PCAP_ERROR; - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "(cannot open BPF device) %s: %s", device, - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "(cannot open BPF device) %s", device); break; } } -#endif return (fd); } @@ -633,8 +645,8 @@ bpf_open_and_bind(const char *name, char *errbuf) return (PCAP_ERROR_IFACE_NOT_UP); default: - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "BIOCSETIF: %s: %s", name, pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETIF: %s", name); close(fd); return (PCAP_ERROR); } @@ -657,14 +669,14 @@ get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1)); if (bdlp->bfl_list == NULL) { - (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); return (PCAP_ERROR); } if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) { - (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, - "BIOCGDLTLIST: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGDLTLIST"); free(bdlp->bfl_list); return (PCAP_ERROR); } @@ -718,8 +730,8 @@ get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf) * this device"; don't treat it as an error. */ if (errno != EINVAL) { - (void)pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, - "BIOCGDLTLIST: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGDLTLIST"); return (PCAP_ERROR); } } @@ -739,7 +751,7 @@ pcap_can_set_rfmon_bpf(pcap_t *p) #endif /* - * The joys of monitor mode on OS X. + * The joys of monitor mode on Mac OS X/OS X/macOS. * * Prior to 10.4, it's not supported at all. * @@ -785,8 +797,8 @@ pcap_can_set_rfmon_bpf(pcap_t *p) } fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { - (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "socket: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "socket"); return (PCAP_ERROR); } strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name)); @@ -840,9 +852,8 @@ pcap_can_set_rfmon_bpf(pcap_t *p) return (PCAP_ERROR_IFACE_NOT_UP); default: - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCSETIF: %s: %s", - p->opt.device, pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETIF: %s", p->opt.device); close(fd); return (PCAP_ERROR); } @@ -904,8 +915,8 @@ pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps) * by libpcap, and thus not yet seen by the application. */ if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGSTATS"); return (PCAP_ERROR); } @@ -1032,8 +1043,8 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) /* fall through */ #endif } - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "read"); return (PCAP_ERROR); } bp = (u_char *)p->buffer; @@ -1186,13 +1197,13 @@ pcap_inject_bpf(pcap_t *p, const void *buf, size_t size) #ifdef __APPLE__ if (ret == -1 && errno == EAFNOSUPPORT) { /* - * In Mac OS X, there's a bug wherein setting the - * BIOCSHDRCMPLT flag causes writes to fail; see, - * for example: + * In some versions of macOS, there's a bug wherein setting + * the BIOCSHDRCMPLT flag causes writes to fail; see, for + * example: * * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/BIOCSHDRCMPLT-10.3.3.patch * - * So, if, on OS X, we get EAFNOSUPPORT from the write, we + * So, if, on macOS, we get EAFNOSUPPORT from the write, we * assume it's due to that bug, and turn off that flag * and try again. If we succeed, it either means that * somebody applied the fix from that URL, or other patches @@ -1201,14 +1212,13 @@ pcap_inject_bpf(pcap_t *p, const void *buf, size_t size) * http://cerberus.sourcefire.com/~jeff/archives/patches/macosx/ * * and are running a Darwin kernel with those fixes, or - * that Apple fixed the problem in some OS X release. + * that Apple fixed the problem in some macOS release. */ u_int spoof_eth_src = 0; if (ioctl(p->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { - (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "send: can't turn off BIOCSHDRCMPLT: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send: can't turn off BIOCSHDRCMPLT"); return (PCAP_ERROR); } @@ -1219,8 +1229,8 @@ pcap_inject_bpf(pcap_t *p, const void *buf, size_t size) } #endif /* __APPLE__ */ if (ret == -1) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "send"); return (PCAP_ERROR); } return (ret); @@ -1308,8 +1318,8 @@ bpf_load(char *errbuf) major = genmajor(BPF_NAME); if (major == -1) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "bpf_load: genmajor failed: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: genmajor failed"); (void)bpf_odmcleanup(NULL); return (PCAP_ERROR); } @@ -1318,9 +1328,8 @@ bpf_load(char *errbuf) if (!minors) { minors = genminor("bpf", major, 0, BPF_MINORS, 1, 1); if (!minors) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "bpf_load: genminor failed: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: genminor failed"); (void)bpf_odmcleanup(NULL); return (PCAP_ERROR); } @@ -1331,20 +1340,19 @@ bpf_load(char *errbuf) rc = stat(BPF_NODE "0", &sbuf); if (rc == -1 && errno != ENOENT) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "bpf_load: can't stat %s: %s", - BPF_NODE "0", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: can't stat %s", BPF_NODE "0"); return (PCAP_ERROR); } if (rc == -1 || getmajor(sbuf.st_rdev) != major) { for (i = 0; i < BPF_MINORS; i++) { - sprintf(buf, "%s%d", BPF_NODE, i); + pcap_snprintf(buf, sizeof(buf), "%s%d", BPF_NODE, i); unlink(buf); if (mknod(buf, S_IRUSR | S_IFCHR, domakedev(major, i)) == -1) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "bpf_load: can't mknod %s: %s", - buf, pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, + PCAP_ERRBUF_SIZE, errno, + "bpf_load: can't mknod %s", buf); return (PCAP_ERROR); } } @@ -1353,14 +1361,13 @@ bpf_load(char *errbuf) /* Check if the driver is loaded */ memset(&cfg_ld, 0x0, sizeof(cfg_ld)); cfg_ld.path = buf; - sprintf(cfg_ld.path, "%s/%s", DRIVER_PATH, BPF_NAME); + pcap_snprintf(cfg_ld.path, sizeof(cfg_ld.path), "%s/%s", DRIVER_PATH, BPF_NAME); if ((sysconfig(SYS_QUERYLOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) || (cfg_ld.kmid == 0)) { /* Driver isn't loaded, load it now */ if (sysconfig(SYS_SINGLELOAD, (void *)&cfg_ld, sizeof(cfg_ld)) == -1) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "bpf_load: could not load driver: %s", - strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: could not load driver"); return (PCAP_ERROR); } } @@ -1373,9 +1380,8 @@ bpf_load(char *errbuf) for (i = 0; i < BPF_MINORS; i++) { cfg_bpf.devno = domakedev(major, i); if (sysconfig(SYS_CFGKMOD, (void *)&cfg_km, sizeof(cfg_km)) == -1) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "bpf_load: could not configure driver: %s", - strerror(errno)); + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "bpf_load: could not configure driver"); return (PCAP_ERROR); } } @@ -1495,7 +1501,6 @@ pcap_cleanup_bpf(pcap_t *p) if (pb->zbuf2 != MAP_FAILED && pb->zbuf2 != NULL) (void) munmap(pb->zbuf2, pb->zbufsize); p->buffer = NULL; - p->buffer = NULL; } #endif if (pb->device != NULL) { @@ -1540,9 +1545,10 @@ check_setif_failure(pcap_t *p, int error) * exist. */ err = PCAP_ERROR_NO_SUCH_DEVICE; - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "SIOCGIFFLAGS on %s failed: %s", - ifr.ifr_name, pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "SIOCGIFFLAGS on %s failed", + ifr.ifr_name); } else { /* * The underlying "enN" device @@ -1564,9 +1570,9 @@ check_setif_failure(pcap_t *p, int error) * just report "no such device". */ err = PCAP_ERROR_NO_SUCH_DEVICE; - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "socket() failed: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + errno, PCAP_ERRBUF_SIZE, + "socket() failed"); } return (err); } @@ -1574,8 +1580,8 @@ check_setif_failure(pcap_t *p, int error) /* * No such device. */ - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF failed: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETIF failed"); return (PCAP_ERROR_NO_SUCH_DEVICE); } else if (errno == ENETDOWN) { /* @@ -1591,8 +1597,8 @@ check_setif_failure(pcap_t *p, int error) * Some other error; fill in the error string, and * return PCAP_ERROR. */ - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", - p->opt.device, pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETIF: %s", p->opt.device); return (PCAP_ERROR); } } @@ -1649,15 +1655,6 @@ pcap_activate_bpf(pcap_t *p) struct bpf_insn total_insn; struct bpf_program total_prog; struct utsname osinfo; - -#ifdef HAVE_DAG_API - if (strstr(device, "dag")) { - return dag_open_live(device, snaplen, promisc, to_ms, ebuf); - } -#endif /* HAVE_DAG_API */ - -#ifdef BIOCGDLTLIST - memset(&bdl, 0, sizeof(bdl)); int have_osinfo = 0; #ifdef HAVE_ZEROCOPY_BPF struct bpf_zbuf bz; @@ -1673,8 +1670,8 @@ pcap_activate_bpf(pcap_t *p) p->fd = fd; if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCVERSION"); status = PCAP_ERROR; goto bad; } @@ -1686,13 +1683,24 @@ pcap_activate_bpf(pcap_t *p) goto bad; } + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + #if defined(LIFNAMSIZ) && defined(ZONENAME_MAX) && defined(lifr_zoneid) /* * Retrieve the zoneid of the zone we are currently executing in. */ if ((ifr.lifr_zoneid = getzoneid()) == -1) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "getzoneid(): %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "getzoneid()"); status = PCAP_ERROR; goto bad; } @@ -1718,16 +1726,15 @@ pcap_activate_bpf(pcap_t *p) (void) strlcpy(path_zname, p->opt.device, znamelen + 1); ifr.lifr_zoneid = getzoneidbyname(path_zname); if (ifr.lifr_zoneid == -1) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "getzoneidbyname(%s): %s", path_zname, - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "getzoneidbyname(%s)", path_zname); status = PCAP_ERROR; goto bad; } lnamep = strdup(zonesep + 1); if (lnamep == NULL) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "strdup"); status = PCAP_ERROR; goto bad; } @@ -1738,20 +1745,13 @@ pcap_activate_bpf(pcap_t *p) pb->device = strdup(p->opt.device); if (pb->device == NULL) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "strdup"); status = PCAP_ERROR; goto bad; } /* - * 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 (uname(&osinfo) == 0) @@ -1800,10 +1800,10 @@ pcap_activate_bpf(pcap_t *p) * exist. */ status = PCAP_ERROR_NO_SUCH_DEVICE; - pcap_snprintf(p->errbuf, + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, - "SIOCGIFFLAGS failed: %s", - pcap_strerror(errno)); + errno, + "SIOCGIFFLAGS failed"); } else status = PCAP_ERROR_RFMON_NOTSUP; close(sockfd); @@ -1814,18 +1814,17 @@ pcap_activate_bpf(pcap_t *p) * report "no such device". */ status = PCAP_ERROR_NO_SUCH_DEVICE; - pcap_snprintf(p->errbuf, - PCAP_ERRBUF_SIZE, - "socket() failed: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "socket() failed"); } goto bad; } wltdev = malloc(strlen(p->opt.device) + 2); if (wltdev == NULL) { - (void)pcap_snprintf(p->errbuf, - PCAP_ERRBUF_SIZE, "malloc: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "malloc"); status = PCAP_ERROR; goto bad; } @@ -1865,9 +1864,9 @@ pcap_activate_bpf(pcap_t *p) */ s = socket(AF_LOCAL, SOCK_DGRAM, 0); if (s < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Can't open socket: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't open socket"); status = PCAP_ERROR; goto bad; } @@ -1898,9 +1897,10 @@ pcap_activate_bpf(pcap_t *p) "Invalid USB bus interface %s", p->opt.device); } else { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Can't create interface for %s: %s", - p->opt.device, pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "Can't create interface for %s", + p->opt.device); } close(s); status = PCAP_ERROR; @@ -1943,8 +1943,8 @@ pcap_activate_bpf(pcap_t *p) * size. */ if (ioctl(fd, BIOCGETZMAX, (caddr_t)&zbufmax) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGETZMAX: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGETZMAX"); status = PCAP_ERROR; goto bad; } @@ -1970,8 +1970,8 @@ pcap_activate_bpf(pcap_t *p) pb->zbuf2 = mmap(NULL, pb->zbufsize, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0); if (pb->zbuf1 == MAP_FAILED || pb->zbuf2 == MAP_FAILED) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "mmap: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "mmap"); status = PCAP_ERROR; goto bad; } @@ -1980,15 +1980,15 @@ pcap_activate_bpf(pcap_t *p) bz.bz_bufb = pb->zbuf2; bz.bz_buflen = pb->zbufsize; if (ioctl(fd, BIOCSETZBUF, (caddr_t)&bz) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETZBUF: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETZBUF"); status = PCAP_ERROR; goto bad; } (void)strncpy(ifrname, p->opt.device, ifnamsiz); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s", - p->opt.device, pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETIF: %s", p->opt.device); status = PCAP_ERROR; goto bad; } @@ -2006,9 +2006,9 @@ pcap_activate_bpf(pcap_t *p) */ if (ioctl(fd, BIOCSBLEN, (caddr_t)&p->opt.buffer_size) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCSBLEN: %s: %s", p->opt.device, - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, + "BIOCSBLEN: %s", p->opt.device); status = PCAP_ERROR; goto bad; } @@ -2072,12 +2072,11 @@ pcap_activate_bpf(pcap_t *p) } } } -#endif /* Get the data link layer type. */ if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGDLT"); status = PCAP_ERROR; goto bad; } @@ -2321,8 +2320,8 @@ pcap_activate_bpf(pcap_t *p) * BSDs - check CVS log for "bpf.c"? */ if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) { - (void)pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCSHDRCMPLT: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSHDRCMPLT"); status = PCAP_ERROR; goto bad; } @@ -2363,8 +2362,8 @@ pcap_activate_bpf(pcap_t *p) bpf_to.tv_sec = p->opt.timeout / 1000; bpf_to.tv_usec = (p->opt.timeout * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&bpf_to) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + errno, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT"); status = PCAP_ERROR; goto bad; } @@ -2373,8 +2372,8 @@ pcap_activate_bpf(pcap_t *p) to.tv_sec = p->opt.timeout / 1000; to.tv_usec = (p->opt.timeout * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + errno, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT"); status = PCAP_ERROR; goto bad; } @@ -2408,8 +2407,8 @@ pcap_activate_bpf(pcap_t *p) #endif /* _AIX */ v = 1; if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "BIOCIMMEDIATE: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCIMMEDIATE"); status = PCAP_ERROR; goto bad; } @@ -2430,8 +2429,8 @@ pcap_activate_bpf(pcap_t *p) if (p->opt.promisc) { /* set promiscuous mode, just warn if it fails */ if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCPROMISC"); status = PCAP_WARNING_PROMISC_NOTSUP; } } @@ -2439,16 +2438,16 @@ pcap_activate_bpf(pcap_t *p) #ifdef BIOCSTSTAMP v = BPF_T_BINTIME; if (ioctl(p->fd, BIOCSTSTAMP, &v) < 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSTSTAMP: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSTSTAMP"); status = PCAP_ERROR; goto bad; } #endif /* BIOCSTSTAMP */ if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCGBLEN"); status = PCAP_ERROR; goto bad; } @@ -2458,8 +2457,8 @@ pcap_activate_bpf(pcap_t *p) #endif p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); status = PCAP_ERROR; goto bad; } @@ -2489,8 +2488,8 @@ pcap_activate_bpf(pcap_t *p) total_prog.bf_len = 1; total_prog.bf_insns = &total_insn; if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETF"); status = PCAP_ERROR; goto bad; } @@ -2572,6 +2571,44 @@ check_bpf_bindable(const char *name) int fd; char errbuf[PCAP_ERRBUF_SIZE]; + /* + * On macOS, we don't do this check if the device name begins + * with "wlt"; at least some versions of macOS (actually, it + * was called "Mac OS X" then...) 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) { + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); + return (-1); + } + strcpy(en_name, "en"); + strcat(en_name, name + 3); + fd = bpf_open_and_bind(en_name, errbuf); + free(en_name); + } else +#endif /* __APPLE */ fd = bpf_open_and_bind(name, errbuf); if (fd < 0) { /* @@ -2606,7 +2643,18 @@ check_bpf_bindable(const char *name) #if defined(__FreeBSD__) && defined(SIOCIFCREATE2) static int -finddevs_usb(pcap_if_t **alldevsp, char *errbuf) +get_usb_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * XXX - if there's a way to determine whether there's something + * plugged into a given USB bus, use that to determine whether + * this device is "connected" or not. + */ + return (0); +} + +static int +finddevs_usb(pcap_if_list_t *devlistp, char *errbuf) { DIR *usbdir; struct dirent *usbitem; @@ -2646,7 +2694,6 @@ finddevs_usb(pcap_if_t **alldevsp, char *errbuf) while ((usbitem = readdir(usbdir)) != NULL) { char *p; size_t busnumlen; - int err; if (strcmp(usbitem->d_name, ".") == 0 || strcmp(usbitem->d_name, "..") == 0) { @@ -2662,11 +2709,18 @@ finddevs_usb(pcap_if_t **alldevsp, char *errbuf) memcpy(name, usbus_prefix, USBUS_PREFIX_LEN); memcpy(name + USBUS_PREFIX_LEN, usbitem->d_name, busnumlen); *(name + USBUS_PREFIX_LEN + busnumlen) = '\0'; - err = pcap_add_if(alldevsp, name, PCAP_IF_UP, NULL, errbuf); - if (err != 0) { + /* + * There's an entry in this directory for every USB device, + * not for every bus; if there's more than one device on + * the bus, there'll be more than one entry for that bus, + * so we need to avoid adding multiple capture devices + * for each bus. + */ + if (find_or_add_dev(devlistp, name, PCAP_IF_UP, + get_usb_if_flags, NULL, errbuf) == NULL) { free(name); closedir(usbdir); - return (err); + return (PCAP_ERROR); } } free(name); @@ -2675,17 +2729,116 @@ finddevs_usb(pcap_if_t **alldevsp, char *errbuf) } #endif +/* + * Get additional flags for a device, using SIOCGIFMEDIA. + */ +#ifdef SIOCGIFMEDIA +static int +get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) +{ + int sock; + struct ifmediareq req; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, + "Can't create socket to get media information for %s", + name); + return (-1); + } + memset(&req, 0, sizeof(req)); + strncpy(req.ifm_name, name, sizeof(req.ifm_name)); + if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { + if (errno == EOPNOTSUPP || errno == EINVAL || errno == ENOTTY || + errno == ENODEV) { + /* + * Not supported, so we can't provide any + * additional information. Assume that + * this means that "connected" vs. + * "disconnected" doesn't apply. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + close(sock); + return (0); + } + pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, errno, + "SIOCGIFMEDIA on %s failed", name); + close(sock); + return (-1); + } + close(sock); + + /* + * OK, what type of network is this? + */ + switch (IFM_TYPE(req.ifm_active)) { + + case IFM_IEEE80211: + /* + * Wireless. + */ + *flags |= PCAP_IF_WIRELESS; + break; + } + + /* + * Do we know whether it's connected? + */ + if (req.ifm_status & IFM_AVALID) { + /* + * Yes. + */ + if (req.ifm_status & IFM_ACTIVE) { + /* + * It's connected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; + } else { + /* + * It's disconnected. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; + } + } + return (0); +} +#else +static int +get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_) +{ + /* + * Nothing we can do other than mark loopback devices as "the + * connected/disconnected status doesn't apply". + * + * XXX - on Solaris, can we do what the dladm command does, + * i.e. get a connected/disconnected indication from a kstat? + * (Note that you can also get the link speed, and possibly + * other information, from a kstat as well.) + */ + if (*flags & PCAP_IF_LOOPBACK) { + /* + * Loopback devices aren't wireless, and "connected"/ + * "disconnected" doesn't apply to them. + */ + *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; + return (0); + } + return (0); +} +#endif + int -pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) { /* * Get the list of regular interfaces first. */ - if (pcap_findalldevs_interfaces(alldevsp, errbuf, check_bpf_bindable) == -1) + if (pcap_findalldevs_interfaces(devlistp, errbuf, check_bpf_bindable, + get_if_flags) == -1) return (-1); /* failure */ #if defined(__FreeBSD__) && defined(SIOCIFCREATE2) - if (finddevs_usb(alldevsp, errbuf) == -1) + if (finddevs_usb(devlistp, errbuf) == -1) return (-1); #endif @@ -2706,8 +2859,8 @@ monitor_mode(pcap_t *p, int set) sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't open socket: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "can't open socket"); return (PCAP_ERROR); } @@ -2738,8 +2891,8 @@ monitor_mode(pcap_t *p, int set) return (PCAP_ERROR_RFMON_NOTSUP); default: - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "SIOCGIFMEDIA 1: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFMEDIA 1"); close(sock); return (PCAP_ERROR); } @@ -2758,15 +2911,15 @@ monitor_mode(pcap_t *p, int set) */ media_list = malloc(req.ifm_count * sizeof(*media_list)); if (media_list == NULL) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "malloc"); close(sock); return (PCAP_ERROR); } req.ifm_ulist = media_list; if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "SIOCGIFMEDIA"); free(media_list); close(sock); return (PCAP_ERROR); @@ -2826,8 +2979,8 @@ monitor_mode(pcap_t *p, int set) sizeof(ifr.ifr_name)); ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR; if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "SIOCSIFMEDIA: %s", pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, + PCAP_ERRBUF_SIZE, errno, "SIOCSIFMEDIA"); close(sock); return (PCAP_ERROR); } @@ -3051,8 +3204,8 @@ pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp) * some kernels. */ if (errno != EINVAL) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s", - pcap_strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "BIOCSETF"); return (-1); } @@ -3080,11 +3233,10 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) direction = (d == PCAP_D_IN) ? BPF_D_IN : ((d == PCAP_D_OUT) ? BPF_D_OUT : BPF_D_INOUT); if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) { - (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), - "Cannot set direction to %s: %s", + pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "Cannot set direction to %s", (d == PCAP_D_IN) ? "PCAP_D_IN" : - ((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT"), - strerror(errno)); + ((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT")); return (-1); } return (0); @@ -3102,10 +3254,9 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) seesent = (d == PCAP_D_INOUT); if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) { - (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), - "Cannot set direction to %s: %s", - (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN", - strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "Cannot set direction to %s", + (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN"); return (-1); } return (0); @@ -3121,10 +3272,23 @@ pcap_set_datalink_bpf(pcap_t *p, int dlt) { #ifdef BIOCSDLT if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) { - (void) pcap_snprintf(p->errbuf, sizeof(p->errbuf), - "Cannot set DLT %d: %s", dlt, strerror(errno)); + pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), + errno, "Cannot set DLT %d", dlt); return (-1); } #endif return (0); } + +/* + * Platform-specific information. + */ +const char * +pcap_lib_version(void) +{ +#ifdef HAVE_ZEROCOPY_BPF + return (PCAP_VERSION_STRING " (with zerocopy support)"); +#else + return (PCAP_VERSION_STRING); +#endif +} |