From 380a3dbf496510c5a14d0f95bb51ed6822f44130 Mon Sep 17 00:00:00 2001 From: guy Date: Sun, 29 Jul 2001 18:25:46 +0000 Subject: [PATCH] From Scott Barron : use the SOL_PACKET/PACKET_STATISTICS "getsockopt()" call, on Linux kernels that support it, to get packet statistics, so that we can report the number of dropped packets, and always use to get definitions for PF_PACKET sockets, so that we don't depend on glibc's header files having been updated to support all the latest shiniest kernel features (many systems with 2.4[.x] kernels don't have a that defines "struct tpacket_stats", for example, so we wouldn't have been able to support that kernel feature on those systems). --- CREDITS | 1 + README.linux | 18 ++++ aclocal.m4 | 20 ++++- config.h.in | 6 +- configure | 236 +++++++++++++++++++++++++-------------------------- configure.in | 6 +- pcap-linux.c | 122 ++++++++++++++++++-------- 7 files changed, 246 insertions(+), 163 deletions(-) diff --git a/CREDITS b/CREDITS index 5537c1c..3583847 100644 --- a/CREDITS +++ b/CREDITS @@ -37,6 +37,7 @@ Additional people who have contributed patches: Peter Jeremy Rafal Maszkowski Rick Jones + Scott Barron Stefan Hudson Tony Li Uns Lider diff --git a/README.linux b/README.linux index ecd00e8..dd95913 100644 --- a/README.linux +++ b/README.linux @@ -68,3 +68,21 @@ file says: Filtering works on all socket types except TCP for now. See the text file linux/Documentation/networking/filter.txt for more information. If unsure, say N. + + +Statistics: +Statistics reported by pcap are platform specific. The statistics +reported by pcap_stats on Linux are as follows: + +2.2.x +===== +ps_recv Number of packets that were accepted by the pcap filter +ps_drops Always 0, this statistic is not gatherd on this platform + +2.4.x +===== +ps_rec Number of packets that were accepted by the pcap filter +ps_drops Number of packets that had passed filtering but were not + passed on to pcap due to things like buffer shortage, etc. + This is useful because these are packets you are interested in + but won't be reported by, for example, tcpdump output. diff --git a/aclocal.m4 b/aclocal.m4 index e283bc8..8f4d9ab 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,4 +1,4 @@ -dnl @(#) $Header: /tcpdump/master/libpcap/aclocal.m4,v 1.71 2000-09-19 03:56:26 guy Exp $ (LBL) +dnl @(#) $Header: /tcpdump/master/libpcap/aclocal.m4,v 1.72 2001-07-29 18:25:46 guy Exp $ (LBL) dnl dnl Copyright (c) 1995, 1996, 1997, 1998 dnl The Regents of the University of California. All rights reserved. @@ -767,3 +767,21 @@ fi AC_MSG_RESULT($ac_cv___attribute__) ]) +dnl +dnl Checks to see if tpacket_stats is defined in linux/if_packet.h +dnl If so then pcap-linux.c can use this to report proper statistics. +dnl +dnl -Scott Barron +dnl +AC_DEFUN(AC_LBL_TPACKET_STATS, + [AC_MSG_CHECKING(if if_packet.h has tpacket_stats defined) + AC_CACHE_VAL(ac_cv_lbl_tpacket_stats, + AC_TRY_COMPILE([ +# include ], + [struct tpacket_stats stats], + ac_cv_lbl_tpacket_stats=yes, + ac_cv_lbl_tpacket_stats=no)) + AC_MSG_RESULT($ac_cv_lbl_tpacket_stats) + if test $ac_cv_lbl_tpacket_stats = yes; then + AC_DEFINE(HAVE_TPACKET_STATS,1,[if if_packet.h has tpacket_stats defined]) + fi]) diff --git a/config.h.in b/config.h.in index f012a9d..c02efad 100644 --- a/config.h.in +++ b/config.h.in @@ -24,9 +24,6 @@ /* Define if you have the header file. */ #undef HAVE_NETINET_IF_ETHER_H -/* Define if you have the header file. */ -#undef HAVE_NETPACKET_PACKET_H - /* Define if you have the header file. */ #undef HAVE_SYS_BUFMOD_H @@ -66,6 +63,9 @@ /* /dev/dlpi directory */ #undef PCAP_DEV_PREFIX +/* if if_packet.h has tpacket_stats defined */ +#undef HAVE_TPACKET_STATS + /* define on AIX to get certain functions */ #undef _SUN diff --git a/configure b/configure index 5245a8a..500502f 100755 --- a/configure +++ b/configure @@ -1,6 +1,7 @@ #! /bin/sh -# From configure.in Revision: 1.88 +# From configure.in Revision: 1.89 + @@ -616,7 +617,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:620: checking host system type" >&5 +echo "configure:621: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -637,7 +638,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$host" 1>&6 echo $ac_n "checking target system type""... $ac_c" 1>&6 -echo "configure:641: checking target system type" >&5 +echo "configure:642: checking target system type" >&5 target_alias=$target case "$target_alias" in @@ -655,7 +656,7 @@ target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$target" 1>&6 echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:659: checking build system type" >&5 +echo "configure:660: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -703,7 +704,7 @@ fi # Extract the first word of "shlicc2", so it can be a program name with args. set dummy shlicc2; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:707: checking for $ac_word" >&5 +echo "configure:708: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_SHLICC2'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -744,7 +745,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:748: checking for $ac_word" >&5 +echo "configure:749: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -774,7 +775,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:778: checking for $ac_word" >&5 +echo "configure:779: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -825,7 +826,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:829: checking for $ac_word" >&5 +echo "configure:830: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -857,7 +858,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:861: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:862: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -868,12 +869,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 872 "configure" +#line 873 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:877: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:878: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -899,12 +900,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:903: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:904: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:908: checking whether we are using GNU C" >&5 +echo "configure:909: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -913,7 +914,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:917: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:918: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -932,7 +933,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:936: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:937: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -969,7 +970,7 @@ fi V_CCOPT="-O2" else echo $ac_n "checking gcc version""... $ac_c" 1>&6 -echo "configure:973: checking gcc version" >&5 +echo "configure:974: checking gcc version" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_gcc_vers'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -987,19 +988,19 @@ fi fi else echo $ac_n "checking that $CC handles ansi prototypes""... $ac_c" 1>&6 -echo "configure:991: checking that $CC handles ansi prototypes" >&5 +echo "configure:992: checking that $CC handles ansi prototypes" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_cc_ansi_prototypes'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { int frob(int, char *) ; return 0; } EOF -if { (eval echo configure:1003: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1004: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_cc_ansi_prototypes=yes else @@ -1017,21 +1018,21 @@ fi hpux*) echo $ac_n "checking for HP-UX ansi compiler ($CC -Aa -D_HPUX_SOURCE)""... $ac_c" 1>&6 -echo "configure:1021: checking for HP-UX ansi compiler ($CC -Aa -D_HPUX_SOURCE)" >&5 +echo "configure:1022: checking for HP-UX ansi compiler ($CC -Aa -D_HPUX_SOURCE)" >&5 savedcflags="$CFLAGS" CFLAGS="-Aa -D_HPUX_SOURCE $CFLAGS" if eval "test \"`echo '$''{'ac_cv_lbl_cc_hpux_cc_aa'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { int frob(int, char *) ; return 0; } EOF -if { (eval echo configure:1035: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1036: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_cc_hpux_cc_aa=yes else @@ -1075,12 +1076,12 @@ EOF ultrix*) echo $ac_n "checking that Ultrix $CC hacks const in prototypes""... $ac_c" 1>&6 -echo "configure:1079: checking that Ultrix $CC hacks const in prototypes" >&5 +echo "configure:1080: checking that Ultrix $CC hacks const in prototypes" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_cc_const_proto'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { @@ -1088,7 +1089,7 @@ struct a { int b; }; void c(const struct a *) ; return 0; } EOF -if { (eval echo configure:1092: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1093: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_cc_const_proto=yes else @@ -1112,21 +1113,21 @@ EOF fi echo $ac_n "checking for inline""... $ac_c" 1>&6 -echo "configure:1116: checking for inline" >&5 +echo "configure:1117: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1131: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else @@ -1153,13 +1154,13 @@ esac echo $ac_n "checking for __attribute__""... $ac_c" 1>&6 -echo "configure:1157: checking for __attribute__" >&5 +echo "configure:1158: checking for __attribute__" >&5 if eval "test \"`echo '$''{'ac_cv___attribute__'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < @@ -1176,7 +1177,7 @@ foo(void) ; return 0; } EOF -if { (eval echo configure:1180: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1181: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv___attribute__=yes else @@ -1198,12 +1199,12 @@ echo "$ac_t""$ac_cv___attribute__" 1>&6 echo $ac_n "checking for u_int8_t using $CC""... $ac_c" 1>&6 -echo "configure:1202: checking for u_int8_t using $CC" >&5 +echo "configure:1203: checking for u_int8_t using $CC" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_have_u_int8_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1221: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_have_u_int8_t=yes else @@ -1236,12 +1237,12 @@ EOF fi echo $ac_n "checking for u_int16_t using $CC""... $ac_c" 1>&6 -echo "configure:1240: checking for u_int16_t using $CC" >&5 +echo "configure:1241: checking for u_int16_t using $CC" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_have_u_int16_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1259: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_have_u_int16_t=yes else @@ -1274,12 +1275,12 @@ EOF fi echo $ac_n "checking for u_int32_t using $CC""... $ac_c" 1>&6 -echo "configure:1278: checking for u_int32_t using $CC" >&5 +echo "configure:1279: checking for u_int32_t using $CC" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_have_u_int32_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1297: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_have_u_int32_t=yes else @@ -1313,7 +1314,7 @@ EOF fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:1317: checking how to run the C preprocessor" >&5 +echo "configure:1318: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -1328,13 +1329,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1338: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1339: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1345,13 +1346,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1355: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1356: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1362,13 +1363,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1372: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1373: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1396,17 +1397,17 @@ for ac_hdr in sys/ioccom.h sys/sockio.h ifaddrs.h netinet/if_ether.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1400: checking for $ac_hdr" >&5 +echo "configure:1401: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1410: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1411: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -1435,12 +1436,12 @@ done if test "$GCC" = yes ; then echo $ac_n "checking for ANSI ioctl definitions""... $ac_c" 1>&6 -echo "configure:1439: checking for ANSI ioctl definitions" >&5 +echo "configure:1440: checking for ANSI ioctl definitions" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_gcc_fixincludes'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1464: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_gcc_fixincludes=yes else @@ -1482,12 +1483,12 @@ fi for ac_func in ether_hostton strerror freeifaddrs strlcpy do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1486: checking for $ac_func" >&5 +echo "configure:1487: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1515: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1536,7 +1537,7 @@ done echo $ac_n "checking if --disable-protochain option is specified""... $ac_c" 1>&6 -echo "configure:1540: checking if --disable-protochain option is specified" >&5 +echo "configure:1541: checking if --disable-protochain option is specified" >&5 # Check whether --enable-protochain or --disable-protochain was given. if test "${enable_protochain+set}" = set; then enableval="$enable_protochain" @@ -1567,7 +1568,7 @@ if test "${with_pcap+set}" = set; then fi echo $ac_n "checking packet capture type""... $ac_c" 1>&6 -echo "configure:1571: checking packet capture type" >&5 +echo "configure:1572: checking packet capture type" >&5 if test ! -z "$with_pcap" ; then V_PCAP="$withval" elif test -r /dev/bpf0 ; then @@ -1598,7 +1599,7 @@ fi echo "$ac_t""$V_PCAP" 1>&6 echo $ac_n "checking if --enable-ipv6 option is specified""... $ac_c" 1>&6 -echo "configure:1602: checking if --enable-ipv6 option is specified" >&5 +echo "configure:1603: checking if --enable-ipv6 option is specified" >&5 # Check whether --enable-ipv6 or --disable-ipv6 was given. if test "${enable_ipv6+set}" = set; then enableval="$enable_ipv6" @@ -1620,17 +1621,17 @@ dlpi) do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1624: checking for $ac_hdr" >&5 +echo "configure:1625: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1634: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1635: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -1657,7 +1658,7 @@ fi done echo $ac_n "checking for /dev/dlpi device""... $ac_c" 1>&6 -echo "configure:1661: checking for /dev/dlpi device" >&5 +echo "configure:1662: checking for /dev/dlpi device" >&5 if test -c /dev/dlpi ; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF @@ -1668,7 +1669,7 @@ EOF echo "$ac_t""no" 1>&6 dir="/dev/dlpi" echo $ac_n "checking for $dir directory""... $ac_c" 1>&6 -echo "configure:1672: checking for $dir directory" >&5 +echo "configure:1673: checking for $dir directory" >&5 if test -d $dir ; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <&6 -echo "configure:1690: checking for $ac_hdr" >&5 -if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -EOF -ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1700: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` -if test -z "$ac_err"; then - rm -rf conftest* - eval "ac_cv_header_$ac_safe=yes" -else - echo "$ac_err" >&5 - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_header_$ac_safe=no" -fi -rm -f conftest* -fi -if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - cat >> confdefs.h <&6 -fi -done - echo $ac_n "checking Linux kernel version""... $ac_c" 1>&6 -echo "configure:1727: checking Linux kernel version" >&5 +echo "configure:1688: checking Linux kernel version" >&5 if test "$cross_compiling" = yes; then if eval "test \"`echo '$''{'ac_cv_linux_vers'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1747,6 +1708,39 @@ fi if test $ac_cv_linux_vers -lt 2 ; then { echo "configure: error: version 2 or higher required; see the INSTALL doc for more info" 1>&2; exit 1; } fi + echo $ac_n "checking if if_packet.h has tpacket_stats defined""... $ac_c" 1>&6 +echo "configure:1713: checking if if_packet.h has tpacket_stats defined" >&5 + if eval "test \"`echo '$''{'ac_cv_lbl_tpacket_stats'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +struct tpacket_stats stats +; return 0; } +EOF +if { (eval echo configure:1726: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_lbl_tpacket_stats=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_lbl_tpacket_stats=no +fi +rm -f conftest* +fi + + echo "$ac_t""$ac_cv_lbl_tpacket_stats" 1>&6 + if test $ac_cv_lbl_tpacket_stats = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_TPACKET_STATS 1 +EOF + + fi ;; null) @@ -1776,7 +1770,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1780: checking for $ac_word" >&5 +echo "configure:1774: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_V_LEX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1810,7 +1804,7 @@ test -n "$V_LEX" || V_LEX="lex" if test "$V_LEX" = flex ; then # The -V flag was added in 2.4 echo $ac_n "checking for flex 2.4 or higher""... $ac_c" 1>&6 -echo "configure:1814: checking for flex 2.4 or higher" >&5 +echo "configure:1808: checking for flex 2.4 or higher" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_flex_v24'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1836,7 +1830,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1840: checking for $ac_word" >&5 +echo "configure:1834: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_V_YACC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1883,7 +1877,7 @@ if test "$V_LEX" = lex ; then # Some versions of lex can't handle the definitions section of scanner.l . # Try lexing it and complain if it can't deal. echo $ac_n "checking for capable lex""... $ac_c" 1>&6 -echo "configure:1887: checking for capable lex" >&5 +echo "configure:1881: checking for capable lex" >&5 if eval "test \"`echo '$''{'tcpdump_cv_capable_lex'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1934,19 +1928,19 @@ EOF sinix*) echo $ac_n "checking if SINIX compiler defines sinix""... $ac_c" 1>&6 -echo "configure:1938: checking if SINIX compiler defines sinix" >&5 +echo "configure:1932: checking if SINIX compiler defines sinix" >&5 if eval "test \"`echo '$''{'ac_cv_cc_sinix_defined'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1944: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cc_sinix_defined=yes else @@ -1978,7 +1972,7 @@ esac # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1982: checking for $ac_word" >&5 +echo "configure:1976: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2046,12 +2040,12 @@ EOF fi echo $ac_n "checking if sockaddr struct has sa_len member""... $ac_c" 1>&6 -echo "configure:2050: checking if sockaddr struct has sa_len member" >&5 +echo "configure:2044: checking if sockaddr struct has sa_len member" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_sockaddr_has_sa_len'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < @@ -2060,7 +2054,7 @@ int main() { u_int i = sizeof(((struct sockaddr *)0)->sa_len) ; return 0; } EOF -if { (eval echo configure:2064: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2058: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_sockaddr_has_sa_len=yes else @@ -2081,12 +2075,12 @@ EOF fi echo $ac_n "checking if dl_hp_ppa_info_t struct has dl_module_id_1 member""... $ac_c" 1>&6 -echo "configure:2085: checking if dl_hp_ppa_info_t struct has dl_module_id_1 member" >&5 +echo "configure:2079: checking if dl_hp_ppa_info_t struct has dl_module_id_1 member" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < @@ -2096,7 +2090,7 @@ int main() { u_int i = sizeof(((dl_hp_ppa_info_t *)0)->dl_module_id_1) ; return 0; } EOF -if { (eval echo configure:2100: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2094: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_lbl_dl_hp_ppa_info_t_has_dl_module_id_1=yes else @@ -2117,7 +2111,7 @@ EOF fi echo $ac_n "checking if unaligned accesses fail""... $ac_c" 1>&6 -echo "configure:2121: checking if unaligned accesses fail" >&5 +echo "configure:2115: checking if unaligned accesses fail" >&5 if eval "test \"`echo '$''{'ac_cv_lbl_unaligned_fail'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2202,7 +2196,7 @@ ln -s ${srcdir}/bpf/net net # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:2206: checking for a BSD compatible install" >&5 +echo "configure:2200: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 diff --git a/configure.in b/configure.in index eefa3c3..6dd0f19 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.88 2001-01-17 18:18:48 guy Exp $ (LBL) +dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.89 2001-07-29 18:25:47 guy Exp $ (LBL) dnl dnl Copyright (c) 1994, 1995, 1996, 1997 dnl The Regents of the University of California. All rights reserved. @@ -6,7 +6,7 @@ dnl dnl Process this file with autoconf to produce a configure script. dnl -AC_REVISION($Revision: 1.88 $) +AC_REVISION($Revision: 1.89 $) AC_INIT(pcap.c) AC_CANONICAL_SYSTEM @@ -116,7 +116,6 @@ dlpi) ;; linux) - AC_CHECK_HEADERS(netpacket/packet.h) AC_MSG_CHECKING(Linux kernel version) if test "$cross_compiling" = yes; then AC_CACHE_VAL(ac_cv_linux_vers, @@ -133,6 +132,7 @@ linux) if test $ac_cv_linux_vers -lt 2 ; then AC_MSG_ERROR(version 2 or higher required; see the INSTALL doc for more info) fi + AC_LBL_TPACKET_STATS ;; null) diff --git a/pcap-linux.c b/pcap-linux.c index ea8b30b..2b1604c 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.60 2001-07-29 01:22:41 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.61 2001-07-29 18:25:47 guy Exp $ (LBL)"; #endif /* @@ -74,37 +74,38 @@ static const char rcsid[] = #include #include -#ifdef HAVE_NETPACKET_PACKET_H -# include +/* + * If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET + * sockets rather than SOCK_PACKET sockets. + * + * To use them, we include rather than + * ; we do so because + * + * some Linux distributions (e.g., Slackware 4.0) have 2.2 or + * later kernels and libc5, and don't provide a + * file; + * + * not all versions of glibc2 have a file + * that defines stuff needed for some of the 2.4-or-later-kernel + * features, so if the system has a 2.4 or later kernel, we + * still can't use those features. + * + * We're already including a number of other headers, and + * this code is Linux-specific (no other OS has PF_PACKET sockets as + * a raw packet capture mechanism), so it's not as if you gain any + * useful portability by using + * + * XXX - should we just include even if PF_PACKET + * isn't defined? It only defines one data structure in 2.0.x, so + * it shouldn't cause any problems. + */ +#ifdef PF_PACKET +# include /* - * We assume this means we really do have PF_PACKET sockets. - */ -# define HAVE_PF_PACKET_SOCKETS -#else - /* - * Oh, joy. Some Linux distributions have 2.2 or later kernels and - * libc5. On at least one of those systems (Slackware 4.0), it - * appears that "/usr/include/sys/socket.h" includes , - * which means it picks up all the AF_, PF_, and SO_ definitions - * appropriate for the current kernel; however, it also appears that - * they did not see fit to provide a "/usr/include/netpacket/packet.h" - * file. - * - * However, you should be able to get the right definitions by including - * . - * - * So if this system has PF_PACKET defined but doesn't have the - * header file, we include - * instead. - */ -# ifdef PF_PACKET -# include - - /* - * However, on at least some Linux distributions (for example, Red Hat - * 5.2), there's no file, but PF_PACKET is defined - * if you include , but doesn't define + * On at least some Linux distributions (for example, Red Hat 5.2), + * there's no file, but PF_PACKET is defined if + * you include , but doesn't define * any of the PF_PACKET stuff such as "struct sockaddr_ll" or any of * the PACKET_xxx stuff. * @@ -114,8 +115,7 @@ static const char rcsid[] = # ifdef PACKET_HOST # define HAVE_PF_PACKET_SOCKETS # endif /* PACKET_HOST */ -# endif /* PF_PACKET */ -#endif /* HAVE_NETPACKET_PACKET_H */ +#endif /* PF_PACKET */ #ifdef SO_ATTACH_FILTER #include @@ -440,8 +440,42 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) pcap_header.caplen = caplen; pcap_header.len = packet_len; - /* Call the user supplied callback function */ + /* + * Count the packet. + * + * Arguably, we should count them before we check the filter, + * as on many other platforms "ps_recv" counts packets + * handed to the filter rather than packets that passed + * the filter, but if filtering is done in the kernel, we + * can't get a count of packets that passed the filter, + * and that would mean the meaning of "ps_recv" wouldn't + * be the same on all Linux systems. + * + * XXX - it's not the same on all systems in any case; + * ideally, we should have a "get the statistics" call + * that supplies more counts and indicates which of them + * it supplies, so that we supply a count of packets + * handed to the filter only on platforms where that + * information is available. + * + * We count them here even if we can get the packet count + * from the kernel, as we can only determine at run time + * whether we'll be able to get it from the kernel (if + * HAVE_TPACKET_STATS isn't defined, we can't get it from + * the kernel, but if it is defined, the library might + * have been built with a 2.4 or later kernel, but we + * might be running on a 2.2[.x] kernel without Alexey + * Kuznetzov's turbopacket patches, and thus the kernel + * might not be able to supply those statistics). We + * could, I guess, try, when opening the socket, to get + * the statistics, and if we can not increment the count + * here, but it's not clear that always incrementing + * the count is more expensive than always testing a flag + * in memory. + */ handle->md.stat.ps_recv++; + + /* Call the user supplied callback function */ callback(userdata, &pcap_header, handle->buffer + handle->offset); return 1; @@ -449,15 +483,33 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) /* * Get the statistics for the given packet capture handle. - * FIXME: Currently does not report the number of dropped packets. + * Reports the number of dropped packets iff the kernel supports + * the PACKET_STATISTICS "getsockopt()" argument (2.4 and later + * kernels, and 2.2[.x] kernels with Alexey Kuznetzov's turbopacket + * patches); otherwise, that information isn't available, and we lie + * and report 0 as the count of dropped packets. */ int pcap_stats(pcap_t *handle, struct pcap_stat *stats) { +#ifdef HAVE_TPACKET_STATS + struct tpacket_stats kstats; + socklen_t len; + + /* + * 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); + handle->md.stat.ps_drop = kstats.tp_drops; + } +#endif /* * "ps_recv" counts only packets that passed the filter. * - * "ps_drop" isn't maintained. + * "ps_drop" is maintained only on systems that support + * the PACKET_STATISTICS "getsockopt()" argument. */ *stats = handle->md.stat; return 0;