diff options
author | guy <guy> | 2001-12-10 05:49:40 +0000 |
---|---|---|
committer | guy <guy> | 2001-12-10 05:49:40 +0000 |
commit | 1a00bc6928e5d066a479025c6eab38086abaebda (patch) | |
tree | 50b6d5f156b2aae059afbb180668e8145fc9476b | |
parent | fde2e99495fae8f5d5caca0c9142049adfdd3dce (diff) |
Fixes from Phil Wood:
Don't subtract "tp_drops" from "tp_packets" - "ps_recv", on BSD,
at least, includes packets dropped due to lack of buffer space,
so it should do so on Linux as well.
The "len" argument to "getsockopt()" is a value-result
parameter, initially containing the size of the buffer being
supplied; set it before the call.
Catch "getsockopt()" errors and, if it's an error other than
EOPNOTSUPP, return an error.
-rw-r--r-- | CREDITS | 1 | ||||
-rw-r--r-- | pcap-linux.c | 50 |
2 files changed, 48 insertions, 3 deletions
@@ -38,6 +38,7 @@ Additional people who have contributed patches: Onno van der Linden <onno@simplex.nl> Pavel Kankovsky <kan@dcit.cz> Peter Jeremy <peter.jeremy@alcatel.com.au> + Phil Wood <cpw@lanl.gov> Rafal Maszkowski <rzm@icm.edu.pl> Rick Jones <raj@cup.hp.com> Scott Barron <sb125499@ohiou.edu> diff --git a/pcap-linux.c b/pcap-linux.c index 49058ab6..1fc90541 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -26,7 +26,7 @@ */ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.71 2001-10-25 18:09:59 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.72 2001-12-10 05:49:40 guy Exp $ (LBL)"; #endif /* @@ -627,16 +627,60 @@ pcap_stats(pcap_t *handle, struct pcap_stat *stats) { #ifdef HAVE_TPACKET_STATS struct tpacket_stats kstats; - socklen_t len; + socklen_t len = sizeof (struct tpacket_stats); /* * Try to get the packet counts from the kernel. */ if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, &kstats, &len) > -1) { - handle->md.stat.ps_recv = (kstats.tp_packets - kstats.tp_drops); + /* + * In "linux/net/packet/af_packet.c", at least in the + * 2.4.9 kernel, "tp_packets" is incremented for every + * packet that passes the packet filter *and* is + * successfully queued on the socket; "tp_drops" is + * incremented for every packet dropped because there's + * not enough free space in the socket buffer. + * + * When the statistics are returned for a PACKET_STATISTICS + * "getsockopt()" call, "tp_drops" is added to "tp_packets", + * so that "tp_packets" counts all packets handed to + * the PF_PACKET socket, including packets dropped because + * there wasn't room on the socket buffer - but not + * including packets that didn't pass the filter. + * + * In the BSD BPF, the count of received packets is + * incremented for every packet handed to BPF, regardless + * of whether it passed the filter. + * + * We can't make "pcap_stats()" work the same on both + * platforms, but the best approximation is to return + * "tp_packets" as the count of packets and "tp_drops" + * as the count of drops. + * + * Note that "tp_packets" may include packets not yet + * processed by libpcap; the packets may have been + * queued on the socket but not read yet. (The equivalent + * may be true on other platforms.) + */ + handle->md.stat.ps_recv = kstats.tp_packets; handle->md.stat.ps_drop = kstats.tp_drops; } + else + { + /* + * If the error was EOPNOTSUPP, fall through, so that + * if you build the library on a system with + * "struct tpacket_stats" and run it on a system + * that doesn't, it works as it does if the library + * is built on a system without "struct tpacket_stats". + */ + if (errno != EOPNOTSUPP) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "pcap_stats: %s", pcap_strerror(errno)); + return -1; + } + } #endif /* * "ps_recv" counts only packets that passed the filter. |