summaryrefslogtreecommitdiffstats
path: root/contrib/libpcap/pcap-bpf.c
diff options
context:
space:
mode:
authorrpaulo <rpaulo@FreeBSD.org>2010-10-29 18:43:23 +0000
committerrpaulo <rpaulo@FreeBSD.org>2010-10-29 18:43:23 +0000
commit22f795f2fd7f982a2847bc9fc73e297abc7e2fbf (patch)
tree99c17a1bdbff3dabc0f310509b912bf2775d2145 /contrib/libpcap/pcap-bpf.c
parent2631ae0f3d6c77323709cd35d1f7241624662320 (diff)
parent724e1a015907ca989c4e1cb30c7ee4e88f26fbff (diff)
downloadFreeBSD-src-22f795f2fd7f982a2847bc9fc73e297abc7e2fbf.zip
FreeBSD-src-22f795f2fd7f982a2847bc9fc73e297abc7e2fbf.tar.gz
Merge libpcap-1.1.1.
Diffstat (limited to 'contrib/libpcap/pcap-bpf.c')
-rw-r--r--contrib/libpcap/pcap-bpf.c216
1 files changed, 170 insertions, 46 deletions
diff --git a/contrib/libpcap/pcap-bpf.c b/contrib/libpcap/pcap-bpf.c
index 8f35e4c..10dcfd1 100644
--- a/contrib/libpcap/pcap-bpf.c
+++ b/contrib/libpcap/pcap-bpf.c
@@ -22,7 +22,7 @@
*/
#ifndef lint
static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.99.2.17 2008-09-16 18:43:02 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.116 2008-09-16 18:42:29 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@@ -34,10 +34,24 @@ static const char rcsid[] _U_ =
#include <sys/mman.h>
#endif
#include <sys/time.h>
-#include <sys/timeb.h>
#include <sys/socket.h>
-#include <sys/file.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 -
+ * 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.
+ *
+ * If we have <sys/ioccom.h>, we include it as well, to handle systems
+ * such as Solaris which don't arrange to include <sys/ioccom.h> if you
+ * include <sys/ioctl.h>
+ */
#include <sys/ioctl.h>
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
#include <sys/utsname.h>
#ifdef HAVE_ZEROCOPY_BPF
@@ -87,6 +101,8 @@ static const char rcsid[] _U_ =
static int bpfloadedflag = 0;
static int odmlockid = 0;
+static int bpf_load(char *errbuf);
+
#else /* _AIX */
#include <net/bpf.h>
@@ -94,6 +110,7 @@ static int odmlockid = 0;
#endif /* _AIX */
#include <ctype.h>
+#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
@@ -111,6 +128,10 @@ static int odmlockid = 0;
#include "pcap-dag.h"
#endif /* HAVE_DAG_API */
+#ifdef HAVE_SNF_API
+#include "pcap-snf.h"
+#endif /* HAVE_SNF_API */
+
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
@@ -194,11 +215,26 @@ pcap_setnonblock_zbuf(pcap_t *p, int nonblock, char *errbuf)
* (from pcap-linux.c).
*/
if (nonblock) {
- if (p->md.timeout > 0)
+ if (p->md.timeout >= 0) {
+ /*
+ * Timeout is non-negative, so we're not already
+ * in non-blocking mode; set it to the 2's
+ * complement, to make it negative, as an
+ * indication that we're in non-blocking mode.
+ */
p->md.timeout = p->md.timeout * -1 - 1;
- } else
- if (p->md.timeout < 0)
+ }
+ } else {
+ if (p->md.timeout < 0) {
+ /*
+ * Timeout is negative, so we're not already
+ * in blocking mode; reverse the previous
+ * operation, to make the timeout non-negative
+ * again.
+ */
p->md.timeout = (p->md.timeout + 1) * -1;
+ }
+ }
return (0);
}
@@ -387,6 +423,10 @@ pcap_create(const char *device, char *ebuf)
if (strstr(device, "dag"))
return (dag_create(device, ebuf));
#endif /* HAVE_DAG_API */
+#ifdef HAVE_SNF_API
+ if (strstr(device, "snf"))
+ return (snf_create(device, ebuf));
+#endif /* HAVE_SNF_API */
p = pcap_create_common(device, ebuf);
if (p == NULL)
@@ -508,11 +548,20 @@ get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf)
* right thing to do, but I suspect it is - Ethernet <->
* 802.11 bridges would probably badly mishandle frames
* that don't have Ethernet headers).
+ *
+ * On Solaris with BPF, Ethernet devices also offer
+ * DLT_IPNET, so we, if DLT_IPNET is defined, we don't
+ * treat it as an indication that the device isn't an
+ * Ethernet.
*/
if (v == DLT_EN10MB) {
is_ethernet = 1;
for (i = 0; i < bdlp->bfl_len; i++) {
- if (bdlp->bfl_list[i] != DLT_EN10MB) {
+ if (bdlp->bfl_list[i] != DLT_EN10MB
+#ifdef DLT_IPNET
+ && bdlp->bfl_list[i] != DLT_IPNET
+#endif
+ ) {
is_ethernet = 0;
break;
}
@@ -714,6 +763,7 @@ pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps)
ps->ps_recv = s.bs_recv;
ps->ps_drop = s.bs_drop;
+ ps->ps_ifdrop = 0;
return (0);
}
@@ -803,7 +853,22 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
case EWOULDBLOCK:
return (0);
-#if defined(sun) && !defined(BSD)
+
+ case ENXIO:
+ /*
+ * The device on which we're capturing
+ * went away.
+ *
+ * XXX - we should really return
+ * PCAP_ERROR_IFACE_NOT_UP, but
+ * pcap_dispatch() etc. aren't
+ * defined to retur that.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The interface went down");
+ return (PCAP_ERROR);
+
+#if defined(sun) && !defined(BSD) && !defined(__svr4__) && !defined(__SVR4)
/*
* Due to a SunOS bug, after 2^31 bytes, the kernel
* file offset overflows and read fails with EINVAL.
@@ -991,6 +1056,7 @@ bpf_odminit(char *errbuf)
snprintf(errbuf, PCAP_ERRBUF_SIZE,
"bpf_load: odm_lock of /etc/objrepos/config_lock failed: %s",
errstr);
+ (void)odm_terminate();
return (PCAP_ERROR);
}
@@ -1003,20 +1069,24 @@ bpf_odmcleanup(char *errbuf)
char *errstr;
if (odm_unlock(odmlockid) == -1) {
- if (odm_err_msg(odmerrno, &errstr) == -1)
- errstr = "Unknown error";
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "bpf_load: odm_unlock failed: %s",
- errstr);
+ if (errbuf != NULL) {
+ if (odm_err_msg(odmerrno, &errstr) == -1)
+ errstr = "Unknown error";
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "bpf_load: odm_unlock failed: %s",
+ errstr);
+ }
return (PCAP_ERROR);
}
if (odm_terminate() == -1) {
- if (odm_err_msg(odmerrno, &errstr) == -1)
- errstr = "Unknown error";
- snprintf(errbuf, PCAP_ERRBUF_SIZE,
- "bpf_load: odm_terminate failed: %s",
- errstr);
+ if (errbuf != NULL) {
+ if (odm_err_msg(odmerrno, &errstr) == -1)
+ errstr = "Unknown error";
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "bpf_load: odm_terminate failed: %s",
+ errstr);
+ }
return (PCAP_ERROR);
}
@@ -1049,6 +1119,7 @@ bpf_load(char *errbuf)
if (major == -1) {
snprintf(errbuf, PCAP_ERRBUF_SIZE,
"bpf_load: genmajor failed: %s", pcap_strerror(errno));
+ (void)bpf_odmcleanup(NULL);
return (PCAP_ERROR);
}
@@ -1059,6 +1130,7 @@ bpf_load(char *errbuf)
snprintf(errbuf, PCAP_ERRBUF_SIZE,
"bpf_load: genminor failed: %s",
pcap_strerror(errno));
+ (void)bpf_odmcleanup(NULL);
return (PCAP_ERROR);
}
}
@@ -1135,13 +1207,13 @@ pcap_cleanup_bpf(pcap_t *p)
struct ifreq ifr;
#endif
- if (p->md.must_clear != 0) {
+ if (p->md.must_do_on_close != 0) {
/*
* There's something we have to do when closing this
* pcap_t.
*/
#ifdef HAVE_BSD_IEEE80211
- if (p->md.must_clear & MUST_CLEAR_RFMON) {
+ if (p->md.must_do_on_close & MUST_CLEAR_RFMON) {
/*
* We put the interface into rfmon mode;
* take it out of rfmon mode.
@@ -1196,7 +1268,7 @@ pcap_cleanup_bpf(pcap_t *p)
* have to take the interface out of some mode.
*/
pcap_remove_from_pcaps_to_close(p);
- p->md.must_clear = 0;
+ p->md.must_do_on_close = 0;
}
#ifdef HAVE_ZEROCOPY_BPF
@@ -1253,7 +1325,9 @@ check_setif_failure(pcap_t *p, int error)
* exist.
*/
err = PCAP_ERROR_NO_SUCH_DEVICE;
- strcpy(p->errbuf, "");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "SIOCGIFFLAGS on %s failed: %s",
+ ifr.ifr_name, pcap_strerror(errno));
} else {
/*
* The underlying "enN" device
@@ -1275,7 +1349,9 @@ check_setif_failure(pcap_t *p, int error)
* just report "no such device".
*/
err = PCAP_ERROR_NO_SUCH_DEVICE;
- strcpy(p->errbuf, "");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "socket() failed: %s",
+ pcap_strerror(errno));
}
return (err);
}
@@ -1283,7 +1359,8 @@ check_setif_failure(pcap_t *p, int error)
/*
* No such device.
*/
- strcpy(p->errbuf, "");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF failed: %s",
+ pcap_strerror(errno));
return (PCAP_ERROR_NO_SUCH_DEVICE);
} else if (errno == ENETDOWN) {
/*
@@ -1305,6 +1382,13 @@ check_setif_failure(pcap_t *p, int error)
}
}
+/*
+ * Default capture buffer size.
+ * 32K isn't very much for modern machines with fast networks; we
+ * pick .5M, as that's the maximum on at least some systems with BPF.
+ */
+#define DEFAULT_BUFSIZE 524288
+
static int
pcap_activate_bpf(pcap_t *p)
{
@@ -1431,7 +1515,10 @@ pcap_activate_bpf(pcap_t *p)
* exist.
*/
status = PCAP_ERROR_NO_SUCH_DEVICE;
- strcpy(p->errbuf, "");
+ snprintf(p->errbuf,
+ PCAP_ERRBUF_SIZE,
+ "SIOCGIFFLAGS failed: %s",
+ pcap_strerror(errno));
} else
status = PCAP_ERROR_RFMON_NOTSUP;
close(sockfd);
@@ -1442,7 +1529,10 @@ pcap_activate_bpf(pcap_t *p)
* report "no such device".
*/
status = PCAP_ERROR_NO_SUCH_DEVICE;
- strcpy(p->errbuf, "");
+ snprintf(p->errbuf,
+ PCAP_ERRBUF_SIZE,
+ "socket() failed: %s",
+ pcap_strerror(errno));
}
goto bad;
}
@@ -1509,8 +1599,8 @@ pcap_activate_bpf(pcap_t *p)
v = p->opt.buffer_size;
} else {
if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) ||
- v < 32768)
- v = 32768;
+ v < DEFAULT_BUFSIZE)
+ v = DEFAULT_BUFSIZE;
}
#ifndef roundup
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */
@@ -1576,14 +1666,15 @@ pcap_activate_bpf(pcap_t *p)
/*
* 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.
+ * Try finding a good size for the buffer;
+ * DEFAULT_BUFSIZE 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;
+ v < DEFAULT_BUFSIZE)
+ v = DEFAULT_BUFSIZE;
for ( ; v != 0; v >>= 1) {
/*
* Ignore the return value - this is because the
@@ -1878,16 +1969,45 @@ pcap_activate_bpf(pcap_t *p)
* XXX - is this seconds/nanoseconds in AIX?
* (Treating it as such doesn't fix the timeout
* problem described below.)
+ *
+ * XXX - Mac OS X 10.6 mishandles BIOCSRTIMEOUT in
+ * 64-bit userland - it takes, as an argument, a
+ * "struct BPF_TIMEVAL", which has 32-bit tv_sec
+ * and tv_usec, rather than a "struct timeval".
+ *
+ * If this platform defines "struct BPF_TIMEVAL",
+ * we check whether the structure size in BIOCSRTIMEOUT
+ * is that of a "struct timeval" and, if not, we use
+ * a "struct BPF_TIMEVAL" rather than a "struct timeval".
+ * (That way, if the bug is fixed in a future release,
+ * we will still do the right thing.)
*/
struct timeval to;
- 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(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
- pcap_strerror(errno));
- status = PCAP_ERROR;
- goto bad;
+#ifdef HAVE_STRUCT_BPF_TIMEVAL
+ struct BPF_TIMEVAL bpf_to;
+
+ if (IOCPARM_LEN(BIOCSRTIMEOUT) != sizeof(struct timeval)) {
+ bpf_to.tv_sec = p->md.timeout / 1000;
+ bpf_to.tv_usec = (p->md.timeout * 1000) % 1000000;
+ if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&bpf_to) < 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "BIOCSRTIMEOUT: %s", pcap_strerror(errno));
+ status = PCAP_ERROR;
+ goto bad;
+ }
+ } else {
+#endif
+ 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(p->errbuf, PCAP_ERRBUF_SIZE,
+ "BIOCSRTIMEOUT: %s", pcap_strerror(errno));
+ status = PCAP_ERROR;
+ goto bad;
+ }
+#ifdef HAVE_STRUCT_BPF_TIMEVAL
}
+#endif
}
#ifdef _AIX
@@ -2077,6 +2197,10 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
if (dag_platform_finddevs(alldevsp, errbuf) < 0)
return (-1);
#endif /* HAVE_DAG_API */
+#ifdef HAVE_SNF_API
+ if (snf_platform_finddevs(alldevsp, errbuf) < 0)
+ return (-1);
+#endif /* HAVE_SNF_API */
return (0);
}
@@ -2211,7 +2335,7 @@ monitor_mode(pcap_t *p, int set)
return (PCAP_ERROR);
}
- p->md.must_clear |= MUST_CLEAR_RFMON;
+ p->md.must_do_on_close |= MUST_CLEAR_RFMON;
/*
* Add this to the list of pcaps to close when we exit.
@@ -2296,7 +2420,8 @@ find_802_11(struct bpf_dltlist *bdlp)
#if defined(__APPLE__) && defined(BIOCGDLTLIST)
/*
- * Remove DLT_EN10MB from the list of DLT_ values.
+ * Remove DLT_EN10MB from the list of DLT_ values, as we're in monitor mode,
+ * and DLT_EN10MB isn't supported in monitor mode.
*/
static void
remove_en(pcap_t *p)
@@ -2337,10 +2462,9 @@ remove_en(pcap_t *p)
}
/*
- * 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.
+ * Remove 802.11 link-layer types from the list of DLT_ values, as
+ * we're not in monitor mode, and those DLT_ values will switch us
+ * to monitor mode.
*/
static void
remove_802_11(pcap_t *p)
OpenPOWER on IntegriCloud