diff options
author | rpaulo <rpaulo@FreeBSD.org> | 2010-10-29 18:43:23 +0000 |
---|---|---|
committer | rpaulo <rpaulo@FreeBSD.org> | 2010-10-29 18:43:23 +0000 |
commit | 22f795f2fd7f982a2847bc9fc73e297abc7e2fbf (patch) | |
tree | 99c17a1bdbff3dabc0f310509b912bf2775d2145 /contrib/libpcap/pcap-bpf.c | |
parent | 2631ae0f3d6c77323709cd35d1f7241624662320 (diff) | |
parent | 724e1a015907ca989c4e1cb30c7ee4e88f26fbff (diff) | |
download | FreeBSD-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.c | 216 |
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) |