diff options
author | guy <guy> | 2008-03-13 18:13:57 +0000 |
---|---|---|
committer | guy <guy> | 2008-03-13 18:13:57 +0000 |
commit | cb44cb05205a7a319e5093fb43ad1e2d66534cb9 (patch) | |
tree | 5035679f04ffd84523cc03d267dc8bd6837e0a85 | |
parent | b32210369660e46420fff7b079dbcafb32bf32ce (diff) |
Support for libdlpi, and for enabling "passive mode" on Solaris systems
that support it, from Sagun Shakya.
-rw-r--r-- | FILES | 3 | ||||
-rw-r--r-- | INSTALL.txt | 5 | ||||
-rw-r--r-- | aclocal.m4 | 29 | ||||
-rw-r--r-- | config.h.in | 6 | ||||
-rwxr-xr-x | configure | 438 | ||||
-rw-r--r-- | configure.in | 37 | ||||
-rw-r--r-- | dlpisubs.c | 349 | ||||
-rw-r--r-- | dlpisubs.h | 28 | ||||
-rw-r--r-- | pcap-dlpi.c | 308 | ||||
-rw-r--r-- | pcap-int.h | 12 | ||||
-rw-r--r-- | pcap-libdlpi.c | 356 |
11 files changed, 1159 insertions, 412 deletions
@@ -33,6 +33,8 @@ config.h.in config.sub configure configure.in +dlpisubs.c +dlpisubs.h etherent.c ethertype.h fad-getad.c @@ -94,6 +96,7 @@ pcap-dos.c pcap-dos.h pcap-enet.c pcap-int.h +pcap-libdlpi.c pcap-linux.c pcap-namedb.h pcap-nit.c diff --git a/INSTALL.txt b/INSTALL.txt index 9d5c4c00..20b02de7 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -1,4 +1,4 @@ -@(#) $Header: /tcpdump/master/libpcap/INSTALL.txt,v 1.24 2008-01-06 21:14:16 guy Exp $ (LBL) +@(#) $Header: /tcpdump/master/libpcap/INSTALL.txt,v 1.25 2008-03-13 18:13:57 guy Exp $ (LBL) To build libpcap, run "./configure" (a shell script). The configure script will determine your system attributes and generate an @@ -327,6 +327,8 @@ config.h.in - autoconf input config.sub - autoconf support configure - configure script (run this first) configure.in - configure script source +dlpisubs.c - DLPI-related functions for pcap-dlpi.c and pcap-libdlpi.c +dlpisubs.h - DLPI-related function declarations etherent.c - /etc/ethers support routines ethertype.h - Ethernet protocol types and names definitions fad-getad.c - pcap_findalldevs() for systems with getifaddrs() @@ -370,6 +372,7 @@ pcap-dos.c - MS-DOS capture support pcap-dos.h - headers for MS-DOS capture support pcap-enet.c - enet support pcap-int.h - internal libpcap definitions +pcap-libdlpi.c - Data Link Provider Interface support for systems with libdlpi pcap-linux.c - Linux packet socket support pcap-namedb.h - header for backwards compatibility pcap-nit.c - SunOS Network Interface Tap support @@ -1,4 +1,4 @@ -dnl @(#) $Header: /tcpdump/master/libpcap/aclocal.m4,v 1.88 2008-02-06 11:18:57 guy Exp $ (LBL) +dnl @(#) $Header: /tcpdump/master/libpcap/aclocal.m4,v 1.89 2008-03-13 18:13:57 guy Exp $ (LBL) dnl dnl Copyright (c) 1995, 1996, 1997, 1998 dnl The Regents of the University of California. All rights reserved. @@ -903,3 +903,30 @@ AC_DEFUN(AC_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]) + +dnl +dnl Checks to see if Solaris has the dl_passive_req_t struct defined +dnl in <sys/dlpi.h>. +dnl +dnl usage: +dnl +dnl AC_LBL_DL_PASSIVE_REQ_T +dnl +dnl results: +dnl +dnl HAVE_DLPI_PASSIVE (defined) +dnl +AC_DEFUN(AC_LBL_DL_PASSIVE_REQ_T, + [AC_MSG_CHECKING(if dl_passive_req_t struct exists) + AC_CACHE_VAL(ac_cv_lbl_has_dl_passive_req_t, + AC_TRY_COMPILE([ +# include <sys/types.h> +# include <sys/dlpi.h>], + [u_int i = sizeof(dl_passive_req_t)], + ac_cv_lbl_has_dl_passive_req_t=yes, + ac_cv_lbl_has_dl_passive_req_t=no)) + AC_MSG_RESULT($ac_cv_lbl_has_dl_passive_req_t) + if test $ac_cv_lbl_has_dl_passive_req_t = yes ; then + AC_DEFINE(HAVE_DLPI_PASSIVE,1,[if passive_req_t primitive + exists]) + fi]) diff --git a/config.h.in b/config.h.in index a52715ac..51ce259a 100644 --- a/config.h.in +++ b/config.h.in @@ -32,6 +32,9 @@ /* define if you have a /dev/dlpi */ #undef HAVE_DEV_DLPI +/* if passive_req_t primitive exists */ +#undef HAVE_DLPI_PASSIVE + /* Define to 1 if you have the `ether_hostton' function. */ #undef HAVE_ETHER_HOSTTON @@ -50,6 +53,9 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H +/* if libdlpi exists */ +#undef HAVE_LIBDLPI + /* Define to 1 if you have the <limits.h> header file. */ #undef HAVE_LIMITS_H @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 1.145 . +# From configure.in Revision: 1.146 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59. # @@ -5999,7 +5999,96 @@ elif test -r /usr/include/odmi.h ; then # V_PCAP=bpf elif test -r /usr/include/sys/dlpi.h ; then - V_PCAP=dlpi + # + # Checks to see if Solaris has the public libdlpi(3LIB) library. + # Note: The existence of /usr/include/libdlpi.h does not mean it is the + # public libdlpi(3LIB) version. Before libdlpi was made public, a + # private version also existed, which did not have the same APIs. + # Due to a gcc bug, the default search path for 32-bit libraries does + # not include /lib, we add it explicitly here. + # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. + # Also, due to the bug above applications that link to libpcap with + # libdlpi will have to add "-L/lib" option to "configure". + # + saved_ldflags=$LDFLAGS + LDFLAGS="$LIBS -L/lib" + echo "$as_me:$LINENO: checking for dlpi_walk in -ldlpi" >&5 +echo $ECHO_N "checking for dlpi_walk in -ldlpi... $ECHO_C" >&6 +if test "${ac_cv_lib_dlpi_dlpi_walk+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldlpi $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlpi_walk (); +int +main () +{ +dlpi_walk (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dlpi_dlpi_walk=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dlpi_dlpi_walk=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dlpi_dlpi_walk" >&5 +echo "${ECHO_T}$ac_cv_lib_dlpi_dlpi_walk" >&6 +if test $ac_cv_lib_dlpi_dlpi_walk = yes; then + LIBS="-ldlpi $LIBS" + V_PCAP=libdlpi + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBDLPI 1 +_ACEOF + +else + V_PCAP=dlpi +fi + + LDFLAGS=$saved_ldflags elif test -c /dev/bpf0 ; then # check again in case not readable V_PCAP=bpf elif test -c /dev/enet ; then # check again in case not readable @@ -6291,7 +6380,158 @@ else # case "$V_PCAP" in - dlpi) + dlpi|libdlpi) + + +for ac_header in sys/bufmod.h sys/dlpi_ext.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------ ## +## Report this to the AC_PACKAGE_NAME lists. ## +## ------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + # # This might be Solaris 8 or later, with # SIOCGLIFCONF, or it might be some other OS @@ -6361,6 +6601,10 @@ echo "${ECHO_T}$ac_cv_lbl_have_siocglifconf" >&6 else V_FINDALLDEVS=gifc fi + # + # Needed for common functions used by pcap-[dlpi,libdlpi].c + # + SSRC="dlpisubs.c" ;; *) @@ -6433,31 +6677,60 @@ echo "${ECHO_T}${enable_yydebug-no}" >&6 case "$V_PCAP" in dlpi) + echo "$as_me:$LINENO: checking for /dev/dlpi device" >&5 +echo $ECHO_N "checking for /dev/dlpi device... $ECHO_C" >&6 + if test -c /dev/dlpi ; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +cat >>confdefs.h <<\_ACEOF +#define HAVE_DEV_DLPI 1 +_ACEOF -for ac_header in sys/bufmod.h sys/dlpi_ext.h -do -as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + dir="/dev/dlpi" + echo "$as_me:$LINENO: checking for $dir directory" >&5 +echo $ECHO_N "checking for $dir directory... $ECHO_C" >&6 + if test -d $dir ; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<_ACEOF +#define PCAP_DEV_PREFIX "$dir" +_ACEOF + + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + fi + fi + # + # This check is for Solaris with DLPI support for passive modes. + # See dlpi(7P) for more details. + # + echo "$as_me:$LINENO: checking if dl_passive_req_t struct exists" >&5 +echo $ECHO_N "checking if dl_passive_req_t struct exists... $ECHO_C" >&6 + if test "${ac_cv_lbl_has_dl_passive_req_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 -fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else - # Is the header compilable? -echo "$as_me:$LINENO: checking $ac_header usability" >&5 -echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -#include <$ac_header> + +# include <sys/types.h> +# include <sys/dlpi.h> +int +main () +{ +u_int i = sizeof(dl_passive_req_t) + ; + return 0; +} _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 @@ -6481,138 +6754,25 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_header_compiler=yes + ac_cv_lbl_has_dl_passive_req_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_header_compiler=no +ac_cv_lbl_has_dl_passive_req_t=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 -echo "${ECHO_T}$ac_header_compiler" >&6 - -# Is the header present? -echo "$as_me:$LINENO: checking $ac_header presence" >&5 -echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 -cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include <$ac_header> -_ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - ac_cpp_err=$ac_cpp_err$ac_c_werror_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then - ac_header_preproc=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_header_preproc=no -fi -rm -f conftest.err conftest.$ac_ext -echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 -echo "${ECHO_T}$ac_header_preproc" >&6 - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in - yes:no: ) - { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 -echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} - ac_header_preproc=yes - ;; - no:yes:* ) - { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 -echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 -echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 -echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 -echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} - { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 -echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} - ( - cat <<\_ASBOX -## ------------------------------------------ ## -## Report this to the AC_PACKAGE_NAME lists. ## -## ------------------------------------------ ## -_ASBOX - ) | - sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac -echo "$as_me:$LINENO: checking for $ac_header" >&5 -echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 -if eval "test \"\${$as_ac_Header+set}\" = set"; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - eval "$as_ac_Header=\$ac_header_preproc" fi -echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 -echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 -fi -if test `eval echo '${'$as_ac_Header'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - echo "$as_me:$LINENO: checking for /dev/dlpi device" >&5 -echo $ECHO_N "checking for /dev/dlpi device... $ECHO_C" >&6 - if test -c /dev/dlpi ; then - echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6 + echo "$as_me:$LINENO: result: $ac_cv_lbl_has_dl_passive_req_t" >&5 +echo "${ECHO_T}$ac_cv_lbl_has_dl_passive_req_t" >&6 + if test $ac_cv_lbl_has_dl_passive_req_t = yes ; then cat >>confdefs.h <<\_ACEOF -#define HAVE_DEV_DLPI 1 -_ACEOF - - else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 - dir="/dev/dlpi" - echo "$as_me:$LINENO: checking for $dir directory" >&5 -echo $ECHO_N "checking for $dir directory... $ECHO_C" >&6 - if test -d $dir ; then - echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6 - -cat >>confdefs.h <<_ACEOF -#define PCAP_DEV_PREFIX "$dir" +#define HAVE_DLPI_PASSIVE 1 _ACEOF - else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 - fi - fi + fi ;; linux) diff --git a/configure.in b/configure.in index d734e8e4..2e142f1e 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.145 2008-02-04 21:09:27 guy Exp $ (LBL) +dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.146 2008-03-13 18:13:57 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.145 $) +AC_REVISION($Revision: 1.146 $) AC_PREREQ(2.50) AC_INIT(pcap.c) @@ -252,7 +252,25 @@ elif test -r /usr/include/odmi.h ; then # V_PCAP=bpf elif test -r /usr/include/sys/dlpi.h ; then - V_PCAP=dlpi + # + # Checks to see if Solaris has the public libdlpi(3LIB) library. + # Note: The existence of /usr/include/libdlpi.h does not mean it is the + # public libdlpi(3LIB) version. Before libdlpi was made public, a + # private version also existed, which did not have the same APIs. + # Due to a gcc bug, the default search path for 32-bit libraries does + # not include /lib, we add it explicitly here. + # [http://bugs.opensolaris.org/view_bug.do?bug_id=6619485]. + # Also, due to the bug above applications that link to libpcap with + # libdlpi will have to add "-L/lib" option to "configure". + # + saved_ldflags=$LDFLAGS + LDFLAGS="$LIBS -L/lib" + AC_CHECK_LIB(dlpi, dlpi_walk, + LIBS="-ldlpi $LIBS" + V_PCAP=libdlpi + AC_DEFINE(HAVE_LIBDLPI,1,[if libdlpi exists]), + V_PCAP=dlpi) + LDFLAGS=$saved_ldflags elif test -c /dev/bpf0 ; then # check again in case not readable V_PCAP=bpf elif test -c /dev/enet ; then # check again in case not readable @@ -310,7 +328,8 @@ else # case "$V_PCAP" in - dlpi) + dlpi|libdlpi) + AC_CHECK_HEADERS(sys/bufmod.h sys/dlpi_ext.h) # # This might be Solaris 8 or later, with # SIOCGLIFCONF, or it might be some other OS @@ -334,6 +353,10 @@ else else V_FINDALLDEVS=gifc fi + # + # Needed for common functions used by pcap-[dlpi,libdlpi].c + # + SSRC="dlpisubs.c" ;; *) @@ -373,7 +396,6 @@ AC_MSG_RESULT(${enable_yydebug-no}) case "$V_PCAP" in dlpi) - AC_CHECK_HEADERS(sys/bufmod.h sys/dlpi_ext.h) AC_MSG_CHECKING(for /dev/dlpi device) if test -c /dev/dlpi ; then AC_MSG_RESULT(yes) @@ -389,6 +411,11 @@ dlpi) AC_MSG_RESULT(no) fi fi + # + # This check is for Solaris with DLPI support for passive modes. + # See dlpi(7P) for more details. + # + AC_LBL_DL_PASSIVE_REQ_T ;; linux) diff --git a/dlpisubs.c b/dlpisubs.c new file mode 100644 index 00000000..beeee3e8 --- /dev/null +++ b/dlpisubs.c @@ -0,0 +1,349 @@ +/* + * This code is derived from code formerly in pcap-dlpi.c, originally + * contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), University College + * London, and subsequently modified by Guy Harris (guy@alum.mit.edu), + * Mark Pizzolato <List-tcpdump-workers@subscriptions.pizzolato.net>, + * Mark C. Brown (mbrown@hp.com), and Sagun Shakya <Sagun.Shakya@Sun.COM>. + */ + +/* + * This file contains dlpi/libdlpi related common functions used + * by pcap-[dlpi,libdlpi].c. + */ +#ifndef lint +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/libpcap/dlpisubs.c,v 1.1 2008-03-13 18:13:57 guy Exp $ (LBL)"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_SYS_BUFMOD_H + /* + * Size of a bufmod chunk to pass upstream; that appears to be the + * biggest value to which you can set it, and setting it to that value + * (which is bigger than what appears to be the Solaris default of 8192) + * reduces the number of packet drops. + */ +#define CHUNKSIZE 65536 + + /* + * Size of the buffer to allocate for packet data we read; it must be + * large enough to hold a chunk. + */ +#define PKTBUFSIZE CHUNKSIZE + +#else /* HAVE_SYS_BUFMOD_H */ + + /* + * Size of the buffer to allocate for packet data we read; this is + * what the value used to be - there's no particular reason why it + * should be tied to MAXDLBUF, but we'll leave it as this for now. + */ +#define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) + +#endif + +#include <sys/types.h> +#include <sys/time.h> +#ifdef HAVE_SYS_BUFMOD_H +#include <sys/bufmod.h> +#endif +#include <sys/dlpi.h> +#include <sys/stream.h> + +#include <errno.h> +#include <memory.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stropts.h> +#include <unistd.h> + +#include "pcap-int.h" +#include "dlpisubs.h" + +static void pcap_stream_err(const char *, int, char *); + +/* + * Get the packet statistics. + */ +int +pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) +{ + + /* + * "ps_recv" counts packets handed to the filter, not packets + * that passed the filter. As filtering is done in userland, + * this would not include packets dropped because we ran out + * of buffer space; in order to make this more like other + * platforms (Linux 2.4 and later, BSDs with BPF), where the + * "packets received" count includes packets received but dropped + * due to running out of buffer space, and to keep from confusing + * applications that, for example, compute packet drop percentages, + * we also make it count packets dropped by "bufmod" (otherwise we + * might run the risk of the packet drop count being bigger than + * the received-packet count). + * + * "ps_drop" counts packets dropped by "bufmod" because of + * flow control requirements or resource exhaustion; it doesn't + * count packets dropped by the interface driver, or packets + * dropped upstream. As filtering is done in userland, it counts + * packets regardless of whether they would've passed the filter. + * + * These statistics don't include packets not yet read from + * the kernel by libpcap, but they may include packets not + * yet read from libpcap by the application. + */ + *ps = p->md.stat; + + /* + * Add in the drop count, as per the above comment. + */ + ps->ps_recv += ps->ps_drop; + return (0); +} + +/* + * Loop through the packets and call the callback for each packet. + * Return the number of packets read. + */ +int +pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, + int count, u_char *bufp, int len) +{ + int n, caplen, origlen; + u_char *ep, *pk; + struct pcap_pkthdr pkthdr; +#ifdef HAVE_SYS_BUFMOD_H + struct sb_hdr *sbp; +#ifdef LBL_ALIGN + struct sb_hdr sbhdr; +#endif +#endif + + /* Loop through packets */ + ep = bufp + len; + n = 0; + +#ifdef HAVE_SYS_BUFMOD_H + while (bufp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bufp; + p->cc = ep - bufp; + return (n); + } + } +#ifdef LBL_ALIGN + if ((long)bufp & 3) { + sbp = &sbhdr; + memcpy(sbp, bufp, sizeof(*sbp)); + } else +#endif + sbp = (struct sb_hdr *)bufp; + p->md.stat.ps_drop = sbp->sbh_drops; + pk = bufp + sizeof(*sbp); + bufp += sbp->sbh_totlen; + origlen = sbp->sbh_origlen; + caplen = sbp->sbh_msglen; +#else + origlen = len; + caplen = min(p->snapshot, len); + pk = bufp; + bufp += caplen; +#endif + ++p->md.stat.ps_recv; + if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) { +#ifdef HAVE_SYS_BUFMOD_H + pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; + pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; +#else + (void) gettimeofday(&pkthdr.ts, NULL); +#endif + pkthdr.len = origlen; + pkthdr.caplen = caplen; + /* Insure caplen does not exceed snapshot */ + if (pkthdr.caplen > p->snapshot) + pkthdr.caplen = p->snapshot; + (*callback)(user, &pkthdr, pk); + if (++n >= count && count >= 0) { + p->cc = ep - bufp; + p->bp = bufp; + return (n); + } + } +#ifdef HAVE_SYS_BUFMOD_H + } +#endif + p->cc = 0; + return (n); +} + +/* + * Process the mac type. Returns -1 if no matching mac type found, otherwise 0. + */ +int +pcap_process_mactype(pcap_t *p, u_int mactype, char *ebuf) +{ + int retv = 0; + + switch (mactype) { + + case DL_CSMACD: + case DL_ETHER: + p->linktype = DLT_EN10MB; + p->offset = 2; + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2); + /* + * If that fails, just leave the list empty. + */ + if (p->dlt_list != NULL) { + p->dlt_list[0] = DLT_EN10MB; + p->dlt_list[1] = DLT_DOCSIS; + p->dlt_count = 2; + } + break; + + case DL_FDDI: + p->linktype = DLT_FDDI; + p->offset = 3; + break; + + case DL_TPR: + /* XXX - what about DL_TPB? Is that Token Bus? */ + p->linktype = DLT_IEEE802; + p->offset = 2; + break; + +#ifdef HAVE_SOLARIS + case DL_IPATM: + p->linktype = DLT_SUNATM; + p->offset = 0; /* works for LANE and LLC encapsulation */ + break; +#endif + + default: + snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mactype %u", + mactype); + retv = -1; + } + + return (retv); +} + +#ifdef HAVE_SYS_BUFMOD_H +/* + * Push and configure the buffer module. Returns -1 for error, otherwise 0. + */ +int +pcap_conf_bufmod(pcap_t *p, int snaplen, int timeout, char *ebuf) +{ + int retv = 0; + + bpf_u_int32 ss, chunksize; + + /* Non-standard call to get the data nicely buffered. */ + if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { + pcap_stream_err("I_PUSH bufmod", errno, ebuf); + retv = -1; + } + + ss = snaplen; + if (ss > 0 && + strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { + pcap_stream_err("SBIOCSSNAP", errno, ebuf); + retv = -1; + } + + /* Set up the bufmod timeout. */ + if (timeout != 0) { + struct timeval to; + + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout * 1000) % 1000000; + if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { + pcap_stream_err("SBIOCSTIME", errno, ebuf); + retv = -1; + } + } + + /* Set the chunk length. */ + chunksize = CHUNKSIZE; + if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) + != 0) { + pcap_stream_err("SBIOCSCHUNKP", errno, ebuf); + retv = -1; + } + + return (retv); +} +#endif /* HAVE_SYS_BUFMOD_H */ + +/* + * Allocate data buffer. Returns -1 if memory allocation fails, else 0. + */ +int +pcap_alloc_databuf(pcap_t *p, char *ebuf) +{ + p->bufsize = PKTBUFSIZE; + p->buffer = (u_char *)malloc(p->bufsize + p->offset); + if (p->buffer == NULL) { + strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); + return (-1); + } + + return (0); +} + +/* + * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise + * length of returned data on success. + */ +int +strioctl(int fd, int cmd, int len, char *dp) +{ + struct strioctl str; + int retv; + + str.ic_cmd = cmd; + str.ic_timout = -1; + str.ic_len = len; + str.ic_dp = dp; + if ((retv = ioctl(fd, I_STR, &str)) < 0) + return (retv); + + return (str.ic_len); +} + +/* + * Write stream error message to errbuf. + */ +static void +pcap_stream_err(const char *func, int err, char *errbuf) +{ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", func, pcap_strerror(err)); +} diff --git a/dlpisubs.h b/dlpisubs.h new file mode 100644 index 00000000..62b9d73d --- /dev/null +++ b/dlpisubs.h @@ -0,0 +1,28 @@ +/* + * @(#) $Header: /tcpdump/master/libpcap/dlpisubs.h,v 1.1 2008-03-13 18:13:57 guy Exp $ + */ + +#ifndef dlpisubs_h +#define dlpisubs_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Functions used by dlpisubs.c. + */ +int pcap_stats_dlpi(pcap_t *, struct pcap_stat *); +int pcap_process_pkts(pcap_t *, pcap_handler, u_char *, int, u_char *, int); +int pcap_process_mactype(pcap_t *, u_int, char *); +#ifdef HAVE_SYS_BUFMOD_H +int pcap_conf_bufmod(pcap_t *, int, int, char *); +#endif +int pcap_alloc_databuf(pcap_t *, char *); +int strioctl(int, int, int, char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pcap-dlpi.c b/pcap-dlpi.c index ebc20df5..21b0097c 100644 --- a/pcap-dlpi.c +++ b/pcap-dlpi.c @@ -22,7 +22,7 @@ * University College London, and subsequently modified by * Guy Harris (guy@alum.mit.edu), Mark Pizzolato * <List-tcpdump-workers@subscriptions.pizzolato.net>, - * and Mark C. Brown (mbrown@hp.com). + * Mark C. Brown (mbrown@hp.com), and Sagun Shakya <Sagun.Shakya@Sun.COM>. */ /* @@ -70,7 +70,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.119 2008-02-02 20:58:18 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.120 2008-03-13 18:13:57 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -121,6 +121,7 @@ static const char rcsid[] _U_ = #endif #include "pcap-int.h" +#include "dlpisubs.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" @@ -136,33 +137,6 @@ static const char rcsid[] _U_ = #define MAXDLBUF 8192 -#ifdef HAVE_SYS_BUFMOD_H - -/* - * Size of a bufmod chunk to pass upstream; that appears to be the biggest - * value to which you can set it, and setting it to that value (which - * is bigger than what appears to be the Solaris default of 8192) - * reduces the number of packet drops. - */ -#define CHUNKSIZE 65536 - -/* - * Size of the buffer to allocate for packet data we read; it must be - * large enough to hold a chunk. - */ -#define PKTBUFSIZE CHUNKSIZE - -#else /* HAVE_SYS_BUFMOD_H */ - -/* - * Size of the buffer to allocate for packet data we read; this is - * what the value used to be - there's no particular reason why it - * should be tied to MAXDLBUF, but we'll leave it as this for now. - */ -#define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) - -#endif - /* Forwards */ static char *split_dname(char *, int *, char *); static int dl_doattach(int, int, char *); @@ -176,6 +150,11 @@ static int dlpromisconreq(int, bpf_u_int32, char *); static int dlokack(int, const char *, char *, char *); static int dlinforeq(int, char *); static int dlinfoack(int, char *, char *); + +#ifdef HAVE_DLPI_PASSIVE +static void dlpassive(int, char *); +#endif + #ifdef DL_HP_RAWDLS static int dlrawdatareq(int, const u_char *, int); #endif @@ -186,9 +165,6 @@ static char *dlprim(bpf_u_int32); static char *get_release(bpf_u_int32 *, bpf_u_int32 *, bpf_u_int32 *); #endif static int send_request(int, char *, int, char *, char *); -#ifdef HAVE_SYS_BUFMOD_H -static int strioctl(int, int, int, char *); -#endif #ifdef HAVE_HPUX9 static int dlpi_kread(int, off_t, void *, u_int, char *); #endif @@ -196,42 +172,6 @@ static int dlpi_kread(int, off_t, void *, u_int, char *); static int get_dlpi_ppa(int, const char *, int, char *); #endif -static int -pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) -{ - - /* - * "ps_recv" counts packets handed to the filter, not packets - * that passed the filter. As filtering is done in userland, - * this would not include packets dropped because we ran out - * of buffer space; in order to make this more like other - * platforms (Linux 2.4 and later, BSDs with BPF), where the - * "packets received" count includes packets received but dropped - * due to running out of buffer space, and to keep from confusing - * applications that, for example, compute packet drop percentages, - * we also make it count packets dropped by "bufmod" (otherwise we - * might run the risk of the packet drop count being bigger than - * the received-packet count). - * - * "ps_drop" counts packets dropped by "bufmod" because of - * flow control requirements or resource exhaustion; it doesn't - * count packets dropped by the interface driver, or packets - * dropped upstream. As filtering is done in userland, it counts - * packets regardless of whether they would've passed the filter. - * - * These statistics don't include packets not yet read from - * the kernel by libpcap, but they may include packets not - * yet read from libpcap by the application. - */ - *ps = p->md.stat; - - /* - * Add in the drop count, as per the above comment. - */ - ps->ps_recv += ps->ps_drop; - return (0); -} - /* XXX Needed by HP-UX (at least) */ static bpf_u_int32 ctlbuf[MAXDLBUF]; static struct strbuf ctl = { @@ -243,17 +183,10 @@ static struct strbuf ctl = { static int pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - register int cc, n, caplen, origlen; - register u_char *bp, *ep, *pk; -#ifdef HAVE_SYS_BUFMOD_H - register struct sb_hdr *sbp; -#ifdef LBL_ALIGN - struct sb_hdr sbhdr; -#endif -#endif + int cc; + u_char *bp; int flags; struct strbuf data; - struct pcap_pkthdr pkthdr; flags = 0; cc = p->cc; @@ -301,73 +234,7 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } else bp = p->bp; - /* Loop through packets */ - ep = bp + cc; - n = 0; -#ifdef HAVE_SYS_BUFMOD_H - while (bp < ep) { - /* - * Has "pcap_breakloop()" been called? - * If so, return immediately - if we haven't read any - * packets, clear the flag and return -2 to indicate - * that we were told to break out of the loop, otherwise - * leave the flag set, so that the *next* call will break - * out of the loop without having read any packets, and - * return the number of packets we've processed so far. - */ - if (p->break_loop) { - if (n == 0) { - p->break_loop = 0; - return (-2); - } else { - p->bp = bp; - p->cc = ep - bp; - return (n); - } - } -#ifdef LBL_ALIGN - if ((long)bp & 3) { - sbp = &sbhdr; - memcpy(sbp, bp, sizeof(*sbp)); - } else -#endif - sbp = (struct sb_hdr *)bp; - p->md.stat.ps_drop = sbp->sbh_drops; - pk = bp + sizeof(*sbp); - bp += sbp->sbh_totlen; - origlen = sbp->sbh_origlen; - caplen = sbp->sbh_msglen; -#else - origlen = cc; - caplen = min(p->snapshot, cc); - pk = bp; - bp += caplen; -#endif - ++p->md.stat.ps_recv; - if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) { -#ifdef HAVE_SYS_BUFMOD_H - pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; - pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; -#else - (void)gettimeofday(&pkthdr.ts, NULL); -#endif - pkthdr.len = origlen; - pkthdr.caplen = caplen; - /* Insure caplen does not exceed snapshot */ - if (pkthdr.caplen > p->snapshot) - pkthdr.caplen = p->snapshot; - (*callback)(user, &pkthdr, pk); - if (++n >= cnt && cnt > 0) { - p->cc = ep - bp; - p->bp = bp; - return (n); - } - } -#ifdef HAVE_SYS_BUFMOD_H - } -#endif - p->cc = 0; - return (n); + return (pcap_process_pkts(p, callback, user, cnt, bp, cc)); } static int @@ -466,7 +333,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, #endif register dl_info_ack_t *infop; #ifdef HAVE_SYS_BUFMOD_H - bpf_u_int32 ss, chunksize; + bpf_u_int32 ss; #ifdef HAVE_SOLARIS register char *release; bpf_u_int32 osmajor, osminor, osmicro; @@ -637,6 +504,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, #endif } +#ifdef HAVE_DLPI_PASSIVE + /* + * Enable Passive mode to be able to capture on aggregated link. + * Not supported in all Solaris versions. + */ + dlpassive(p->fd, ebuf); +#endif /* ** Bind (defer if using HP-UX 9 or HP-UX 10.20 or later, totally ** skip if using SINIX) @@ -783,58 +657,8 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, goto bad; infop = &((union DL_primitives *)buf)->info_ack; - switch (infop->dl_mac_type) { - - case DL_CSMACD: - case DL_ETHER: - p->linktype = DLT_EN10MB; - p->offset = 2; - /* - * This is (presumably) a real Ethernet capture; give it a - * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so - * that an application can let you choose it, in case you're - * capturing DOCSIS traffic that a Cisco Cable Modem - * Termination System is putting out onto an Ethernet (it - * doesn't put an Ethernet header onto the wire, it puts raw - * DOCSIS frames out on the wire inside the low-level - * Ethernet framing). - */ - p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); - /* - * If that fails, just leave the list empty. - */ - if (p->dlt_list != NULL) { - p->dlt_list[0] = DLT_EN10MB; - p->dlt_list[1] = DLT_DOCSIS; - p->dlt_count = 2; - } - break; - - case DL_FDDI: - p->linktype = DLT_FDDI; - p->offset = 3; - break; - - case DL_TPR: - /* - * XXX - what about DL_TPB? Is that Token Bus? - */ - p->linktype = DLT_IEEE802; - p->offset = 2; - break; - -#ifdef HAVE_SOLARIS - case DL_IPATM: - p->linktype = DLT_SUNATM; - p->offset = 0; /* works for LANE and LLC encapsulation */ - break; -#endif - - default: - snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mac type %lu", - (unsigned long)infop->dl_mac_type); + if (pcap_process_mactype(p, infop->dl_mac_type, ebuf) != 0) goto bad; - } #ifdef DLIOCRAW /* @@ -848,19 +672,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, } #endif -#ifdef HAVE_SYS_BUFMOD_H - /* - ** Another non standard call to get the data nicely buffered - */ - if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_PUSH bufmod: %s", - pcap_strerror(errno)); - goto bad; - } + ss = snaplen; /* - ** Now that the bufmod is pushed lets configure it. - ** ** There is a bug in bufmod(7). When dealing with messages of ** less than snaplen size it strips data from the beginning not ** the end. @@ -868,7 +682,6 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, ** This bug is fixed in 5.3.2. Also, there is a patch available. ** Ask for bugid 1149065. */ - ss = snaplen; #ifdef HAVE_SOLARIS release = get_release(&osmajor, &osminor, &osmicro); if (osmajor == 5 && (osminor <= 2 || (osminor == 3 && osmicro < 2)) && @@ -879,38 +692,11 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, ss = 0; } #endif - if (ss > 0 && - strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSSNAP: %s", - pcap_strerror(errno)); - goto bad; - } - /* - ** Set up the bufmod timeout - */ - if (to_ms != 0) { - struct timeval to; - - to.tv_sec = to_ms / 1000; - to.tv_usec = (to_ms * 1000) % 1000000; - if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSTIME: %s", - pcap_strerror(errno)); - goto bad; - } - } - - /* - ** Set the chunk length. - */ - chunksize = CHUNKSIZE; - if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) - != 0) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "SBIOCSCHUNKP: %s", - pcap_strerror(errno)); +#ifdef HAVE_SYS_BUFMOD_H + /* Push and configure bufmod. */ + if (pcap_conf_bufmod(p, ss, to_ms, ebuf) != 0) goto bad; - } #endif /* @@ -922,13 +708,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, goto bad; } - /* Allocate data buffer */ - p->bufsize = PKTBUFSIZE; - p->buffer = (u_char *)malloc(p->bufsize + p->offset); - if (p->buffer == NULL) { - strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); + /* Allocate data buffer. */ + if (pcap_alloc_databuf(p, ebuf) != 0) goto bad; - } /* * "p->fd" is an FD for a STREAMS device, so "select()" and @@ -1484,6 +1266,24 @@ dlinfoack(int fd, char *bufp, char *ebuf) return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf, NULL)); } +#ifdef HAVE_DLPI_PASSIVE +/* + * Enable DLPI passive mode. We do not care if this request fails, as this + * indicates the underlying DLPI device does not support link aggregation. + */ +static void +dlpassive(int fd, char *ebuf) +{ + dl_passive_req_t req; + bpf_u_int32 buf[MAXDLBUF]; + + req.dl_primitive = DL_PASSIVE_REQ; + + if (send_request(fd, (char *)&req, sizeof(req), "dlpassive", ebuf) == 0) + (void) dlokack(fd, "dlpassive", (char *)buf, ebuf); +} +#endif + #ifdef DL_HP_RAWDLS /* * There's an ack *if* there's an error. @@ -1520,26 +1320,6 @@ dlrawdatareq(int fd, const u_char *datap, int datalen) } #endif /* DL_HP_RAWDLS */ -#ifdef HAVE_SYS_BUFMOD_H -static int -strioctl(int fd, int cmd, int len, char *dp) -{ - struct strioctl str; - int rc; - - str.ic_cmd = cmd; - str.ic_timout = -1; - str.ic_len = len; - str.ic_dp = dp; - rc = ioctl(fd, I_STR, &str); - - if (rc < 0) - return (rc); - else - return (str.ic_len); -} -#endif - #if defined(HAVE_SOLARIS) && defined(HAVE_SYS_BUFMOD_H) static char * get_release(bpf_u_int32 *majorp, bpf_u_int32 *minorp, bpf_u_int32 *microp) @@ -30,11 +30,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.87 2008-01-06 20:23:17 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.88 2008-03-13 18:13:57 guy Exp $ (LBL) */ #ifndef pcap_int_h -#define pcap_int_h +#define pcap_int_h #include <pcap/pcap.h> @@ -42,6 +42,10 @@ extern "C" { #endif +#ifdef HAVE_LIBDLPI +#include <libdlpi.h> +#endif + #ifdef WIN32 #include <Packet32.h> #endif /* WIN32 */ @@ -167,6 +171,10 @@ struct pcap { int selectable_fd; int send_fd; #endif /* WIN32 */ + +#ifdef HAVE_LIBDLPI + dlpi_handle_t dlpi_hd; +#endif int snapshot; int linktype; /* Network linktype */ int linktype_ext; /* Extended information stored in the linktype field of a file */ diff --git a/pcap-libdlpi.c b/pcap-libdlpi.c new file mode 100644 index 00000000..274dfc1a --- /dev/null +++ b/pcap-libdlpi.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * 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. + * + * This code contributed by Sagun Shakya (sagun.shakya@sun.com) + */ +/* + * Packet capture routines for DLPI using libdlpi under SunOS 5.11. + */ + +#ifndef lint +static const char rcsid[] _U_ = + "@(#) $Header: /tcpdump/master/libpcap/pcap-libdlpi.c,v 1.1 2008-03-13 18:13:57 guy Exp $ (LBL)"; +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/bufmod.h> +#include <sys/stream.h> +#include <libdlpi.h> +#include <errno.h> +#include <memory.h> +#include <stropts.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pcap-int.h" +#include "dlpisubs.h" + +/* Forwards. */ +static int pcap_read_libdlpi(pcap_t *, int, pcap_handler, u_char *); +static int pcap_inject_libdlpi(pcap_t *, const void *, size_t); +static void pcap_close_libdlpi(pcap_t *); +static void pcap_libdlpi_err(const char *, const char *, int, char *); + +/* + * list_interfaces() will list all the network links that are + * available on a system. + */ +static boolean_t list_interfaces(const char *, void *); + +typedef struct linknamelist { + char linkname[DLPI_LINKNAME_MAX]; + struct linknamelist *lnl_next; +} linknamelist_t; + +typedef struct linkwalk { + linknamelist_t *lw_list; + int lw_err; +} linkwalk_t; + +/* + * The caller of this function should free the memory allocated + * for each linknamelist_t "entry" allocated. + */ +static boolean_t +list_interfaces(const char *linkname, void *arg) +{ + linkwalk_t *lwp = arg; + linknamelist_t *entry; + + if ((entry = calloc(1, sizeof(linknamelist_t))) == NULL) { + lwp->lw_err = ENOMEM; + return (B_TRUE); + } + (void) strlcpy(entry->linkname, linkname, DLPI_LINKNAME_MAX); + + if (lwp->lw_list == NULL) { + lwp->lw_list = entry; + } else { + entry->lnl_next = lwp->lw_list; + lwp->lw_list = entry; + } + + return (B_FALSE); +} + +pcap_t * +pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, + char *ebuf) +{ + int retv; + pcap_t *p; + dlpi_handle_t dh; + dlpi_info_t dlinfo; + bpf_u_int32 ss, chunksize; + + if ((p = (pcap_t *)malloc(sizeof(*p))) == NULL) { + strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); + return (NULL); + } + memset(p, 0, sizeof(*p)); + p->fd = -1; /* indicate that it hasn't been opened yet */ + p->dlpi_hd; + p->send_fd = -1; + + /* + * Enable Solaris raw and passive DLPI extensions; + * dlpi_open() will not fail if the underlying link does not support + * passive mode. See dlpi(7P) for details. + */ + retv = dlpi_open(device, &dh, DLPI_RAW|DLPI_PASSIVE); + if (retv != DLPI_SUCCESS) { + pcap_libdlpi_err(device, "dlpi_open", retv, ebuf); + goto bad; + } + p->dlpi_hd = dh; + + p->snapshot = snaplen; + + /* Bind with DLPI_ANY_SAP. */ + if ((retv = dlpi_bind(p->dlpi_hd, DLPI_ANY_SAP, 0)) != DLPI_SUCCESS) { + pcap_libdlpi_err(device, "dlpi_bind", retv, ebuf); + goto bad; + } + + /* Enable promiscuous mode. */ + if (promisc) { + retv = dlpi_promiscon(p->dlpi_hd, DL_PROMISC_PHYS); + if (retv != DLPI_SUCCESS) { + pcap_libdlpi_err(device, "dlpi_promisc(PHYSICAL)", + retv, ebuf); + goto bad; + } + } else { + /* Try to enable multicast. */ + retv = dlpi_promiscon(p->dlpi_hd, DL_PROMISC_MULTI); + if (retv != DLPI_SUCCESS) { + pcap_libdlpi_err(device, "dlpi_promisc(MULTI)", + retv, ebuf); + goto bad; + } + } + + /* Try to enable SAP promiscuity. */ + if ((retv = dlpi_promiscon(p->dlpi_hd, DL_PROMISC_SAP)) != DLPI_SUCCESS) { + if (!promisc) { + pcap_libdlpi_err(device, "dlpi_promisc(SAP)", + retv, ebuf); + goto bad; + } + + /* Not fatal, since the DL_PROMISC_PHYS mode worked. */ + fprintf(stderr, "WARNING: dlpi_promisc(SAP) failed on" + " %s:(%s)\n", device, dlpi_strerror(retv)); + } + + /* Determine link type. */ + if ((retv = dlpi_info(p->dlpi_hd, &dlinfo, 0)) != DLPI_SUCCESS) { + pcap_libdlpi_err(device, "dlpi_info", retv, ebuf); + goto bad; + } + + if (pcap_process_mactype(p, dlinfo.di_mactype, ebuf) != 0) + goto bad; + + p->fd = dlpi_fd(p->dlpi_hd); + + /* Push and configure bufmod. */ + if (pcap_conf_bufmod(p, ss, to_ms, ebuf) != 0) + goto bad; + + /* + * Flush the read side. + */ + if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s", + pcap_strerror(errno)); + goto bad; + } + + /* Allocate data buffer. */ + if (pcap_alloc_databuf(p, ebuf) != 0) + goto bad; + + /* + * "p->fd" is a FD for a STREAMS device, so "select()" and + * "poll()" should work on it. + */ + p->selectable_fd = p->fd; + + p->read_op = pcap_read_libdlpi; + p->inject_op = pcap_inject_libdlpi; + p->setfilter_op = install_bpf_program; /* No kernel filtering */ + p->setdirection_op = NULL; /* Not implemented */ + p->set_datalink_op = NULL; /* Can't change data link type */ + p->getnonblock_op = pcap_getnonblock_fd; + p->setnonblock_op = pcap_setnonblock_fd; + p->stats_op = pcap_stats_dlpi; + p->close_op = pcap_close_libdlpi; + + return (p); +bad: + /* Get rid of any link-layer type list we allocated. */ + if (p->dlt_list != NULL) + free(p->dlt_list); + pcap_close_libdlpi(p); + free(p); + return (NULL); +} + +/* + * In Solaris, the "standard" mechanism" i.e SIOCGLIFCONF will only find + * network links that are plumbed and are up. dlpi_walk(3DLPI) will find + * additional network links present in the system. + */ +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + int retv = 0; + + linknamelist_t *entry, *next; + linkwalk_t lw = {NULL, 0}; + int save_errno; + + /* dlpi_walk() for loopback will be added here. */ + + dlpi_walk(list_interfaces, &lw, 0); + + if (lw.lw_err != 0) { + snprintf(errbuf, PCAP_ERRBUF_SIZE, + "dlpi_walk: %s", pcap_strerror(lw.lw_err)); + retv = -1; + goto done; + } + + /* Add linkname if it does not exist on the list. */ + for (entry = lw.lw_list; entry != NULL; entry = entry->lnl_next) { + if (pcap_add_if(alldevsp, entry->linkname, 0, NULL, errbuf) < 0) + retv = -1; + } +done: + save_errno = errno; + for (entry = lw.lw_list; entry != NULL; entry = next) { + next = entry->lnl_next; + free(entry); + } + errno = save_errno; + + return (retv); +} + +/* + * Read data received on DLPI handle. Returns -2 if told to terminate, else + * returns the number of packets read. + */ +static int +pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user) +{ + int len; + u_char *bufp; + size_t msglen; + int retv; + + len = p->cc; + if (len != 0) { + bufp = p->bp; + goto process_pkts; + } + do { + /* Has "pcap_breakloop()" been called? */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it has, + * and return -2 to indicate that we were told to + * break out of the loop. + */ + p->break_loop = 0; + return (-2); + } + + msglen = p->bufsize; + bufp = p->buffer + p->offset; + + retv = dlpi_recv(p->dlpi_hd, NULL, NULL, bufp, + &msglen, -1, NULL); + if (retv != DLPI_SUCCESS) { + /* + * This is most likely a call to terminate out of the + * loop. So, do not return an error message, instead + * check if "pcap_breakloop()" has been called above. + */ + if (retv == DL_SYSERR && errno == EINTR) { + len = 0; + continue; + } + pcap_libdlpi_err(dlpi_linkname(p->dlpi_hd), + "dlpi_recv", retv, p->errbuf); + return (-1); + } + len = msglen; + } while (len == 0); + +process_pkts: + return (pcap_process_pkts(p, callback, user, count, bufp, len)); +} + +static int +pcap_inject_libdlpi(pcap_t *p, const void *buf, size_t size) +{ + int retv; + + retv = dlpi_send(p->dlpi_hd, NULL, 0, buf, size, NULL); + if (retv != DLPI_SUCCESS) { + pcap_libdlpi_err(dlpi_linkname(p->dlpi_hd), "dlpi_send", retv, + p->errbuf); + return (-1); + } + /* + * dlpi_send(3DLPI) does not provide a way to return the number of + * bytes sent on the wire. Based on the fact that DLPI_SUCCESS was + * returned we are assuming 'size' bytes were sent. + */ + return (size); +} + +/* + * Close dlpi handle and deallocate data buffer. + */ +static void +pcap_close_libdlpi(pcap_t *p) +{ + dlpi_close(p->dlpi_hd); + free(p->buffer); +} + +/* + * Write error message to buffer. + */ +static void +pcap_libdlpi_err(const char *linkname, const char *func, int err, char *errbuf) +{ + snprintf(errbuf, PCAP_ERRBUF_SIZE, "libpcap: %s failed on %s: %s", + func, linkname, dlpi_strerror(err)); +} |