]> The Tcpdump Group git mirrors - libpcap/commitdiff
From Paolo Abeni and me: split pcap_open_live() into a "get a pcap_t
authorguy <guy>
Fri, 4 Apr 2008 19:39:05 +0000 (19:39 +0000)
committerguy <guy>
Fri, 4 Apr 2008 19:39:05 +0000 (19:39 +0000)
handle" routine, an 'activate a pcap_t handle" routine, and some "set
the properties of the pcap_t handle" routines, so that, for example, the
buffer size can be set on a BPF device before the device is bound to an
interface.

Add additional routines to set monitor mode, and make at least an
initial attempt at supporting that on Linux, *BSD, and Mac OS X 10.4 and
10.5.

Have a "timeout" member of the pcap_md structure on all platforms, use
that on Windows instead of the "timeout" member of the pcap_t structure,
and get rid of the "timeout" member of that structure.

29 files changed:
config.h.in
configure
configure.in
dlpisubs.c
dlpisubs.h
pcap-bpf.c
pcap-bt-linux.c
pcap-bt-linux.h [new file with mode: 0644]
pcap-dag.c
pcap-dag.h
pcap-dlpi.c
pcap-dos.c
pcap-int.h
pcap-libdlpi.c
pcap-linux.c
pcap-nit.c
pcap-null.c
pcap-pf.c
pcap-septel.c [new file with mode: 0644]
pcap-septel.h [new file with mode: 0644]
pcap-sita.c
pcap-snit.c
pcap-snoop.c
pcap-usb-linux.c
pcap-usb-linux.h [new file with mode: 0644]
pcap-win32.c
pcap.c
pcap/pcap.h
savefile.c

index 87a5a7a9e490f802adb23986cb9e7e50966a13ae..3544f15aac58d04aaaf69ae9bb8ff09ea0b20c13 100644 (file)
@@ -59,6 +59,9 @@
 /* Define to 1 if you have the <limits.h> header file. */
 #undef HAVE_LIMITS_H
 
+/* Define to 1 if you have the <linux/wireless.h> header file. */
+#undef HAVE_LINUX_WIRELESS_H
+
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
@@ -68,6 +71,9 @@
 /* Define to 1 if you have the <netinet/if_ether.h> header file. */
 #undef HAVE_NETINET_IF_ETHER_H
 
+/* Define to 1 if you have the <net/if_media.h> header file. */
+#undef HAVE_NET_IF_MEDIA_H
+
 /* Define to 1 if you have the <net/pfvar.h> header file. */
 #undef HAVE_NET_PFVAR_H
 
index 41bdfa3501be0b9e785efa738ca336f1d2e9de27..63ab4ea7a4a8d8779c3a6fa132514d85a6ad2f75 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 1.138.2.10 .
+# From configure.in Revision: 1.138.2.11 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.59.
 #
@@ -6866,6 +6866,220 @@ echo "$as_me: error: cannot determine linux version when cross-compiling" >&2;}
 echo "$as_me: error: version 2 or higher required; see the INSTALL doc for more info" >&2;}
    { (exit 1); exit 1; }; }
        fi
+
+for ac_header in linux/wireless.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+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
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <linux/types.h>
+
+
+#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
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+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
+
+       for ac_header in
+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
+
        echo "$as_me:$LINENO: checking if if_packet.h has tpacket_stats defined" >&5
 echo $ECHO_N "checking if if_packet.h has tpacket_stats defined... $ECHO_C" >&6
    if test "${ac_cv_lbl_tpacket_stats+set}" = set; then
@@ -6930,6 +7144,162 @@ _ACEOF
    fi
        ;;
 
+bpf)
+       #
+       # Check whether we have the *BSD-style ioctls.
+       #
+
+for ac_header in net/if_media.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
+
+       ;;
+
 dag)
        V_DEFS="$V_DEFS -DDAG_ONLY"
        ;;
index 938a0fd3795a14a0025dea784090aa9e9583b0a4..8f95a207374745baa657fc969ccfebe84982e14a 100644 (file)
@@ -1,4 +1,4 @@
-dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.138.2.10 2008-03-14 09:13:49 guy Exp $ (LBL)
+dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.138.2.11 2008-04-04 19:39:05 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.138.2.10 $)
+AC_REVISION($Revision: 1.138.2.11 $)
 AC_PREREQ(2.50)
 AC_INIT(pcap.c)
 
@@ -448,9 +448,23 @@ 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_CHECK_HEADERS(linux/wireless.h, [], [],
+       [
+#include <sys/socket.h>
+#include <net/if.h>
+#include <linux/types.h>
+       ])
+       AC_CHECK_HEADERS()
        AC_LBL_TPACKET_STATS
        ;;
 
+bpf)
+       #
+       # Check whether we have the *BSD-style ioctls.
+       #
+       AC_CHECK_HEADERS(net/if_media.h)
+       ;;
+
 dag)
        V_DEFS="$V_DEFS -DDAG_ONLY"
        ;;
index 9f8e3ea2e3878dcbf5aa6ec35aea7edf097bae54..441b8c04797e95346f85090f598312fb7fab6aee 100644 (file)
@@ -12,7 +12,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-       "@(#) $Header: /tcpdump/master/libpcap/dlpisubs.c,v 1.1.2.1 2008-03-13 18:17:17 guy Exp $ (LBL)";
+       "@(#) $Header: /tcpdump/master/libpcap/dlpisubs.c,v 1.1.2.2 2008-04-04 19:39:05 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -197,7 +197,7 @@ pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user,
  * 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)
+pcap_process_mactype(pcap_t *p, u_int mactype)
 {
        int retv = 0;
 
@@ -247,7 +247,7 @@ pcap_process_mactype(pcap_t *p, u_int mactype, char *ebuf)
 #endif
 
        default:
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mactype %u",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype %u",
                    mactype);
                retv = -1;
        }
@@ -260,7 +260,7 @@ pcap_process_mactype(pcap_t *p, u_int mactype, char *ebuf)
  * 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)
+pcap_conf_bufmod(pcap_t *p, int snaplen, int timeout)
 {
        int retv = 0;
 
@@ -268,14 +268,14 @@ pcap_conf_bufmod(pcap_t *p, int snaplen, int timeout, char *ebuf)
 
        /* 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);
+               pcap_stream_err("I_PUSH bufmod", errno, p->errbuf);
                retv = -1;
        }
 
        ss = snaplen;
        if (ss > 0 &&
            strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
-               pcap_stream_err("SBIOCSSNAP", errno, ebuf);
+               pcap_stream_err("SBIOCSSNAP", errno, p->errbuf);
                retv = -1;
        }
 
@@ -286,7 +286,7 @@ pcap_conf_bufmod(pcap_t *p, int snaplen, int timeout, char *ebuf)
                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);
+                       pcap_stream_err("SBIOCSTIME", errno, p->errbuf);
                        retv = -1;
                }
        }
@@ -295,7 +295,7 @@ pcap_conf_bufmod(pcap_t *p, int snaplen, int timeout, char *ebuf)
        chunksize = CHUNKSIZE;
        if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize)
            != 0) {
-               pcap_stream_err("SBIOCSCHUNKP", errno, ebuf);
+               pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf);
                retv = -1;
        }
 
@@ -307,12 +307,12 @@ pcap_conf_bufmod(pcap_t *p, int snaplen, int timeout, char *ebuf)
  * Allocate data buffer. Returns -1 if memory allocation fails, else 0.
  */
 int
-pcap_alloc_databuf(pcap_t *p, char *ebuf)
+pcap_alloc_databuf(pcap_t *p)
 {
        p->bufsize = PKTBUFSIZE;
        p->buffer = (u_char *)malloc(p->bufsize + p->offset);
        if (p->buffer == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
+               strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
                return (-1);
        }
 
index 49f91818ff3c50a8ee839669ccf0cc68645cd4e2..67acd292f4009619b41868e910bf27bd946764ad 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * @(#) $Header: /tcpdump/master/libpcap/dlpisubs.h,v 1.1.2.1 2008-03-13 18:17:17 guy Exp $
+ * @(#) $Header: /tcpdump/master/libpcap/dlpisubs.h,v 1.1.2.2 2008-04-04 19:39:05 guy Exp $
  */
 
 #ifndef dlpisubs_h
@@ -14,11 +14,11 @@ extern "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 *);
+int pcap_process_mactype(pcap_t *, u_int);
 #ifdef HAVE_SYS_BUFMOD_H
-int pcap_conf_bufmod(pcap_t *, int, int, char *);
+int pcap_conf_bufmod(pcap_t *, int, int);
 #endif
-int pcap_alloc_databuf(pcap_t *, char *);
+int pcap_alloc_databuf(pcap_t *);
 int strioctl(int, int, int, char *);
 
 #ifdef __cplusplus
index aab48247b1573812070adcfbeb9c38ea163ee119..d5d0fe1c167926a8727a5c5e8a354d550c14a423 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.99.2.4 2008-01-29 10:13:11 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.99.2.5 2008-04-04 19:39:05 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -92,6 +92,10 @@ static int odmlockid = 0;
 #include <string.h>
 #include <unistd.h>
 
+#ifdef HAVE_NET_IF_MEDIA_H
+# include <net/if_media.h>
+#endif
+
 #include "pcap-int.h"
 
 #ifdef HAVE_DAG_API
@@ -102,10 +106,346 @@ static int odmlockid = 0;
 #include "os-proto.h"
 #endif
 
+#ifdef BIOCGDLTLIST
+# if (defined(HAVE_NET_IF_MEDIA_H) && defined(IFM_IEEE80211)) && !defined(__APPLE__)
+#define HAVE_BSD_IEEE80211
+# endif
+
+# if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)
+static int find_802_11(struct bpf_dltlist *);
+
+#  ifdef HAVE_BSD_IEEE80211
+static int monitor_mode(pcap_t *, int);
+#  endif
+
+#  if defined(__APPLE__)
+static void remove_en(pcap_t *);
+static void remove_802_11(pcap_t *);
+#  endif
+
+# endif /* defined(__APPLE__) || defined(HAVE_BSD_IEEE80211) */
+
+#endif /* BIOCGDLTLIST */
+
+/*
+ * We include the OS's <net/bpf.h>, not our "pcap/bpf.h", so we probably
+ * don't get DLT_DOCSIS defined.
+ */
+#ifndef DLT_DOCSIS
+#define DLT_DOCSIS     143
+#endif
+
+/*
+ * On OS X, we don't even get any of the 802.11-plus-radio-header DLT_'s
+ * defined, even though some of them are used by various Airport drivers.
+ */
+#ifndef DLT_PRISM_HEADER
+#define DLT_PRISM_HEADER       119
+#endif
+#ifndef DLT_AIRONET_HEADER
+#define DLT_AIRONET_HEADER     120
+#endif
+#ifndef DLT_IEEE802_11_RADIO
+#define DLT_IEEE802_11_RADIO   127
+#endif
+#ifndef DLT_IEEE802_11_RADIO_AVS
+#define DLT_IEEE802_11_RADIO_AVS 163
+#endif
+
+static int pcap_can_set_rfmon_bpf(pcap_t *p);
+static int pcap_activate_bpf(pcap_t *p);
 static int pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp);
 static int pcap_setdirection_bpf(pcap_t *, pcap_direction_t);
 static int pcap_set_datalink_bpf(pcap_t *p, int dlt);
 
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+#ifdef HAVE_DAG_API
+       if (strstr(device, "dag"))
+               return (dag_create(device, ebuf));
+#endif /* HAVE_DAG_API */
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_bpf;
+       p->can_set_rfmon_op = pcap_can_set_rfmon_bpf;
+       return (p);
+}
+
+static int
+bpf_open(pcap_t *p)
+{
+       int fd;
+#ifdef HAVE_CLONING_BPF
+       static const char device[] = "/dev/bpf";
+#else
+       int n = 0;
+       char device[sizeof "/dev/bpf0000000000"];
+#endif
+
+#ifdef _AIX
+       /*
+        * Load the bpf driver, if it isn't already loaded,
+        * and create the BPF device entries, if they don't
+        * already exist.
+        */
+       if (bpf_load(p->errbuf) == -1)
+               return (-1);
+#endif
+
+#ifdef HAVE_CLONING_BPF
+       if ((fd = open(device, O_RDWR)) == -1 &&
+           (errno != EACCES || (fd = open(device, O_RDONLY)) == -1))
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                 "(cannot open device) %s: %s", device, pcap_strerror(errno));
+#else
+       /*
+        * Go through all the minors and find one that isn't in use.
+        */
+       do {
+               (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+               /*
+                * Initially try a read/write open (to allow the inject
+                * method to work).  If that fails due to permission
+                * issues, fall back to read-only.  This allows a
+                * non-root user to be granted specific access to pcap
+                * capabilities via file permissions.
+                *
+                * XXX - we should have an API that has a flag that
+                * controls whether to open read-only or read-write,
+                * so that denial of permission to send (or inability
+                * to send, if sending packets isn't supported on
+                * the device in question) can be indicated at open
+                * time.
+                */
+               fd = open(device, O_RDWR);
+               if (fd == -1 && errno == EACCES)
+                       fd = open(device, O_RDONLY);
+       } while (fd < 0 && errno == EBUSY);
+
+       /*
+        * XXX better message for all minors used
+        */
+       if (fd < 0)
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
+                   device, pcap_strerror(errno));
+#endif
+
+       return (fd);
+}
+
+#ifdef BIOCGDLTLIST
+static int
+get_dlt_list(int fd, int v, struct bpf_dltlist *bdlp, char *ebuf)
+{
+       memset(bdlp, 0, sizeof(*bdlp));
+       if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) == 0) {
+               u_int i;
+               int is_ethernet;
+
+               bdlp->bfl_list = (u_int *) malloc(sizeof(u_int) * (bdlp->bfl_len + 1));
+               if (bdlp->bfl_list == NULL) {
+                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+                           pcap_strerror(errno));
+                       return (-1);
+               }
+
+               if (ioctl(fd, BIOCGDLTLIST, (caddr_t)bdlp) < 0) {
+                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                           "BIOCGDLTLIST: %s", pcap_strerror(errno));
+                       free(bdlp->bfl_list);
+                       return (-1);
+               }
+
+               /*
+                * OK, for real Ethernet devices, add DLT_DOCSIS to the
+                * list, 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).
+                *
+                * A "real Ethernet device" is defined here as a device
+                * that has a link-layer type of DLT_EN10MB and that has
+                * no alternate link-layer types; that's done to exclude
+                * 802.11 interfaces (which might or might not be the
+                * right thing to do, but I suspect it is - Ethernet <->
+                * 802.11 bridges would probably badly mishandle frames
+                * that don't have Ethernet headers).
+                */
+               if (v == DLT_EN10MB) {
+                       is_ethernet = 1;
+                       for (i = 0; i < bdlp->bfl_len; i++) {
+                               if (bdlp->bfl_list[i] != DLT_EN10MB) {
+                                       is_ethernet = 0;
+                                       break;
+                               }
+                       }
+                       if (is_ethernet) {
+                               /*
+                                * We reserved one more slot at the end of
+                                * the list.
+                                */
+                               bdlp->bfl_list[bdlp->bfl_len] = DLT_DOCSIS;
+                               bdlp->bfl_len++;
+                       }
+               }
+       } else {
+               /*
+                * EINVAL just means "we don't support this ioctl on
+                * this device"; don't treat it as an error.
+                */
+               if (errno != EINVAL) {
+                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                           "BIOCGDLTLIST: %s", pcap_strerror(errno));
+                       return (-1);
+               }
+       }
+       return (0);
+}
+#endif
+
+static int
+pcap_can_set_rfmon_bpf(pcap_t *p)
+{
+#if defined(__APPLE__)
+       struct utsname osinfo;
+       struct ifreq ifr;
+       int fd;
+#ifdef BIOCGDLTLIST
+       struct bpf_dltlist bdl;
+#endif
+
+       /*
+        * The joys of monitor mode on OS X.
+        *
+        * Prior to 10.4, it's not supported at all.
+        *
+        * In 10.4, if adapter enN supports monitor mode, there's a
+        * wltN adapter corresponding to it; you open it, instead of
+        * enN, to get monitor mode.  You get whatever link-layer
+        * headers it supplies.
+        *
+        * In 10.5, and, we assume, later releases, if adapter enN
+        * supports monitor mode, it offers, among its selectable
+        * DLT_ values, values that let you get the 802.11 header;
+        * selecting one of those values puts the adapter into monitor
+        * mode (i.e., you can't get 802.11 headers except in monitor
+        * mode, and you can't get Ethernet headers in monitor mode).
+        */
+       if (uname(&osinfo) == -1) {
+               /*
+                * Can't get the OS version; just say "no".
+                */
+               return (0);
+       }
+       /*
+        * We assume osinfo.sysname is "Darwin", because
+        * __APPLE__ is defined.  We just check the version.
+        */
+       if (osinfo.release[0] < '8' && osinfo.release[1] == '.') {
+               /*
+                * 10.3 (Darwin 7.x) or earlier.
+                * Monitor mode not supported.
+                */
+               return (0);
+       }
+       if (osinfo.release[0] == '8' && osinfo.release[1] == '.') {
+               /*
+                * 10.4 (Darwin 8.x).  s/en/wlt/, and check
+                * whether the device exists.
+                */
+               if (strncmp(p->opt.source, "en", 2) != 0) {
+                       /*
+                        * Not an enN device; no monitor mode.
+                        */
+                       return (0);
+               }
+               fd = socket(AF_INET, SOCK_DGRAM, 0);
+               if (fd == -1) {
+                       (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "socket: %s", pcap_strerror(errno));
+                       return (PCAP_ERROR);
+               }
+               strlcpy(ifr.ifr_name, "wlt", sizeof(ifr.ifr_name));
+               strlcat(ifr.ifr_name, p->opt.source + 2, sizeof(ifr.ifr_name));
+               if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+                       /*
+                        * No such device?
+                        */
+                       close(fd);
+                       return (0);
+               }
+               close(fd);
+               return (1);
+       }
+
+#ifdef BIOCGDLTLIST
+       /*
+        * Everything else is 10.5 or later; for those,
+        * we just open the enN device, and check whether
+        * we have any 802.11 devices.
+        *
+        * First, open a BPF device.
+        */
+       fd = bpf_open(p);
+       if (fd < 0)
+               return (PCAP_ERROR);
+
+       /*
+        * Now bind to the device.
+        */
+       (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name));
+       if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "BIOCSETIF: %s: %s",
+                   p->opt.source, pcap_strerror(errno));
+               close(fd);
+               return (PCAP_ERROR);
+       }
+
+       /*
+        * We know the default link type -- now determine all the DLTs
+        * this interface supports.  If this fails with EINVAL, it's
+        * not fatal; we just don't get to use the feature later.
+        * (We don't care about DLT_DOCSIS, so we pass DLT_NULL
+        * as the default DLT for this adapter.)
+        */
+       if (get_dlt_list(fd, DLT_NULL, &bdl, p->errbuf) == -1) {
+               close(fd);
+               return (PCAP_ERROR);
+       }
+       if (find_802_11(&bdl) != -1) {
+               /*
+                * We have an 802.11 DLT, so we can set monitor mode.
+                */
+               free(bdl.bfl_list);
+               close(fd);
+               return (1);
+       }
+       free(bdl.bfl_list);
+#endif /* BIOCGDLTLIST */
+       return (0);
+#elif defined(HAVE_BSD_IEEE80211)
+       int ret;
+
+       ret = monitor_mode(p, 0);
+       if (ret == PCAP_ERROR_RFMON_NOTSUP)
+               return (0);     /* not an error, just a "can't do" */
+       if (ret == 0)
+               return (1);     /* success */
+       return (ret);
+#else
+       return (0);
+#endif
+}
+
 static int
 pcap_stats_bpf(pcap_t *p, struct pcap_stat *ps)
 {
@@ -516,169 +856,348 @@ bpf_load(char *errbuf)
 }
 #endif
 
-static inline int
-bpf_open(pcap_t *p, char *errbuf)
+/*
+ * Turn off rfmon mode if necessary.
+ */
+static void
+pcap_close_bpf(pcap_t *p)
 {
-       int fd;
-#ifdef HAVE_CLONING_BPF
-       static const char device[] = "/dev/bpf";
-#else
-       int n = 0;
-       char device[sizeof "/dev/bpf0000000000"];
+#ifdef HAVE_BSD_IEEE80211
+       int sock;
+       struct ifmediareq req;
+       struct ifreq ifr;
 #endif
 
-#ifdef _AIX
-       /*
-        * Load the bpf driver, if it isn't already loaded,
-        * and create the BPF device entries, if they don't
-        * already exist.
-        */
-       if (bpf_load(errbuf) == -1)
-               return (-1);
-#endif
+       if (p->md.must_clear != 0) {
+               /*
+                * There's something we have to do when closing this
+                * pcap_t.
+                */
+#ifdef HAVE_BSD_IEEE80211
+               if (p->md.must_clear & MUST_CLEAR_RFMON) {
+                       /*
+                        * We put the interface into rfmon mode;
+                        * take it out of rfmon mode.
+                        *
+                        * XXX - if somebody else wants it in rfmon
+                        * mode, this code cannot know that, so it'll take
+                        * it out of rfmon mode.
+                        */
+                       sock = socket(AF_INET, SOCK_DGRAM, 0);
+                       if (sock == -1) {
+                               fprintf(stderr,
+                                   "Can't restore interface flags (socket() failed: %s).\n"
+                                   "Please adjust manually.\n",
+                                   strerror(errno));
+                       } else {
+                               memset(&req, 0, sizeof(req));
+                               strncpy(req.ifm_name, p->md.device,
+                                   sizeof(req.ifm_name));
+                               if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
+                                       fprintf(stderr,
+                                           "Can't restore interface flags (SIOCGIFMEDIA failed: %s).\n"
+                                           "Please adjust manually.\n",
+                                           strerror(errno));
+                               } else {
+                                       if (req.ifm_current & IFM_IEEE80211_MONITOR) {
+                                               /*
+                                                * Rfmon mode is currently on;
+                                                * turn it off.
+                                                */
+                                               memset(&ifr, 0, sizeof(ifr));
+                                               (void)strncpy(ifr.ifr_name,
+                                                   p->md.device,
+                                                   sizeof(ifr.ifr_name));
+                                               ifr.ifr_media =
+                                                   req.ifm_current & ~IFM_IEEE80211_MONITOR;
+                                               if (ioctl(sock, SIOCSIFMEDIA,
+                                                   &ifr) == -1) {
+                                                       fprintf(stderr,
+                                                           "Can't restore interface flags (SIOCSIFMEDIA failed: %s).\n"
+                                                           "Please adjust manually.\n",
+                                                           strerror(errno));
+                                               }
+                                       }
+                               }
+                               close(sock);
+                       }
+               }
+#endif /* HAVE_BSD_IEEE80211 */
 
-#ifdef HAVE_CLONING_BPF
-       if ((fd = open(device, O_RDWR)) == -1 &&
-           (errno != EACCES || (fd = open(device, O_RDONLY)) == -1))
-               snprintf(errbuf, PCAP_ERRBUF_SIZE,
-                 "(cannot open device) %s: %s", device, pcap_strerror(errno));
-#else
-       /*
-        * Go through all the minors and find one that isn't in use.
-        */
-       do {
-               (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
                /*
-                * Initially try a read/write open (to allow the inject
-                * method to work).  If that fails due to permission
-                * issues, fall back to read-only.  This allows a
-                * non-root user to be granted specific access to pcap
-                * capabilities via file permissions.
-                *
-                * XXX - we should have an API that has a flag that
-                * controls whether to open read-only or read-write,
-                * so that denial of permission to send (or inability
-                * to send, if sending packets isn't supported on
-                * the device in question) can be indicated at open
-                * time.
+                * Take this pcap out of the list of pcaps for which we
+                * have to take the interface out of some mode.
                 */
-               fd = open(device, O_RDWR);
-               if (fd == -1 && errno == EACCES)
-                       fd = open(device, O_RDONLY);
-       } while (fd < 0 && errno == EBUSY);
-
-       /*
-        * XXX better message for all minors used
-        */
-       if (fd < 0)
-               snprintf(errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
-                   device, pcap_strerror(errno));
-#endif
+               pcap_remove_from_pcaps_to_close(p);
+       }
 
-       return (fd);
+       if (p->md.device != NULL)
+               free(p->md.device);
+       p->md.device = NULL;
+       pcap_close_common(p);
 }
 
-/*
- * We include the OS's <net/bpf.h>, not our "pcap/bpf.h", so we probably
- * don't get DLT_DOCSIS defined.
- */
-#ifndef DLT_DOCSIS
-#define DLT_DOCSIS     143
+static int
+check_setif_failure(pcap_t *p, int error)
+{
+#ifdef __APPLE__
+       int fd;
+       struct ifreq ifr;
+       int err;
 #endif
 
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+       if (error == ENXIO) {
+               /*
+                * No such device exists.
+                */
+#ifdef __APPLE__
+               if (p->opt.rfmon && strncmp(p->opt.source, "wlt", 3) == 0) {
+                       /*
+                        * Monitor mode was requested, and we're trying
+                        * to open a "wltN" device.  Assume that this
+                        * is 10.4 and that we were asked to open an
+                        * "enN" device; if that device exists, return
+                        * "monitor mode not supported on the device".
+                        */
+                       fd = socket(AF_INET, SOCK_DGRAM, 0);
+                       if (fd != -1) {
+                               strlcpy(ifr.ifr_name, "en",
+                                   sizeof(ifr.ifr_name));
+                               strlcat(ifr.ifr_name, p->opt.source + 3,
+                                   sizeof(ifr.ifr_name));
+                               if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+                                       /*
+                                        * We assume this failed because
+                                        * the underlying device doesn't
+                                        * exist.
+                                        */
+                                       err = PCAP_ERROR_NO_SUCH_DEVICE;
+                               } else {
+                                       /*
+                                        * The underlying "enN" device
+                                        * exists, but there's no
+                                        * corresponding "wltN" device;
+                                        * that means that the "enN"
+                                        * device doesn't support
+                                        * monitor mode, probably because
+                                        * it's an Ethernet device rather
+                                        * than a wireless device.
+                                        */
+                                       err = PCAP_ERROR_RFMON_NOTSUP;
+                               }
+                               close(fd);
+                       } else {
+                               /*
+                                * We can't find out whether there's
+                                * an underlying "enN" device, so
+                                * just report "no such device".
+                                */
+                               err = PCAP_ERROR_NO_SUCH_DEVICE;
+                       }
+                       return (err);
+               }
+#endif
+               /*
+                * No such device.
+                */
+               return (PCAP_ERROR_NO_SUCH_DEVICE);
+       } else {
+               /*
+                * Some other error; fill in the error string, and
+                * return PCAP_ERROR.
+                */
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
+                   p->opt.source, pcap_strerror(errno));
+               return (PCAP_ERROR);
+       }
+}
+
+static int
+pcap_activate_bpf(pcap_t *p)
 {
+       int err;
        int fd;
        struct ifreq ifr;
        struct bpf_version bv;
+#ifdef __APPLE__
+       char *wltdev = NULL;
+#endif
 #ifdef BIOCGDLTLIST
        struct bpf_dltlist bdl;
+#if defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)
+       int new_dlt;
 #endif
+#endif /* BIOCGDLTLIST */
 #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
        u_int spoof_eth_src = 1;
 #endif
        u_int v;
-       pcap_t *p;
        struct bpf_insn total_insn;
        struct bpf_program total_prog;
        struct utsname osinfo;
+       int have_osinfo = 0;
 
-#ifdef HAVE_DAG_API
-       if (strstr(device, "dag")) {
-               return dag_open_live(device, snaplen, promisc, to_ms, ebuf);
-       }
-#endif /* HAVE_DAG_API */
-
-       p = (pcap_t *)malloc(sizeof(*p));
-       if (p == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                   pcap_strerror(errno));
-               return (NULL);
-       }
-       memset(p, 0, sizeof(*p));
-       fd = bpf_open(p, ebuf);
-       if (fd < 0)
+       fd = bpf_open(p);
+       if (fd < 0) {
+               err = PCAP_ERROR;
                goto bad;
+       }
 
        p->fd = fd;
-       p->snapshot = snaplen;
 
        if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
                    pcap_strerror(errno));
+               err = PCAP_ERROR;
                goto bad;
        }
        if (bv.bv_major != BPF_MAJOR_VERSION ||
            bv.bv_minor < BPF_MINOR_VERSION) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "kernel bpf filter out of date");
+               err = PCAP_ERROR;
                goto bad;
        }
 
+       p->md.device = strdup(p->opt.source);
+       if (p->md.device == NULL) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s",
+                    pcap_strerror(errno));
+               return PCAP_ERROR;
+       }
+
        /*
-        * Try finding a good size for the buffer; 32768 may be too
-        * big, so keep cutting it in half until we find a size
-        * that works, or run out of sizes to try.  If the default
-        * is larger, don't make it smaller.
-        *
-        * XXX - there should be a user-accessible hook to set the
-        * initial buffer size.
+        * Attempt to find out the version of the OS on which we're running.
         */
-       if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 32768)
-               v = 32768;
-       for ( ; v != 0; v >>= 1) {
-               /* Ignore the return value - this is because the call fails
-                * on BPF systems that don't have kernel malloc.  And if
-                * the call fails, it's no big deal, we just continue to
-                * use the standard buffer size.
-                */
-               (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
+       if (uname(&osinfo) == 0)
+               have_osinfo = 1;
+
+#ifdef __APPLE__
+       /*
+        * See comment in pcap_can_set_rfmon_bpf() for an explanation
+        * of why we check the version number.
+        */
+       if (p->opt.rfmon) {
+               if (have_osinfo) {
+                       /*
+                        * We assume osinfo.sysname is "Darwin", because
+                        * __APPLE__ is defined.  We just check the version.
+                        */
+                       if (osinfo.release[0] < '8' &&
+                           osinfo.release[1] == '.') {
+                               /*
+                                * 10.3 (Darwin 7.x) or earlier.
+                                */
+                               err = PCAP_ERROR_RFMON_NOTSUP;
+                               goto bad;
+                       }
+                       if (osinfo.release[0] == '8' &&
+                           osinfo.release[1] == '.') {
+                               /*
+                                * 10.4 (Darwin 8.x).  s/en/wlt/
+                                */
+                               if (strncmp(p->opt.source, "en", 2) != 0) {
+                                       /*
+                                        * Not an enN device; no monitor
+                                        * mode.
+                                        */
+                                       err = PCAP_ERROR_RFMON_NOTSUP;
+                                       goto bad;
+                               }
+                               wltdev = malloc(strlen(p->opt.source) + 2);
+                               if (wltdev == NULL) {
+                                       (void)snprintf(p->errbuf,
+                                           PCAP_ERRBUF_SIZE, "malloc: %s",
+                                           pcap_strerror(errno));
+                                       err = PCAP_ERROR;
+                                       goto bad;
+                               }
+                               strcpy(wltdev, "wlt");
+                               strcat(wltdev, p->opt.source + 2);
+                               free(p->opt.source);
+                               p->opt.source = wltdev;
+                       }
+                       /*
+                        * Everything else is 10.5 or later; for those,
+                        * we just open the enN device, and set the DLT.
+                        */
+               }
+       }
+#endif /* __APPLE__ */
 
-               (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
-               if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
-                       break;  /* that size worked; we're done */
+       /*
+        * Set the buffer size.
+        */
+       if (p->opt.buffer_size != 0) {
+               /*
+                * A buffer size was explicitly specified; use it.
+                */
+               if (ioctl(fd, BIOCSBLEN, (caddr_t)&p->opt.buffer_size) < 0) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "BIOCSBLEN: %s: %s", p->opt.source,
+                           pcap_strerror(errno));
+                       err = PCAP_ERROR;
+                       goto bad;
+               }
 
-               if (errno != ENOBUFS) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
-                           device, pcap_strerror(errno));
+               /*
+                * Now bind to the device.
+                */
+               (void)strncpy(ifr.ifr_name, p->opt.source,
+                   sizeof(ifr.ifr_name));
+               if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+                       err = check_setif_failure(p, errno);
                        goto bad;
                }
-       }
+       } else {
+               /*
+                * No buffer size was explicitly specified.
+                *
+                * Try finding a good size for the buffer; 32768 may
+                * be too big, so keep cutting it in half until we
+                * find a size that works, or run out of sizes to try.
+                * If the default is larger, don't make it smaller.
+                */
+               if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 32768)
+                       v = 32768;
+               for ( ; v != 0; v >>= 1) {
+                       /*
+                        * Ignore the return value - this is because the
+                        * call fails on BPF systems that don't have
+                        * kernel malloc.  And if the call fails, it's
+                        * no big deal, we just continue to use the
+                        * standard buffer size.
+                        */
+                       (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
 
-       if (v == 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                        "BIOCSBLEN: %s: No buffer size worked", device);
-               goto bad;
+                       (void)strncpy(ifr.ifr_name, p->opt.source,
+                           sizeof(ifr.ifr_name));
+                       if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
+                               break;  /* that size worked; we're done */
+
+                       if (errno != ENOBUFS) {
+                               err = check_setif_failure(p, errno);
+                               goto bad;
+                       }
+               }
+
+               if (v == 0) {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "BIOCSBLEN: %s: No buffer size worked",
+                           p->opt.source);
+                       err = PCAP_ERROR;
+                       goto bad;
+               }
        }
 
        /* Get the data link layer type. */
        if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
                    pcap_strerror(errno));
+               err = PCAP_ERROR;
                goto bad;
        }
+
 #ifdef _AIX
        /*
         * AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT.
@@ -706,8 +1225,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                /*
                 * We don't know what to map this to yet.
                 */
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown interface type %u",
                    v);
+               err = PCAP_ERROR;
                goto bad;
        }
 #endif
@@ -732,13 +1252,6 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                break;
        }
 #endif
-#ifdef PCAP_FDDIPAD
-       if (v == DLT_FDDI)
-               p->fddipad = PCAP_FDDIPAD;
-       else
-               p->fddipad = 0;
-#endif
-       p->linktype = v;
 
 #ifdef BIOCGDLTLIST
        /*
@@ -746,69 +1259,144 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * this interface supports.  If this fails with EINVAL, it's
         * not fatal; we just don't get to use the feature later.
         */
-       memset(&bdl, 0, sizeof(bdl));
-       if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) == 0) {
-               u_int i;
-               int is_ethernet;
+       if (get_dlt_list(fd, v, &bdl, p->errbuf) == -1) {
+               err = PCAP_ERROR;
+               goto bad;
+       }
+       p->dlt_count = bdl.bfl_len;
+       p->dlt_list = bdl.bfl_list;
 
-               bdl.bfl_list = (u_int *) malloc(sizeof(u_int) * (bdl.bfl_len + 1));
-               if (bdl.bfl_list == NULL) {
-                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                           pcap_strerror(errno));
-                       goto bad;
+#ifdef __APPLE__
+       /*
+        * Monitor mode fun, continued.
+        *
+        * For 10.5 and, we're assuming, later releases, as noted above,
+        * 802.1 adapters that support monitor mode offer both DLT_EN10MB,
+        * DLT_IEEE802_11, and possibly some 802.11-plus-radio-information
+        * DLT_ value.  Choosing one of the 802.11 DLT_ values will turn
+        * monitor mode on.
+        *
+        * Therefore, if the user asked for monitor mode, we filter out
+        * the DLT_EN10MB value, as you can't get that in monitor mode,
+        * and, if the user didn't ask for monitor mode, we filter out
+        * the 802.11 DLT_ values, because selecting those will turn
+        * monitor mode on.  Then, for monitor mode, if an 802.11-plus-
+        * radio DLT_ value is offered, we try to select that, otherwise
+        * we try to select DLT_IEEE802_11.
+        */
+       if (have_osinfo) {
+               if (isdigit((unsigned)osinfo.release[0]) &&
+                    (osinfo.release[0] == '9' ||
+                    isdigit((unsigned)osinfo.release[1]))) {
+                       /*
+                        * 10.5 (Darwin 9.x), or later.
+                        */
+                       new_dlt = find_802_11(&bdl);
+                       if (new_dlt != -1) {
+                               /*
+                                * We have at least one 802.11 DLT_ value,
+                                * so this is an 802.11 interface.
+                                * new_dlt is the best of the 802.11
+                                * DLT_ values in the list.
+                                */
+                               if (p->opt.rfmon) {
+                                       /*
+                                        * Our caller wants monitor mode.
+                                        * Purge DLT_EN10MB from the list
+                                        * of link-layer types, as selecting
+                                        * it will keep monitor mode off.
+                                        */
+                                       remove_en(p);
+
+                                       /*
+                                        * If the new mode we want isn't
+                                        * the default mode, attempt to
+                                        * select the new mode.
+                                        */
+                                       if (new_dlt != v) {
+                                               if (ioctl(p->fd, BIOCSDLT,
+                                                   &new_dlt) != -1) {
+                                                       /*
+                                                        * We succeeded;
+                                                        * make this the
+                                                        * new DLT_ value.
+                                                        */
+                                                       v = new_dlt;
+                                               }
+                                       }
+                               } else {
+                                       /*
+                                        * Our caller doesn't want
+                                        * monitor mode.  Unless this
+                                        * is being done by pcap_open_live(),
+                                        * purge the 802.11 link-layer types
+                                        * from the list, as selecting
+                                        * one of them will turn monitor
+                                        * mode on.
+                                        */
+                                       if (!p->oldstyle)
+                                               remove_802_11(p);
+                               }
+                       } else {
+                               if (p->opt.rfmon) {
+                                       /*
+                                        * The caller requested monitor
+                                        * mode, but we have no 802.11
+                                        * link-layer types, so they
+                                        * can't have it.
+                                        */
+                                       err = PCAP_ERROR_RFMON_NOTSUP;
+                                       goto bad;
+                               }
+                       }
                }
-
-               if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) < 0) {
-                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                           "BIOCGDLTLIST: %s", pcap_strerror(errno));
-                       free(bdl.bfl_list);
+       }
+#elif defined(HAVE_BSD_IEEE80211)
+       /*
+        * *BSD with the new 802.11 ioctls.
+        * Do we want monitor mode?
+        */
+       if (p->opt.rfmon) {
+               /*
+                * Try to put the interface into monitor mode.
+                */
+               err = monitor_mode(p, 1);
+               if (err != 0) {
+                       /*
+                        * We failed.
+                        */
                        goto bad;
                }
 
                /*
-                * OK, for real Ethernet devices, add DLT_DOCSIS to the
-                * list, 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).
-                *
-                * A "real Ethernet device" is defined here as a device
-                * that has a link-layer type of DLT_EN10MB and that has
-                * no alternate link-layer types; that's done to exclude
-                * 802.11 interfaces (which might or might not be the
-                * right thing to do, but I suspect it is - Ethernet <->
-                * 802.11 bridges would probably badly mishandle frames
-                * that don't have Ethernet headers).
+                * We're in monitor mode.
+                * Try to find the best 802.11 DLT_ value and, if we
+                * succeed, try to switch to that mode if we're not
+                * already in that mode.
                 */
-               if (p->linktype == DLT_EN10MB) {
-                       is_ethernet = 1;
-                       for (i = 0; i < bdl.bfl_len; i++) {
-                               if (bdl.bfl_list[i] != DLT_EN10MB) {
-                                       is_ethernet = 0;
-                                       break;
+               new_dlt = find_802_11(&bdl);
+               if (new_dlt != -1) {
+                       /*
+                        * We have at least one 802.11 DLT_ value.
+                        * new_dlt is the best of the 802.11
+                        * DLT_ values in the list.
+                        *
+                        * If the new mode we want isn't the default mode,
+                        * attempt to select the new mode.
+                        */
+                       if (new_dlt != v) {
+                               if (ioctl(p->fd, BIOCSDLT, &new_dlt) != -1) {
+                                       /*
+                                        * We succeeded; make this the
+                                        * new DLT_ value.
+                                        */
+                                       v = new_dlt;
                                }
                        }
-                       if (is_ethernet) {
-                               /*
-                                * We reserved one more slot at the end of
-                                * the list.
-                                */
-                               bdl.bfl_list[bdl.bfl_len] = DLT_DOCSIS;
-                               bdl.bfl_len++;
-                       }
-               }
-               p->dlt_count = bdl.bfl_len;
-               p->dlt_list = bdl.bfl_list;
-       } else {
-               if (errno != EINVAL) {
-                       (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                           "BIOCGDLTLIST: %s", pcap_strerror(errno));
-                       goto bad;
                }
        }
-#endif
+#endif /* various platforms */
+#endif /* BIOCGDLTLIST */
 
        /*
         * If this is an Ethernet device, and we don't have a DLT_ list,
@@ -818,7 +1406,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * some other way of determining whether it's an Ethernet or 802.11
         * device.)
         */
-       if (p->linktype == DLT_EN10MB && p->dlt_count == 0) {
+       if (v == DLT_EN10MB && p->dlt_count == 0) {
                p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
                /*
                 * If that fails, just leave the list empty.
@@ -829,6 +1417,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                        p->dlt_count = 2;
                }
        }
+#ifdef PCAP_FDDIPAD
+       if (v == DLT_FDDI)
+               p->fddipad = PCAP_FDDIPAD;
+       else
+               p->fddipad = 0;
+#endif
+       p->linktype = v;
 
 #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)
        /*
@@ -841,24 +1436,26 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * BSDs - check CVS log for "bpf.c"?
         */
        if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) {
-               (void)snprintf(ebuf, PCAP_ERRBUF_SIZE,
+               (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "BIOCSHDRCMPLT: %s", pcap_strerror(errno));
+               err = PCAP_ERROR;
                goto bad;
        }
 #endif
        /* set timeout */
-       if (to_ms != 0) {
+       if (p->md.timeout != 0) {
                /*
                 * XXX - is this seconds/nanoseconds in AIX?
                 * (Treating it as such doesn't fix the timeout
                 * problem described below.)
                 */
                struct timeval to;
-               to.tv_sec = to_ms / 1000;
-               to.tv_usec = (to_ms * 1000) % 1000000;
+               to.tv_sec = p->md.timeout / 1000;
+               to.tv_usec = (p->md.timeout * 1000) % 1000000;
                if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
                            pcap_strerror(errno));
+                       err = PCAP_ERROR;
                        goto bad;
                }
        }
@@ -913,31 +1510,34 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         */
        v = 1;
        if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s",
                    pcap_strerror(errno));
+               err = PCAP_ERROR;
                goto bad;
        }
 #endif /* BIOCIMMEDIATE */
 #endif /* _AIX */
 
-       if (promisc) {
+       if (p->opt.promisc) {
                /* set promiscuous mode, okay if it fails */
                if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s",
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s",
                            pcap_strerror(errno));
                }
        }
 
        if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
                    pcap_strerror(errno));
+               err = PCAP_ERROR;
                goto bad;
        }
        p->bufsize = v;
        p->buffer = (u_char *)malloc(p->bufsize);
        if (p->buffer == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s",
                    pcap_strerror(errno));
+               err = PCAP_ERROR;
                goto bad;
        }
 #ifdef _AIX
@@ -958,13 +1558,14 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        total_insn.code = (u_short)(BPF_RET | BPF_K);
        total_insn.jt = 0;
        total_insn.jf = 0;
-       total_insn.k = snaplen;
+       total_insn.k = p->snapshot;
 
        total_prog.bf_len = 1;
        total_prog.bf_insns = &total_insn;
        if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
                    pcap_strerror(errno));
+               err = PCAP_ERROR;
                goto bad;
        }
 
@@ -1005,7 +1606,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * XXX - what about AIX?
         */
        p->selectable_fd = p->fd;       /* assume select() works until we know otherwise */
-       if (uname(&osinfo) == 0) {
+       if (have_osinfo) {
                /*
                 * We can check what OS this is.
                 */
@@ -1024,15 +1625,16 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->getnonblock_op = pcap_getnonblock_fd;
        p->setnonblock_op = pcap_setnonblock_fd;
        p->stats_op = pcap_stats_bpf;
-       p->close_op = pcap_close_common;
+       p->close_op = pcap_close_bpf;
 
-       return (p);
+       return (0);
  bad:
        (void)close(fd);
-       if (p->dlt_list != NULL)
-               free(p->dlt_list);
-       free(p);
-       return (NULL);
+       if (p->buffer != NULL) {
+               free(p->buffer);
+               p->buffer = NULL;
+       }
+       return (err);
 }
 
 int
@@ -1046,6 +1648,303 @@ pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
        return (0);
 }
 
+#ifdef HAVE_BSD_IEEE80211
+static int
+monitor_mode(pcap_t *p, int set)
+{
+       int sock;
+       struct ifmediareq req;
+       int *media_list;
+       int i;
+       int can_do;
+       struct ifreq ifr;
+
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock == -1) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't open socket: %s",
+                   pcap_strerror(errno));
+               return (PCAP_ERROR);
+       }
+
+       memset(&req, 0, sizeof req);
+       strncpy(req.ifm_name, p->opt.source, sizeof req.ifm_name);
+
+       /*
+        * Find out how many media types we have.
+        */
+       if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
+               /*
+                * Can't get the media types.
+                */
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s",
+                   pcap_strerror(errno));
+               close(sock);
+               return (PCAP_ERROR);
+       }
+       if (req.ifm_count == 0) {
+               /*
+                * No media types.
+                */
+               close(sock);
+               return (PCAP_ERROR_RFMON_NOTSUP);
+       }
+
+       /*
+        * Allocate a buffer to hold all the media types, and
+        * get the media types.
+        */
+       media_list = malloc(req.ifm_count * sizeof(int));
+       if (media_list == NULL) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+                   pcap_strerror(errno));
+               close(sock);
+               return (PCAP_ERROR);
+       }
+       req.ifm_ulist = media_list;
+       if (ioctl(sock, SIOCGIFMEDIA, &req) < 0) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMEDIA: %s",
+                   pcap_strerror(errno));
+               free(media_list);
+               close(sock);
+               return (PCAP_ERROR);
+       }
+
+       /*
+        * Look for an 802.11 "automatic" media type.
+        * We assume that all 802.11 adapters have that media type,
+        * and that it will carry the monitor mode supported flag.
+        */
+       can_do = 0;
+       for (i = 0; i < req.ifm_count; i++) {
+               if (IFM_TYPE(media_list[i]) == IFM_IEEE80211
+                   && IFM_SUBTYPE(media_list[i]) == IFM_AUTO) {
+                       /* OK, does it do monitor mode? */
+                       if (media_list[i] & IFM_IEEE80211_MONITOR) {
+                               can_do = 1;
+                               break;
+                       }
+               }
+       }
+       free(media_list);
+       if (!can_do) {
+               /*
+                * This adapter doesn't support monitor mode.
+                */
+               close(sock);
+               return (PCAP_ERROR_RFMON_NOTSUP);
+       }
+
+       if (set) {
+               /*
+                * Don't just check whether we can enable monitor mode,
+                * do so, if it's not already enabled.
+                */
+               if ((req.ifm_current & IFM_IEEE80211_MONITOR) == 0) {
+                       /*
+                        * Monitor mode isn't currently on, so turn it on,
+                        * and remember that we should turn it off when the
+                        * pcap_t is closed.
+                        */
+
+                       /*
+                        * If we haven't already done so, arrange to have
+                        * "pcap_close_all()" called when we exit.
+                        */
+                       if (!pcap_do_addexit(p)) {
+                               /*
+                                * "atexit()" failed; don't put the interface
+                                * in monitor mode, just give up.
+                                */
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                                    "atexit failed");
+                               close(sock);
+                               return (PCAP_ERROR);
+                       }
+                       memset(&ifr, 0, sizeof(ifr));
+                       (void)strncpy(ifr.ifr_name, p->opt.source,
+                           sizeof(ifr.ifr_name));
+                       ifr.ifr_media = req.ifm_current | IFM_IEEE80211_MONITOR;
+                       if (ioctl(sock, SIOCSIFMEDIA, &ifr) == -1) {
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                                    "SIOCSIFMEDIA: %s", pcap_strerror(errno));
+                               close(sock);
+                               return (PCAP_ERROR);
+                       }
+
+                       p->md.must_clear |= MUST_CLEAR_RFMON;
+
+                       /*
+                        * Add this to the list of pcaps to close when we exit.
+                        */
+                       pcap_add_to_pcaps_to_close(p);
+               }
+       }
+       return (0);
+}
+#endif /* HAVE_BSD_IEEE80211 */
+
+#if defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211))
+/*
+ * Check whether we have any 802.11 link-layer types; return the best
+ * of the 802.11 link-layer types if we find one, and return -1
+ * otherwise.
+ *
+ * DLT_IEEE802_11_RADIO, with the radiotap header, is considered the
+ * best 802.11 link-layer type; any of the other 802.11-plus-radio
+ * headers are second-best; 802.11 with no radio information is
+ * the least good.
+ */
+static int
+find_802_11(struct bpf_dltlist *bdlp)
+{
+       int new_dlt;
+       int i;
+
+       /*
+        * Scan the list of DLT_ values, looking for 802.11 values,
+        * and, if we find any, choose the best of them.
+        */
+       new_dlt = -1;
+       for (i = 0; i < bdlp->bfl_len; i++) {
+               switch (bdlp->bfl_list[i]) {
+
+               case DLT_IEEE802_11:
+                       /*
+                        * 802.11, but no radio.
+                        *
+                        * Offer this, and select it as the new mode
+                        * unless we've already found an 802.11
+                        * header with radio information.
+                        */
+                       if (new_dlt == -1)
+                               new_dlt = bdlp->bfl_list[i];
+                       break;
+
+               case DLT_PRISM_HEADER:
+               case DLT_AIRONET_HEADER:
+               case DLT_IEEE802_11_RADIO_AVS:
+                       /*
+                        * 802.11 with radio, but not radiotap.
+                        *
+                        * Offer this, and select it as the new mode
+                        * unless we've already found the radiotap DLT_.
+                        */
+                       if (new_dlt != DLT_IEEE802_11_RADIO)
+                               new_dlt = bdlp->bfl_list[i];
+                       break;
+
+               case DLT_IEEE802_11_RADIO:
+                       /*
+                        * 802.11 with radiotap.
+                        *
+                        * Offer this, and select it as the new mode.
+                        */
+                       new_dlt = bdlp->bfl_list[i];
+                       break;
+
+               default:
+                       /*
+                        * Not 802.11.
+                        */
+                       break;
+               }
+       }
+
+       return (new_dlt);
+}
+#endif /* defined(BIOCGDLTLIST) && (defined(__APPLE__) || defined(HAVE_BSD_IEEE80211)) */
+
+#if defined(__APPLE__) && defined(BIOCGDLTLIST)
+/*
+ * Remove DLT_EN10MB from the list of DLT_ values.
+ */
+static void
+remove_en(pcap_t *p)
+{
+       int i, j;
+
+       /*
+        * Scan the list of DLT_ values and discard DLT_EN10MB.
+        */
+       j = 0;
+       for (i = 0; i < p->dlt_count; i++) {
+               switch (p->dlt_list[i]) {
+
+               case DLT_EN10MB:
+                       /*
+                        * Don't offer this one.
+                        */
+                       continue;
+
+               default:
+                       /*
+                        * Just copy this mode over.
+                        */
+                       break;
+               }
+
+               /*
+                * Copy this DLT_ value to its new position.
+                */
+               p->dlt_list[j] = p->dlt_list[i];
+               j++;
+       }
+
+       /*
+        * Set the DLT_ count to the number of entries we copied.
+        */
+       p->dlt_count = j;
+}
+
+/*
+ * Remove DLT_EN10MB from the list of DLT_ values, and look for the
+ * best 802.11 link-layer type in that list and return it.
+ * Radiotap is better than anything else; 802.11 with any other radio
+ * header is better than 802.11 with no radio header.
+ */
+static void
+remove_802_11(pcap_t *p)
+{
+       int i, j;
+
+       /*
+        * Scan the list of DLT_ values and discard 802.11 values.
+        */
+       j = 0;
+       for (i = 0; i < p->dlt_count; i++) {
+               switch (p->dlt_list[i]) {
+
+               case DLT_IEEE802_11:
+               case DLT_PRISM_HEADER:
+               case DLT_AIRONET_HEADER:
+               case DLT_IEEE802_11_RADIO:
+               case DLT_IEEE802_11_RADIO_AVS:
+                       /*
+                        * 802.11.  Don't offer this one.
+                        */
+                       continue;
+
+               default:
+                       /*
+                        * Just copy this mode over.
+                        */
+                       break;
+               }
+
+               /*
+                * Copy this DLT_ value to its new position.
+                */
+               p->dlt_list[j] = p->dlt_list[i];
+               j++;
+       }
+
+       /*
+        * Set the DLT_ count to the number of entries we copied.
+        */
+       p->dlt_count = j;
+}
+#endif /* defined(__APPLE__) && defined(BIOCGDLTLIST) */
+
 static int
 pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp)
 {
index c1027342fe7592368734e5b6c81616a7017b3397..a50d39e75d5a0c71c9c9119d022f5b392b6d429a 100644 (file)
@@ -33,7 +33,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-bt-linux.c,v 1.9.2.1 2008-02-14 23:28:00 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-bt-linux.c,v 1.9.2.2 2008-04-04 19:39:05 guy Exp $ (LBL)";
 #endif
  
 #ifdef HAVE_CONFIG_H
@@ -64,6 +64,7 @@ static const char rcsid[] _U_ =
 #define BT_CTRL_SIZE 128
 
 /* forward declaration */
+static int bt_activate(pcap_t *);
 static int bt_read_linux(pcap_t *, int , pcap_handler , u_char *);
 static int bt_inject_linux(pcap_t *, const void *, size_t);
 static int bt_setfilter_linux(pcap_t *, struct bpf_program *);
@@ -134,39 +135,41 @@ done:
        return ret;
 }
 
-pcap_t*
-bt_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errmsg)
+pcap_t *
+bt_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = bt_activate;
+       return (p);
+}
+
+static int
+bt_activate(pcap_t* handle)
 {
        struct sockaddr_hci addr;
        int opt;
-       pcap_t          *handle;
        int             dev_id;
        struct hci_filter       flt;
-           
+
        /* get bt interface id */
-       if (sscanf(bus, BT_IFACE"%d", &dev_id) != 1)
+       if (sscanf(handle->opt.source, BT_IFACE"%d", &dev_id) != 1)
        {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE,
-                       "Can't get Bluetooth bus index from %s", bus);
-               return NULL;
-       }
-       
-       /* Allocate a handle for this session. */
-       handle = malloc(sizeof(*handle));
-       if (handle == NULL) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "malloc: %s",
-                       pcap_strerror(errno));
-               return NULL;
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                       "Can't get Bluetooth device index from %s", 
+                        handle->opt.source);
+               return -1;
        }
-       
+
        /* Initialize some components of the pcap structure. */
-       memset(handle, 0, sizeof(*handle));
-       handle->snapshot        = snaplen;
-       handle->md.timeout      = to_ms;
-       handle->bufsize = snaplen+BT_CTRL_SIZE+sizeof(pcap_bluetooth_h4_header);
+       handle->bufsize = handle->snapshot+BT_CTRL_SIZE+sizeof(pcap_bluetooth_h4_header);
        handle->offset = BT_CTRL_SIZE;
        handle->linktype = DLT_BLUETOOTH_HCI_H4_WITH_PHDR;
-       
+
        handle->read_op = bt_read_linux;
        handle->inject_op = bt_inject_linux;
        handle->setfilter_op = bt_setfilter_linux;
@@ -181,46 +184,41 @@ bt_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errmsg
        /* Create HCI socket */
        handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
        if (handle->fd < 0) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s",
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s",
                        errno, strerror(errno));
-               free(handle);
-               return NULL;
+               return -1;
        }
 
        handle->buffer = malloc(handle->bufsize);
        if (!handle->buffer) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s",
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s",
                        pcap_strerror(errno));
-               pcap_close(handle);
-               return NULL;
+               goto close_fail;
        }
 
        opt = 1;
        if (setsockopt(handle->fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't enable data direction info %d:%s",
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't enable data direction info %d:%s",
                        errno, strerror(errno));
-               pcap_close(handle);
-               return NULL;
+               goto close_fail;
        }
 
        opt = 1;
        if (setsockopt(handle->fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't enable time stamp %d:%s",
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't enable time stamp %d:%s",
                        errno, strerror(errno));
-               pcap_close(handle);
-               return NULL;
+               goto close_fail;
        }
-       
+
        /* Setup filter, do not call hci function to avoid dependence on 
         * external libs        */
        memset(&flt, 0, sizeof(flt));
        memset((void *) &flt.type_mask, 0xff, sizeof(flt.type_mask));   
        memset((void *) &flt.event_mask, 0xff, sizeof(flt.event_mask));
        if (setsockopt(handle->fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't set filter %d:%s",
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't set filter %d:%s",
                        errno, strerror(errno));
-               pcap_close(handle);
-               return NULL;
+               goto close_fail;
        }
 
 
@@ -228,14 +226,16 @@ bt_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errmsg
        addr.hci_family = AF_BLUETOOTH;
        addr.hci_dev = handle->md.ifindex;
        if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "Can't attach to device %d %d:%s",
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't attach to device %d %d:%s",
                        handle->md.ifindex, errno, strerror(errno));
-               pcap_close(handle);
-               return NULL;
+               goto close_fail;
        }
-       handle->selectable_fd = handle->fd;     
-       
-       return handle;  
+       handle->selectable_fd = handle->fd;
+       return 0;
+
+close_fail:
+       close(handle->fd);
+       return -1;
 }
 
 static int
diff --git a/pcap-bt-linux.h b/pcap-bt-linux.h
new file mode 100644 (file)
index 0000000..87d22a6
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006 Paolo Abeni (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote 
+ * products derived from this software without specific prior written 
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Bluetooth sniffing API implementation for Linux platform
+ * By Paolo Abeni <[email protected]>
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-bt-linux.h,v 1.4.2.1 2008-04-04 19:39:05 guy Exp $ (LBL)
+ */
+
+/*
+ * Prototypes for Bluetooth-related functions
+ */
+int bt_platform_finddevs(pcap_if_t **alldevsp, char *err_str);
+pcap_t *bt_create(const char *device, char *ebuf);
index 3c1b4377a41172fea94b530434f46f93ad81f765..83684b5671d096ad79c04c664e3a2156b44abaf5 100644 (file)
@@ -17,7 +17,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-       "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.31.2.5 2008-02-02 20:42:57 guy Exp $ (LBL)";
+       "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.31.2.6 2008-04-04 19:39:05 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -87,7 +87,7 @@ static const unsigned short endian_test_word = 0x0100;
 /* This code is required when compiling for a DAG device only. */
 
 /* Replace dag function names with pcap equivalent. */
-#define dag_open_live pcap_open_live
+#define dag_create pcap_create
 #define dag_platform_finddevs pcap_platform_finddevs
 #endif /* DAG_ONLY */
 
@@ -564,21 +564,20 @@ dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
  *  not supported in hardware.
  *  
  *  snaplen is now also ignored, until we get per-stream slen support. Set
- *  slen with approprite DAG tool BEFORE pcap_open_live().
+ *  slen with approprite DAG tool BEFORE pcap_activate().
  *
  *  See also pcap(3).
  */
-pcap_t *
-dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+static int dag_activate(pcap_t* handle)
 {
 #if 0
        char conf[30]; /* dag configure string */
 #endif
-       pcap_t *handle;
        char *s;
        int n;
        daginf_t* daginf;
        char * newDev = NULL;
+       char * device = handle->opt.source;
 #ifdef HAVE_DAG_STREAMS_API
        uint32_t mindata;
        struct timeval maxwait;
@@ -586,44 +585,35 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
 #endif
 
        if (device == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno));
-               return NULL;
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno));
+               return -1;
        }
-       /* Allocate a handle for this session. */
 
-       handle = malloc(sizeof(*handle));
-       if (handle == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc %s: %s", device, pcap_strerror(errno));
-               return NULL;
-       }
-       
        /* Initialize some components of the pcap structure. */
-       
-       memset(handle, 0, sizeof(*handle));
 
 #ifdef HAVE_DAG_STREAMS_API
        newDev = (char *)malloc(strlen(device) + 16);
        if (newDev == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno));
                goto fail;
        }
        
        /* Parse input name to get dag device and stream number if provided */
        if (dag_parse_name(device, newDev, strlen(device) + 16, &handle->md.dag_stream) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_parse_name: %s\n", pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: %s\n", pcap_strerror(errno));
                goto fail;
        }
        device = newDev;
 
        if (handle->md.dag_stream%2) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture\n");
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture\n");
                goto fail;
        }
 #else
        if (strncmp(device, "/dev/", 5) != 0) {
                newDev = (char *)malloc(strlen(device) + 5);
                if (newDev == NULL) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno));
+                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno));
                        goto fail;
                }
                strcpy(newDev, "/dev/");
@@ -634,14 +624,14 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
 
        /* setup device parameters */
        if((handle->fd = dag_open((char *)device)) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno));
                goto fail;
        }
 
 #ifdef HAVE_DAG_STREAMS_API
        /* Open requested stream. Can fail if already locked or on error */
        if (dag_attach_stream(handle->fd, handle->md.dag_stream, 0, 0) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s\n", pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s\n", pcap_strerror(errno));
                goto failclose;
        }
 
@@ -650,7 +640,7 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
         */
        if (dag_get_stream_poll(handle->fd, handle->md.dag_stream,
                                &mindata, &maxwait, &poll) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno));
                goto faildetach;
        }
        
@@ -668,13 +658,13 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
 
        if (dag_set_stream_poll(handle->fd, handle->md.dag_stream,
                                mindata, &maxwait, &poll) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno));
                goto faildetach;
        }
                
 #else
        if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno));
                goto failclose;
        }
 
@@ -688,28 +678,28 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
        /* set the card snap length to the specified snaplen parameter */
        /* This is a really bad idea, as different cards have different
         * valid slen ranges. Should fix in Config API. */
-       if (snaplen == 0 || snaplen > MAX_DAG_SNAPLEN) {
-               snaplen = MAX_DAG_SNAPLEN;
+       if (handle->snapshot == 0 || handle->snapshot > MAX_DAG_SNAPLEN) {
+               handle->snapshot = MAX_DAG_SNAPLEN;
        } else if (snaplen < MIN_DAG_SNAPLEN) {
-               snaplen = MIN_DAG_SNAPLEN;
+               handle->snapshot = MIN_DAG_SNAPLEN;
        }
        /* snap len has to be a multiple of 4 */
        snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); 
 
        if(dag_configure(handle->fd, conf) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno));
                goto faildetach;
        }
 #endif 
        
 #ifdef HAVE_DAG_STREAMS_API
        if(dag_start_stream(handle->fd, handle->md.dag_stream) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s\n", device, pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s\n", device, pcap_strerror(errno));
                goto faildetach;
        }
 #else
        if(dag_start(handle->fd) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno));
                goto failclose;
        }
 #endif /* HAVE_DAG_STREAMS_API */
@@ -745,7 +735,7 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
                                handle->md.dag_fcs_bits = n;
                        } else {
                                snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                       "pcap_open_live %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n);
+                                       "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n);
                                goto failstop;
                        }
                }
@@ -763,19 +753,16 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
                }
        }
 
-       handle->snapshot        = snaplen;
-       handle->md.dag_timeout  = to_ms;
+       handle->md.dag_timeout  = handle->md.timeout;
 
        handle->linktype = -1;
-       if (dag_get_datalink(handle) < 0) {
-               strcpy(ebuf, handle->errbuf);
+       if (dag_get_datalink(handle) < 0)
                goto failstop;
-       }
        
        handle->bufsize = 0;
 
        if (new_pcap_dag(handle) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno));
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno));
                goto failstop;
        }
 
@@ -799,51 +786,46 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
        handle->close_op = dag_platform_close;
        handle->md.stat.ps_drop = 0;
        handle->md.stat.ps_recv = 0;
-       return handle;
+       return 0;
 
 #ifdef HAVE_DAG_STREAMS_API 
 failstop:
-       if (handle != NULL) {
-               if (dag_stop_stream(handle->fd, handle->md.dag_stream) < 0)
-                       fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno));
+       if (dag_stop_stream(handle->fd, handle->md.dag_stream) < 0)
+               fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno));
        }
        
 faildetach:
-       if (handle != NULL) {
-               if (dag_detach_stream(handle->fd, handle->md.dag_stream) < 0)
-                       fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno));
-       }
-#else  
+       if (dag_detach_stream(handle->fd, handle->md.dag_stream) < 0)
+               fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno));
+#else
 failstop:
-       if (handle != NULL) {
-               if (dag_stop(handle->fd) < 0)
-                       fprintf(stderr,"dag_stop: %s\n", strerror(errno));
-       }
+       if (dag_stop(handle->fd) < 0)
+               fprintf(stderr,"dag_stop: %s\n", strerror(errno));
 #endif /* HAVE_DAG_STREAMS_API */
        
 failclose:
-       if (handle != NULL) {
-               if (dag_close(handle->fd) < 0)
-                       fprintf(stderr,"dag_close: %s\n", strerror(errno));
-       }
-       if (handle != NULL)
-               delete_pcap_dag(handle);
-       
+       if (dag_close(handle->fd) < 0)
+               fprintf(stderr,"dag_close: %s\n", strerror(errno));
+       delete_pcap_dag(handle);
+
 fail:
        if (newDev != NULL) {
                free((char *)newDev);
        }
-       if (handle != NULL) {
-               /*
-                * Get rid of any link-layer type list we allocated.
-                */
-               if (handle->dlt_list != NULL) {
-                       free(handle->dlt_list);
-               }
-               free(handle);
-       }
 
-       return NULL;
+       return PCAP_ERROR;
+}
+
+pcap_t *dag_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return NULL;
+
+       p->activate_op = dag_activate;
+       return p;
 }
 
 static int
index 738f21296f951411f50ffc3ad501c1de843d7f6c..7ba272bec340946de86f9839ad64edbd99de72b9 100644 (file)
@@ -7,10 +7,10 @@
  *
  * Author: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com)
  *
- * @(#) $Header: /tcpdump/master/libpcap/pcap-dag.h,v 1.4.2.2 2007-11-09 00:58:46 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-dag.h,v 1.4.2.3 2008-04-04 19:39:06 guy Exp $ (LBL)
  */
 
-pcap_t *dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf);
+pcap_t *dag_create(const char *, char *);
 int dag_platform_finddevs(pcap_if_t **devlistp, char *errbuf);
 
 #ifndef TYPE_AAL5
index 0c4cafb2ce589c52c8a2f07aa16fee7a27f5e6b4..e782fe07c51caebfacaf0ec88364a4495a07ec85 100644 (file)
@@ -70,7 +70,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.116.2.4 2008-03-13 18:16:37 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.116.2.5 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -321,12 +321,10 @@ pcap_close_dlpi(pcap_t *p)
                close(p->send_fd);
 }
 
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+static int
+pcap_activate_dlpi(pcap_t *p)
 {
        register char *cp;
-       register pcap_t *p;
        int ppa;
 #ifdef HAVE_SOLARIS
        int isatm = 0;
@@ -345,12 +343,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        char dname2[100];
 #endif
 
-       p = (pcap_t *)malloc(sizeof(*p));
-       if (p == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
-               return (NULL);
+       if (p->opt.rfmon) {
+               /*
+                * No monitor mode on any platforms that support DLPI.
+                */
+               return (PCAP_ERROR_RFMON_NOTSUP);
        }
-       memset(p, 0, sizeof(*p));
+
        p->fd = -1;     /* indicate that it hasn't been opened yet */
        p->send_fd = -1;
 
@@ -358,9 +357,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        /*
        ** Remove any "/dev/" on the front of the device.
        */
-       cp = strrchr(device, '/');
+       cp = strrchr(p->opt.source, '/');
        if (cp == NULL)
-               strlcpy(dname, device, sizeof(dname));
+               strlcpy(dname, p->opt.source, sizeof(dname));
        else
                strlcpy(dname, cp + 1, sizeof(dname));
 
@@ -368,7 +367,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * Split the device name into a device type name and a unit number;
         * chop off the unit number, so "dname" is just a device type name.
         */
-       cp = split_dname(dname, &ppa, ebuf);
+       cp = split_dname(dname, &ppa, p->errbuf);
        if (cp == NULL)
                goto bad;
        *cp = '\0';
@@ -386,7 +385,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         */
        cp = "/dev/dlpi";
        if ((p->fd = open(cp, O_RDWR)) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "%s: %s", cp, pcap_strerror(errno));
                goto bad;
        }
@@ -410,7 +409,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * Get a table of all PPAs for that device, and search that
         * table for the specified device type name and unit number.
         */
-       ppa = get_dlpi_ppa(p->fd, dname, ppa, ebuf);
+       ppa = get_dlpi_ppa(p->fd, dname, ppa, p->errbuf);
        if (ppa < 0)
                goto bad;
 #else
@@ -420,17 +419,17 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * otherwise, concatenate the device directory name and the
         * device name.
         */
-       if (*device == '/')
-               strlcpy(dname, device, sizeof(dname));
+       if (*p->opt.source == '/')
+               strlcpy(dname, p->opt.source, sizeof(dname));
        else
                snprintf(dname, sizeof(dname), "%s/%s", PCAP_DEV_PREFIX,
-                   device);
+                   p->opt.source);
 
        /*
         * Get the unit number, and a pointer to the end of the device
         * type name.
         */
-       cp = split_dname(dname, &ppa, ebuf);
+       cp = split_dname(dname, &ppa, p->errbuf);
        if (cp == NULL)
                goto bad;
 
@@ -444,7 +443,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        /* Try device without unit number */
        if ((p->fd = open(dname, O_RDWR)) < 0) {
                if (errno != ENOENT) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dname,
                            pcap_strerror(errno));
                        goto bad;
                }
@@ -467,10 +466,10 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                                 * for the loopback interface is just a
                                 * symptom of that inability.
                                 */
-                               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                                    "%s: No DLPI device found", device);
                        } else {
-                               snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s",
+                               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
                                    dname2, pcap_strerror(errno));
                        }
                        goto bad;
@@ -480,13 +479,11 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        }
 #endif
 
-       p->snapshot = snaplen;
-
        /*
        ** Attach if "style 2" provider
        */
-       if (dlinforeq(p->fd, ebuf) < 0 ||
-           dlinfoack(p->fd, (char *)buf, ebuf) < 0)
+       if (dlinforeq(p->fd, p->errbuf) < 0 ||
+           dlinfoack(p->fd, (char *)buf, p->errbuf) < 0)
                goto bad;
        infop = &((union DL_primitives *)buf)->info_ack;
 #ifdef HAVE_SOLARIS
@@ -494,11 +491,11 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                isatm = 1;
 #endif
        if (infop->dl_provider_style == DL_STYLE2) {
-               if (dl_doattach(p->fd, ppa, ebuf) < 0)
+               if (dl_doattach(p->fd, ppa, p->errbuf) < 0)
                        goto bad;
 #ifdef DL_HP_RAWDLS
                if (p->send_fd >= 0) {
-                       if (dl_doattach(p->send_fd, ppa, ebuf) < 0)
+                       if (dl_doattach(p->send_fd, ppa, p->errbuf) < 0)
                                goto bad;
                }
 #endif
@@ -535,15 +532,15 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        ** assume the SAP value in a DLPI bind is an LLC SAP for network
        ** types that use 802.2 LLC).
        */
-       if ((dlbindreq(p->fd, 1537, ebuf) < 0 &&
-            dlbindreq(p->fd, 2, ebuf) < 0) ||
-            dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0)
+       if ((dlbindreq(p->fd, 1537, p->errbuf) < 0 &&
+            dlbindreq(p->fd, 2, p->errbuf) < 0) ||
+            dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0)
                goto bad;
 #elif defined(DL_HP_RAWDLS)
        /*
        ** HP-UX 10.0x and 10.1x.
        */
-       if (dl_dohpuxbind(p->fd, ebuf) < 0)
+       if (dl_dohpuxbind(p->fd, p->errbuf) < 0)
                goto bad;
        if (p->send_fd >= 0) {
                /*
@@ -551,7 +548,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                ** set it to -1, so that you can't send but can
                ** still receive?
                */
-               if (dl_dohpuxbind(p->send_fd, ebuf) < 0)
+               if (dl_dohpuxbind(p->send_fd, p->errbuf) < 0)
                        goto bad;
        }
 #else /* neither AIX nor HP-UX */
@@ -559,8 +556,8 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        ** Not Sinix, and neither AIX nor HP-UX - Solaris, and any other
        ** OS using DLPI.
        **/
-       if (dlbindreq(p->fd, 0, ebuf) < 0 ||
-           dlbindack(p->fd, (char *)buf, ebuf, NULL) < 0)
+       if (dlbindreq(p->fd, 0, p->errbuf) < 0 ||
+           dlbindack(p->fd, (char *)buf, p->errbuf, NULL) < 0)
                goto bad;
 #endif /* AIX vs. HP-UX vs. other */
 #endif /* !HP-UX 9 and !HP-UX 10.20 or later and !SINIX */
@@ -574,18 +571,18 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                ** help, and may break things.
                */
                if (strioctl(p->fd, A_PROMISCON_REQ, 0, NULL) < 0) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "A_PROMISCON_REQ: %s",
-                           pcap_strerror(errno));
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                           "A_PROMISCON_REQ: %s", pcap_strerror(errno));
                        goto bad;
                }
        } else
 #endif
-       if (promisc) {
+       if (p->opt.promisc) {
                /*
                ** Enable promiscuous (not necessary on send FD)
                */
-               if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, ebuf) < 0 ||
-                   dlokack(p->fd, "promisc_phys", (char *)buf, ebuf) < 0)
+               if (dlpromisconreq(p->fd, DL_PROMISC_PHYS, p->errbuf) < 0 ||
+                   dlokack(p->fd, "promisc_phys", (char *)buf, p->errbuf) < 0)
                        goto bad;
 
                /*
@@ -594,10 +591,11 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                ** HP-UX or SINIX) (Not necessary on send FD)
                */
 #if !defined(__hpux) && !defined(sinix)
-               if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, ebuf) < 0 ||
-                   dlokack(p->fd, "promisc_multi", (char *)buf, ebuf) < 0)
+               if (dlpromisconreq(p->fd, DL_PROMISC_MULTI, p->errbuf) < 0 ||
+                   dlokack(p->fd, "promisc_multi", (char *)buf, p->errbuf) < 0)
                        fprintf(stderr,
-                           "WARNING: DL_PROMISC_MULTI failed (%s)\n", ebuf);
+                           "WARNING: DL_PROMISC_MULTI failed (%s)\n",
+                           p->errbuf);
 #endif
        }
        /*
@@ -608,17 +606,17 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
 #ifndef sinix
        if (
 #ifdef __hpux
-           !promisc &&
+           !p->opt.promisc &&
 #endif
 #ifdef HAVE_SOLARIS
            !isatm &&
 #endif
-           (dlpromisconreq(p->fd, DL_PROMISC_SAP, ebuf) < 0 ||
-           dlokack(p->fd, "promisc_sap", (char *)buf, ebuf) < 0)) {
+           (dlpromisconreq(p->fd, DL_PROMISC_SAP, p->errbuf) < 0 ||
+           dlokack(p->fd, "promisc_sap", (char *)buf, p->errbuf) < 0)) {
                /* Not fatal if promisc since the DL_PROMISC_PHYS worked */
-               if (promisc)
+               if (p->opt.promisc)
                        fprintf(stderr,
-                           "WARNING: DL_PROMISC_SAP failed (%s)\n", ebuf);
+                           "WARNING: DL_PROMISC_SAP failed (%s)\n", p->errbuf);
                else
                        goto bad;
        }
@@ -629,7 +627,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        ** promiscuous options.
        */
 #if defined(HAVE_HPUX9) || defined(HAVE_HPUX10_20_OR_LATER)
-       if (dl_dohpuxbind(p->fd, ebuf) < 0)
+       if (dl_dohpuxbind(p->fd, p->errbuf) < 0)
                goto bad;
        /*
        ** We don't set promiscuous mode on the send FD, but we'll defer
@@ -642,7 +640,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                ** set it to -1, so that you can't send but can
                ** still receive?
                */
-               if (dl_dohpuxbind(p->send_fd, ebuf) < 0)
+               if (dl_dohpuxbind(p->send_fd, p->errbuf) < 0)
                        goto bad;
        }
 #endif
@@ -652,12 +650,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        ** XXX - get SAP length and address length as well, for use
        ** when sending packets.
        */
-       if (dlinforeq(p->fd, ebuf) < 0 ||
-           dlinfoack(p->fd, (char *)buf, ebuf) < 0)
+       if (dlinforeq(p->fd, p->errbuf) < 0 ||
+           dlinfoack(p->fd, (char *)buf, p->errbuf) < 0)
                goto bad;
 
        infop = &((union DL_primitives *)buf)->info_ack;
-       if (pcap_process_mactype(p, infop->dl_mac_type, ebuf) != 0)
+       if (pcap_process_mactype(p, infop->dl_mac_type, p->errbuf) != 0)
                goto bad;
 
 #ifdef DLIOCRAW
@@ -666,13 +664,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        ** header.
        */
        if (strioctl(p->fd, DLIOCRAW, 0, NULL) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "DLIOCRAW: %s",
                    pcap_strerror(errno));
                goto bad;
        }
 #endif
 
-       ss = snaplen;
+       ss = p->snapshot;
 
        /*
        ** There is a bug in bufmod(7). When dealing with messages of
@@ -695,7 +693,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
 
 #ifdef HAVE_SYS_BUFMOD_H
        /* Push and configure bufmod. */
-       if (pcap_conf_bufmod(p, ss, to_ms, ebuf) != 0)
+       if (pcap_conf_bufmod(p, ss, p->md.timeout) != 0)
                goto bad;
 #endif
 
@@ -703,13 +701,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        ** As the last operation flush the read side.
        */
        if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
                    pcap_strerror(errno));
                goto bad;
        }
 
        /* Allocate data buffer. */
-       if (pcap_alloc_databuf(p, ebuf) != 0)
+       if (pcap_alloc_databuf(p) != 0)
                goto bad;
 
        /*
@@ -728,19 +726,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->stats_op = pcap_stats_dlpi;
        p->close_op = pcap_close_dlpi;
 
-       return (p);
+       return (0);
 bad:
        if (p->fd >= 0)
                close(p->fd);
        if (p->send_fd >= 0)
                close(p->send_fd);
-       /*
-        * Get rid of any link-layer type list we allocated.
-        */
-       if (p->dlt_list != NULL)
-               free(p->dlt_list);
-       free(p);
-       return (NULL);
+       return (PCAP_ERROR);
 }
 
 /*
@@ -1649,3 +1641,16 @@ dlpi_kread(register int fd, register off_t addr,
        return (cc);
 }
 #endif
+
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_dlpi;
+       return (p);
+}
index c20e5d838eaa62bce055f48d55797b10b702a06d..1453c35538c2ea03c1548f6e0030607d68a371b8 100644 (file)
@@ -5,7 +5,7 @@
  *  pcap-dos.c: Interface to PKTDRVR, NDIS2 and 32-bit pmode
  *              network drivers.
  *
- * @(#) $Header: /tcpdump/master/libpcap/pcap-dos.c,v 1.2.2.1 2007-12-05 23:38:11 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-dos.c,v 1.2.2.2 2008-04-04 19:39:06 guy Exp $ (LBL)
  */
 
 #include <stdio.h>
@@ -97,6 +97,7 @@ static volatile BOOL exc_occured = 0;
 
 static struct device *handle_to_device [20];
 
+static void pcap_activate_dos (pcap_t *p);
 static int  pcap_read_dos (pcap_t *p, int cnt, pcap_handler callback,
                            u_char *data);
 static void pcap_close_dos (pcap_t *p);
@@ -142,59 +143,68 @@ static struct device *get_device (int fd)
   return handle_to_device [fd-1];
 }
 
+pcap_t *pcap_create (const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_dos;
+       return (p);
+}
+
 /*
  * Open MAC-driver with name 'device_name' for live capture of
  * network packets.
  */
-pcap_t *pcap_open_live (const char *device_name, int snaplen, int promisc,
-                        int timeout_ms, char *errbuf)
+static int pcap_activate_dos (pcap_t *pcap)
 { 
-  struct pcap *pcap;
+  int err = 0;
 
-  if (snaplen < ETH_MIN)
-      snaplen = ETH_MIN;
+  if (p->opt.rfmon) {
+    /*
+     * No monitor mode on DOS.
+     */
+    return (PCAP_ERROR_RFMON_NOTSUP);
+  }
 
-  if (snaplen > ETH_MAX)   /* silently accept and truncate large MTUs */
-      snaplen = ETH_MAX;
+  if (pcap->snapshot < ETH_MIN+8)
+      pcap->snapshot = ETH_MIN+8;
 
-  pcap = calloc (sizeof(*pcap), 1);
-  if (!pcap)
-  {
-    strcpy (errbuf, "Not enough memory (pcap)");
-    return (NULL);
-  }
+  if (pcap->snapshot > ETH_MAX)   /* silently accept and truncate large MTUs */
+      pcap->snapshot = ETH_MAX;
 
-  pcap->snapshot          = max (ETH_MIN+8, snaplen);
   pcap->linktype          = DLT_EN10MB;  /* !! */
-  pcap->inter_packet_wait = timeout_ms;
   pcap->close_op          = pcap_close_dos;
   pcap->read_op           = pcap_read_dos;
   pcap->stats_op          = pcap_stats_dos;
   pcap->inject_op         = pcap_sendpacket_dos;
   pcap->setfilter_op      = pcap_setfilter_dos;
-       pcap->setdirection_op   = NULL; /* Not implemented.*/
+  pcap->setdirection_op   = NULL; /* Not implemented.*/
   pcap->fd                = ++ref_count;
 
   if (pcap->fd == 1)  /* first time we're called */
   {
-    if (!init_watt32(pcap, device_name, errbuf) ||
-        !first_init(device_name, errbuf, promisc))
+    if (!init_watt32(pcap, pcap->md.device, pcap->errbuf) ||
+        !first_init(pcap->md.device, pcap->errbuf, pcap->opt.promisc))
     {
       free (pcap);
-      return (NULL);
+      return (PCAP_ERROR);
     } 
     atexit (close_driver);
   }
-  else if (stricmp(active_dev->name,device_name))
+  else if (stricmp(active_dev->name,pcap->md.device))
   {
-    snprintf (errbuf, PCAP_ERRBUF_SIZE,
+    snprintf (pcap->errbuf, PCAP_ERRBUF_SIZE,
               "Cannot use different devices simultaneously "
-              "(`%s' vs. `%s')", active_dev->name, device_name);
+              "(`%s' vs. `%s')", active_dev->name, pcap->md.device);
     free (pcap);
-    pcap = NULL;
+    err = PCAP_ERROR;
   }
   handle_to_device [pcap->fd-1] = active_dev;
-  return (pcap);
+  return (err);
 }
 
 /*
@@ -209,10 +219,10 @@ pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data)
   BYTE  *rx_buf;
   int    rx_len = 0;
 
-  if (p->inter_packet_wait > 0)
+  if (p->md.timeout > 0)
   {
     gettimeofday2 (&now, NULL);
-    expiry.tv_usec = now.tv_usec + 1000UL * p->inter_packet_wait;
+    expiry.tv_usec = now.tv_usec + 1000UL * p->md.timeout;
     expiry.tv_sec  = now.tv_sec;
     while (expiry.tv_usec >= 1000000L)
     {
@@ -284,7 +294,7 @@ pcap_read_one (pcap_t *p, pcap_handler callback, u_char *data)
     /* If not to wait for a packet or pcap_close() called from
      * e.g. SIGINT handler, exit loop now.
      */
-    if (p->inter_packet_wait <= 0 || (volatile int)p->fd <= 0)
+    if (p->md.timeout <= 0 || (volatile int)p->fd <= 0)
        break;
 
     gettimeofday2 (&now, NULL);
@@ -476,7 +486,7 @@ int pcap_lookupnet (const char *device, bpf_u_int32 *localnet,
 {
   if (!_watt_is_init)
   {
-    strcpy (errbuf, "pcap_open_offline() or pcap_open_live() must be "
+    strcpy (errbuf, "pcap_open_offline() or pcap_activate() must be "
                     "called first");
     return (-1);
   }
@@ -587,7 +597,7 @@ void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait)
   if (p)
   {
     p->wait_proc         = yield;
-    p->inter_packet_wait = wait;
+    p->md.timeout        = wait;
   }
 }
 
@@ -739,7 +749,7 @@ static void exc_handler (int sig)
 
 
 /*
- * Open the pcap device for the first client calling pcap_open_live()
+ * Open the pcap device for the first client calling pcap_activate()
  */
 static int first_init (const char *name, char *ebuf, int promisc)
 {
index 038797e9e7a3556a641f68b4b9198e1899e9ab4c..222ef89d3b4bb9414ee0e2326295a7600e032d52 100644 (file)
@@ -30,7 +30,7 @@
  * 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.85.2.3 2008-03-13 18:16:37 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.85.2.4 2008-04-04 19:39:06 guy Exp $ (LBL)
  */
 
 #ifndef pcap_int_h
@@ -96,6 +96,9 @@ typedef enum {
        MAYBE_SWAPPED
 } swapped_type_t;
 
+/*
+ * Used when reading a savefile.
+ */
 struct pcap_sf {
        FILE *rfile;
        int swapped;
@@ -106,6 +109,9 @@ struct pcap_sf {
        u_char *base;
 };
 
+/*
+ * Used when doing a live capture.
+ */
 struct pcap_md {
        struct pcap_stat stat;
        /*XXX*/
@@ -116,18 +122,17 @@ struct pcap_md {
        long    TotMissed;      /* missed by i/f during this run */
        long    OrigMissed;     /* missed by i/f before this run */
        char    *device;        /* device name */
+       int     timeout;        /* timeout for buffering */
+       int     must_clear;     /* stuff we must clear when we close */
+       struct pcap *next;      /* list of open pcaps that need stuff cleared on close */
 #ifdef linux
        int     sock_packet;    /* using Linux 2.0 compatible interface */
        int     cooked;         /* using SOCK_DGRAM rather than SOCK_RAW */
        int     ifindex;        /* interface index of device we're bound to */
        int     lo_ifindex;     /* interface index of the loopback device */
-       struct pcap *next;      /* list of open promiscuous sock_packet pcaps */
        u_int   packets_read;   /* count of packets read with recvfrom() */
+       bpf_u_int32 oldmode;    /* mode to restore when turning monitor mode off */
 #endif /* linux */
-#if defined(linux) || defined(SITA)
-       int     timeout;        /* timeout specified to pcap_open_live */
-       int     clear_promisc;  /* must clear promiscuous mode when we close */
-#endif /* linux || SITA */
 
 #ifdef HAVE_DAG_API
 #ifdef HAVE_DAG_STREAMS_API
@@ -147,6 +152,19 @@ struct pcap_md {
 #endif /* HAVE_DAG_API */
 };
 
+/*
+ * Stuff to clear when we close.
+ */
+#define MUST_CLEAR_PROMISC     0x00000001      /* promiscuous mode */
+#define MUST_CLEAR_RFMON       0x00000002      /* rfmon (monitor) mode */
+
+struct pcap_opt {
+       int     buffer_size;
+       char    *source;
+       int     promisc;
+       int     rfmon;
+};
+
 /*
  * Ultrix, DEC OSF/1^H^H^H^H^H^H^H^H^HDigital UNIX^H^H^H^H^H^H^H^H^H^H^H^H
  * Tru64 UNIX, and some versions of NetBSD pad FDDI packets to make everything
@@ -160,11 +178,27 @@ struct pcap_md {
 #define       PCAP_FDDIPAD 3
 #endif
 
+typedef int    (*activate_op_t)(pcap_t *);
+typedef int    (*can_set_rfmon_op_t)(pcap_t *);
+typedef int    (*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *);
+typedef int    (*inject_op_t)(pcap_t *, const void *, size_t);
+typedef int    (*setfilter_op_t)(pcap_t *, struct bpf_program *);
+typedef int    (*setdirection_op_t)(pcap_t *, pcap_direction_t);
+typedef int    (*set_datalink_op_t)(pcap_t *, int);
+typedef int    (*getnonblock_op_t)(pcap_t *, char *);
+typedef int    (*setnonblock_op_t)(pcap_t *, int, char *);
+typedef int    (*stats_op_t)(pcap_t *, struct pcap_stat *);
+#ifdef WIN32
+typedef int    (*setbuff_op_t)(pcap_t *, int);
+typedef int    (*setmode_op_t)(pcap_t *, int);
+typedef int    (*setmintocopy_op_t)(pcap_t *, int);
+#endif
+typedef void   (*close_op_t)(pcap_t *);
+
 struct pcap {
 #ifdef WIN32
        ADAPTER *adapter;
        LPPACKET Packet;
-       int timeout;
        int nonblock;
 #else
        int fd;
@@ -180,6 +214,8 @@ struct pcap {
        int linktype_ext;       /* Extended information stored in the linktype field of a file */
        int tzoff;              /* timezone offset */
        int offset;             /* offset for proper alignment */
+       int activated;          /* true if the capture is really started */
+       int oldstyle;           /* if we're opening with pcap_open_live() */
 
        int break_loop;         /* flag set to force break from packet-reading loop */
 
@@ -188,12 +224,12 @@ struct pcap {
 #endif
 
 #ifdef MSDOS
-        int inter_packet_wait;   /* offline: wait between packets */
         void (*wait_proc)(void); /*          call proc while waiting */
 #endif
 
        struct pcap_sf sf;
        struct pcap_md md;
+       struct pcap_opt opt;
 
        /*
         * Read buffer.
@@ -214,30 +250,27 @@ struct pcap {
        /*
         * Methods.
         */
-       int     (*read_op)(pcap_t *, int cnt, pcap_handler, u_char *);
-       int     (*inject_op)(pcap_t *, const void *, size_t);
-       int     (*setfilter_op)(pcap_t *, struct bpf_program *);
-       int     (*setdirection_op)(pcap_t *, pcap_direction_t);
-       int     (*set_datalink_op)(pcap_t *, int);
-       int     (*getnonblock_op)(pcap_t *, char *);
-       int     (*setnonblock_op)(pcap_t *, int, char *);
-       int     (*stats_op)(pcap_t *, struct pcap_stat *);
-#ifdef WIN32
-       /*
-        * Win32-only; given the way the buffer size is set with BPF,
-        * to make this cross-platform we'll have to set the buffer
-        * size at open time.
-        */
-       int     (*setbuff_op)(pcap_t *, int);
+       activate_op_t activate_op;
+       can_set_rfmon_op_t can_set_rfmon_op;
+       read_op_t read_op;
+       inject_op_t inject_op;
+       setfilter_op_t setfilter_op;
+       setdirection_op_t setdirection_op;
+       set_datalink_op_t set_datalink_op;
+       getnonblock_op_t getnonblock_op;
+       setnonblock_op_t setnonblock_op;
+       stats_op_t stats_op;
 
+#ifdef WIN32
        /*
         * These are, at least currently, specific to the Win32 NPF
         * driver.
         */
-       int     (*setmode_op)(pcap_t *, int);
-       int     (*setmintocopy_op)(pcap_t *, int);
+       setbuff_op_t setbuff_op;
+       setmode_op_t setmode_op;
+       setmintocopy_op_t setmintocopy_op;
 #endif
-       void    (*close_op)(pcap_t *);
+       close_op_t close_op;
 
        /*
         * Placeholder for filter code if bpf not in kernel.
@@ -354,7 +387,13 @@ int        pcap_getnonblock_fd(pcap_t *, char *);
 int    pcap_setnonblock_fd(pcap_t *p, int, char *);
 #endif
 
+pcap_t *pcap_create_common(const char *, char *);
+int    pcap_do_addexit(pcap_t *);
+void   pcap_add_to_pcaps_to_close(pcap_t *);
+void   pcap_remove_from_pcaps_to_close(pcap_t *);
 void   pcap_close_common(pcap_t *);
+int    pcap_not_initialized(pcap_t *);
+int    pcap_check_activated(pcap_t *);
 
 /*
  * Internal interfaces for "pcap_findalldevs()".
index 8fab98be606c50210a8a9575d97efc6382841615..5d0458de571f53d58362b2df6d2ead821e84316e 100644 (file)
@@ -26,7 +26,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-       "@(#) $Header: /tcpdump/master/libpcap/pcap-libdlpi.c,v 1.1.2.3 2008-03-15 04:26:29 guy Exp $ (LBL)";
+       "@(#) $Header: /tcpdump/master/libpcap/pcap-libdlpi.c,v 1.1.2.4 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -96,57 +96,54 @@ list_interfaces(const char *linkname, void *arg)
        return (B_FALSE);
 }
 
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+static int
+pcap_activate_libdlpi(pcap_t *p)
 {
        int retv;
-       pcap_t *p;
        dlpi_handle_t dh;
        dlpi_info_t dlinfo;
 
-       if ((p = (pcap_t *)malloc(sizeof(*p))) == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
-               return (NULL);
+       if (p->opt.rfmon) {
+               /*
+                * No monitor mode on any platforms that support DLPI.
+                */
+               return (PCAP_ERROR_RFMON_NOTSUP);
        }
-       memset(p, 0, sizeof(*p));
+
        p->fd = -1;     /* indicate that it hasn't been opened yet */
-       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);
+       retv = dlpi_open(p->opt.source, &dh, DLPI_RAW|DLPI_PASSIVE);
        if (retv != DLPI_SUCCESS) {
-               pcap_libdlpi_err(device, "dlpi_open", retv, ebuf);
+               pcap_libdlpi_err(p->opt.source, "dlpi_open", retv, p->errbuf);
                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);
+               pcap_libdlpi_err(p->opt.source, "dlpi_bind", retv, p->errbuf);
                goto bad;
        }
 
        /* Enable promiscuous mode. */
-       if (promisc) {
+       if (p->opt.promisc) {
                retv = dlpi_promiscon(p->dlpi_hd, DL_PROMISC_PHYS);
                if (retv != DLPI_SUCCESS) {
-                       pcap_libdlpi_err(device, "dlpi_promisc(PHYSICAL)",
-                           retv, ebuf);
+                       pcap_libdlpi_err(p->opt.source,
+                           "dlpi_promisc(PHYSICAL)", retv, p->errbuf);
                        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);
+                       pcap_libdlpi_err(p->opt.source, "dlpi_promisc(MULTI)",
+                           retv, p->errbuf);
                        goto bad;
                }
        }
@@ -154,42 +151,42 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        /* 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);
+                       pcap_libdlpi_err(p->opt.source, "dlpi_promisc(SAP)",
+                           retv, p->errbuf);
                        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));
+                   " %s:(%s)\n", p->opt.source, 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);
+               pcap_libdlpi_err(p->opt.source, "dlpi_info", retv, p->errbuf);
                goto bad;
        }
 
-       if (pcap_process_mactype(p, dlinfo.di_mactype, ebuf) != 0)
+       if (pcap_process_mactype(p, dlinfo.di_mactype) != 0)
                goto bad;
 
        p->fd = dlpi_fd(p->dlpi_hd);
 
        /* Push and configure bufmod. */
-       if (pcap_conf_bufmod(p, snaplen, to_ms, ebuf) != 0)
+       if (pcap_conf_bufmod(p, snaplen, p->md.timeout) != 0)
                goto bad;
 
        /*
         * Flush the read side.
         */
        if (ioctl(p->fd, I_FLUSH, FLUSHR) != 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "FLUSHR: %s",
                    pcap_strerror(errno));
                goto bad;
        }
 
        /* Allocate data buffer. */
-       if (pcap_alloc_databuf(p, ebuf) != 0)
+       if (pcap_alloc_databuf(p) != 0)
                goto bad;
 
        /*
@@ -208,14 +205,13 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->stats_op = pcap_stats_dlpi;
        p->close_op = pcap_close_libdlpi;
 
-       return (p);
+       return (0);
 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);
+       dlpi_close(p->dlpi_hd);
+       return (PCAP_ERROR);
 }
 
 /*
@@ -352,3 +348,16 @@ 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));
 }
+
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_libdlpi;
+       return (p);
+}
index 70c889e6670eb06ea24d4346ce832a624e6f952b..9a9244b572e3e92d2d7f475a18949c3a0695fe06 100644 (file)
@@ -34,7 +34,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.129.2.10 2008-03-14 09:13:33 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.129.2.11 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 /*
@@ -84,6 +84,28 @@ static const char rcsid[] _U_ =
 #include "config.h"
 #endif
 
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <sys/mman.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/if_ether.h>
+#include <net/if_arp.h>
+#include <poll.h>
+
+/*
+ * Got Wireless Extensions?
+ */
+#ifdef HAVE_LINUX_WIRELESS_H
+#include <linux/wireless.h>
+#endif
+
 #include "pcap-int.h"
 #include "pcap/sll.h"
 
@@ -103,21 +125,6 @@ static const char rcsid[] _U_ =
 #include "pcap-bt-linux.h"
 #endif
 
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/utsname.h>
-#include <sys/mman.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <linux/if_ether.h>
-#include <net/if_arp.h>
-#include <poll.h>
-
 /*
  * If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET
  * sockets rather than SOCK_PACKET sockets.
@@ -210,15 +217,17 @@ typedef int               socklen_t;
 #define BIGGER_THAN_ALL_MTUS   (64*1024)
 
 /*
- * Prototypes for internal functions
+ * Prototypes for internal functions and methods.
  */
 static void map_arphrd_to_dlt(pcap_t *, int, int);
 #ifdef HAVE_PF_PACKET_SOCKETS
 static short int map_packet_type_to_sll_type(short int);
 #endif
-static int live_open_old(pcap_t *, const char *, int, int, char *);
-static int live_open_new(pcap_t *, const char *, int, int, char *);
-static int live_open_mmap(pcap_t *, char *);
+static int pcap_activate_linux(pcap_t *);
+static int activate_old(pcap_t *);
+static int activate_new(pcap_t *);
+static int activate_mmap(pcap_t *);
+static int pcap_can_set_rfmon_linux(pcap_t *);
 static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *);
 static int pcap_read_packet(pcap_t *, pcap_handler, u_char *);
 static int pcap_inject_linux(pcap_t *, const void *, size_t);
@@ -231,7 +240,7 @@ static void pcap_close_linux(pcap_t *);
 #define RING_GET_FRAME(h) (((struct tpacket_hdr**)h->buffer)[h->offset])
 
 static void destroy_ring(pcap_t *handle);
-static int create_ring(pcap_t* handle, unsigned size, char* errmsg);
+static int create_ring(pcap_t *handle);
 static void pcap_close_linux_mmap(pcap_t *);
 static int pcap_read_linux_mmap(pcap_t *, int, pcap_handler , u_char *);
 static int pcap_setfilter_linux_mmap(pcap_t *, struct bpf_program *);
@@ -249,6 +258,9 @@ static int  iface_get_mtu(int fd, const char *device, char *ebuf);
 static int     iface_get_arptype(int fd, const char *device, char *ebuf);
 #ifdef HAVE_PF_PACKET_SOCKETS
 static int     iface_bind(int fd, int ifindex, char *ebuf);
+static int     has_wext(int sock_fd, const char *device);
+static int     enter_rfmon_mode_wext(pcap_t *handle, int sock_fd,
+    const char *device);
 #endif
 static int     iface_bind_old(int fd, const char *device, char *ebuf);
 
@@ -264,62 +276,220 @@ static struct sock_fprog total_fcode
        = { 1, &total_insn };
 #endif
 
-/*
- *  Get a handle for a live capture from the given device. You can
- *  pass NULL as device to get all packages (without link level
- *  information of course). If you pass 1 as promisc the interface
- *  will be set to promiscous mode (XXX: I think this usage should
- *  be deprecated and functions be added to select that later allow
- *  modification of that values -- Torsten).
- *
- *  See also pcap(3).
- */
 pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+pcap_create(const char *device, char *ebuf)
 {
-       pcap_t          *handle;
-       int             err;
-       int             live_open_ok = 0;
+       pcap_t *handle;
 
 #ifdef HAVE_DAG_API
        if (strstr(device, "dag")) {
-               return dag_open_live(device, snaplen, promisc, to_ms, ebuf);
+               return dag_create(device, ebuf);
        }
 #endif /* HAVE_DAG_API */
 
 #ifdef HAVE_SEPTEL_API
        if (strstr(device, "septel")) {
-               return septel_open_live(device, snaplen, promisc, to_ms, ebuf);
+               return septel_create(device, ebuf);
        }
 #endif /* HAVE_SEPTEL_API */
 
 #ifdef PCAP_SUPPORT_BT
        if (strstr(device, "bluetooth")) {
-               return bt_open_live(device, snaplen, promisc, to_ms, ebuf);
+               return bt_create(device, ebuf);
        }
 #endif
 
 #ifdef PCAP_SUPPORT_USB
        if (strstr(device, "usb")) {
-               return usb_open_live(device, snaplen, promisc, to_ms, ebuf);
+               return usb_create(device, ebuf);
        }
 #endif
 
-       /* Allocate a handle for this session. */
-
-       handle = malloc(sizeof(*handle));
-       if (handle == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                        pcap_strerror(errno));
+       handle = pcap_create_common(device, ebuf);
+       if (handle == NULL)
                return NULL;
+
+       handle->activate_op = pcap_activate_linux;
+       handle->can_set_rfmon_op = pcap_can_set_rfmon_linux;
+       return handle;
+}
+
+static int
+pcap_can_set_rfmon_linux(pcap_t *p)
+{
+#ifdef IW_MODE_MONITOR
+       int sock_fd;
+       struct iwreq ireq;
+#endif
+
+       if (p->opt.source == NULL) {
+               /*
+                * This is equivalent to the "any" device, and we don't
+                * support monitor mode on it.
+                */
+               return 0;
+       }
+
+#ifdef IW_MODE_MONITOR
+       /*
+        * Bleah.  There doesn't appear to be an ioctl to use to ask
+        * whether a device supports monitor mode; we'll just do
+        * SIOCGIWMODE and, if it succeeds, assume the device supports
+        * monitor mode.
+        *
+        * Open a socket on which to attempt to get the mode.
+        * (We assume that if we have Wireless Extensions support
+        * we also have PF_PACKET support.)
+        */
+       sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       if (sock_fd == -1) {
+               (void)snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "socket: %s", pcap_strerror(errno));
+               return PCAP_ERROR;
+       }
+
+       /*
+        * Attempt to get the current mode.
+        */
+       strncpy(ireq.ifr_ifrn.ifrn_name, p->opt.source,
+           sizeof ireq.ifr_ifrn.ifrn_name);
+       ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+       if (ioctl(sock_fd, SIOCGIWMODE, &ireq) != -1) {
+               /*
+                * Well, we got the mode; assume we can set it.
+                */
+               close(sock_fd);
+               return 1;
+       }
+       if (errno == ENODEV) {
+               /* The device doesn't even exist. */
+               close(sock_fd);
+               return PCAP_ERROR_NO_SUCH_DEVICE;
+       }
+       close(sock_fd);
+#endif
+       return 0;
+}
+
+/*
+ * With older kernels promiscuous mode is kind of interesting because we
+ * have to reset the interface before exiting. The problem can't really
+ * be solved without some daemon taking care of managing usage counts.
+ * If we put the interface into promiscuous mode, we set a flag indicating
+ * that we must take it out of that mode when the interface is closed,
+ * and, when closing the interface, if that flag is set we take it out
+ * of promiscuous mode.
+ *
+ * Even with newer kernels, we have the same issue with rfmon mode.
+ */
+
+static void    pcap_close_linux( pcap_t *handle )
+{
+       struct ifreq    ifr;
+#ifdef IW_MODE_MONITOR
+       struct iwreq ireq;
+#endif
+
+       if (handle->md.must_clear != 0) {
+               /*
+                * There's something we have to do when closing this
+                * pcap_t.
+                */
+               if (handle->md.must_clear & MUST_CLEAR_PROMISC) {
+                       /*
+                        * We put the interface into promiscuous mode;
+                        * take it out of promiscuous mode.
+                        *
+                        * XXX - if somebody else wants it in promiscuous
+                        * mode, this code cannot know that, so it'll take
+                        * it out of promiscuous mode.  That's not fixable
+                        * in 2.0[.x] kernels.
+                        */
+                       memset(&ifr, 0, sizeof(ifr));
+                       strncpy(ifr.ifr_name, handle->md.device,
+                           sizeof(ifr.ifr_name));
+                       if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
+                               fprintf(stderr,
+                                   "Can't restore interface flags (SIOCGIFFLAGS failed: %s).\n"
+                                   "Please adjust manually.\n"
+                                   "Hint: This can't happen with Linux >= 2.2.0.\n",
+                                   strerror(errno));
+                       } else {
+                               if (ifr.ifr_flags & IFF_PROMISC) {
+                                       /*
+                                        * Promiscuous mode is currently on;
+                                        * turn it off.
+                                        */
+                                       ifr.ifr_flags &= ~IFF_PROMISC;
+                                       if (ioctl(handle->fd, SIOCSIFFLAGS,
+                                           &ifr) == -1) {
+                                               fprintf(stderr,
+                                                   "Can't restore interface flags (SIOCSIFFLAGS failed: %s).\n"
+                                                   "Please adjust manually.\n"
+                                                   "Hint: This can't happen with Linux >= 2.2.0.\n",
+                                                   strerror(errno));
+                                       }
+                               }
+                       }
+               }
+
+#ifdef IW_MODE_MONITOR
+               if (handle->md.must_clear & MUST_CLEAR_RFMON) {
+                       /*
+                        * We put the interface into rfmon mode;
+                        * take it out of rfmon mode.
+                        *
+                        * XXX - if somebody else wants it in rfmon
+                        * mode, this code cannot know that, so it'll take
+                        * it out of rfmon mode.
+                        */
+                       strncpy(ireq.ifr_ifrn.ifrn_name, handle->md.device,
+                           sizeof ireq.ifr_ifrn.ifrn_name);
+                       ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1]
+                           = 0;
+                       ireq.u.mode = handle->md.oldmode;
+                       if (ioctl(handle->fd, SIOCSIWMODE, &ireq) == -1) {
+                               /*
+                                * Scientist, you've failed.
+                                */
+                               fprintf(stderr,
+                                   "Can't restore interface wireless mode (SIOCSIWMODE failed: %s).\n"
+                                   "Please adjust manually.\n",
+                                   strerror(errno));
+                       }
+               }
+#endif
+
+               /*
+                * Take this pcap out of the list of pcaps for which we
+                * have to take the interface out of some mode.
+                */
+               pcap_remove_from_pcaps_to_close(handle);
        }
 
-       /* Initialize some components of the pcap structure. */
+       if (handle->md.device != NULL) {
+               free(handle->md.device);
+               handle->md.device = NULL;
+       }
+       pcap_close_common(handle);
+}
+
+/*
+ *  Get a handle for a live capture from the given device. You can
+ *  pass NULL as device to get all packages (without link level
+ *  information of course). If you pass 1 as promisc the interface
+ *  will be set to promiscous mode (XXX: I think this usage should
+ *  be deprecated and functions be added to select that later allow
+ *  modification of that values -- Torsten).
+ */
+static int
+pcap_activate_linux(pcap_t *handle)
+{
+       const char      *device;
+       int             err;
+       int             activate_ok = 0;
 
-       memset(handle, 0, sizeof(*handle));
-       handle->snapshot        = snaplen;
-       handle->md.timeout      = to_ms;
+       device = handle->opt.source;
 
        handle->inject_op = pcap_inject_linux;
        handle->setfilter_op = pcap_setfilter_linux;
@@ -338,10 +508,10 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        if (!device || strcmp(device, "any") == 0) {
                device                  = NULL;
                handle->md.device       = strdup("any");
-               if (promisc) {
-                       promisc = 0;
+               if (handle->opt.promisc) {
+                       handle->opt.promisc = 0;
                        /* Just a warning. */
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                            "Promiscuous mode not supported on the \"any\" device");
                }
 
@@ -349,10 +519,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                handle->md.device       = strdup(device);
 
        if (handle->md.device == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "strdup: %s",
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "strdup: %s",
                         pcap_strerror(errno) );
-               free(handle);
-               return NULL;
+               return PCAP_ERROR;
        }
 
        /*
@@ -365,38 +534,40 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * trying both methods with the newer method preferred.
         */
 
-       if ((err = live_open_new(handle, device, promisc, to_ms, ebuf)) == 1) {
-               live_open_ok = 1;
-               if (live_open_mmap(handle, ebuf) == 1)
-                       return handle;
+       if ((err = activate_new(handle)) == 1) {
+               activate_ok = 1;
+               /*
+                * Try to use memory-mapped access.
+                */
+               if (activate_mmap(handle) == 1)
+                       return 0;       /* we succeeded; nothing more to do */
        }
        else if (err == 0) {
                /* Non-fatal error; try old way */
-               if (live_open_old(handle, device, promisc, to_ms, ebuf))
-                       live_open_ok = 1;
+               if ((err = activate_old(handle)) == 1)
+                       activate_ok = 1;
        }
-       if (!live_open_ok) {
+       if (!activate_ok) {
                /*
                 * Both methods to open the packet socket failed. Tidy
                 * up and report our failure (ebuf is expected to be
                 * set by the functions above).
                 */
 
-               if (handle->md.device != NULL)
+               if (handle->md.device != NULL) {
                        free(handle->md.device);
-               free(handle);
-               return NULL;
+                       handle->md.device = NULL;
+               }
+               return err;
        }
 
        /* Allocate the buffer */
 
        handle->buffer   = malloc(handle->bufsize + handle->offset);
        if (!handle->buffer) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                         "malloc: %s", pcap_strerror(errno));
-               pcap_close_linux(handle);
-               free(handle);
-               return NULL;
+               return PCAP_ERROR;
        }
 
        /*
@@ -405,7 +576,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         */
        handle->selectable_fd = handle->fd;
 
-       return handle;
+       return 0;
 }
 
 /*
@@ -489,7 +660,7 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
                if (errno == EAGAIN)
                        return 0;       /* no packet there */
                else {
-                       snprintf(handle->errbuf, sizeof(handle->errbuf),
+                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                                 "recvfrom: %s", pcap_strerror(errno));
                        return -1;
                }
@@ -617,7 +788,7 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
        /* Fill in our own header data */
 
        if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) {
-               snprintf(handle->errbuf, sizeof(handle->errbuf),
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                         "SIOCGSTAMP: %s", pcap_strerror(errno));
                return -1;
        }
@@ -880,7 +1051,7 @@ pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter)
                return -1;
        if (!filter) {
                strncpy(handle->errbuf, "setfilter: No filter specified",
-                       sizeof(handle->errbuf));
+                       PCAP_ERRBUF_SIZE);
                return -1;
        }
 
@@ -1018,7 +1189,7 @@ pcap_setdirection_linux(pcap_t *handle, pcap_direction_t d)
         * We're not using PF_PACKET sockets, so we can't determine
         * the direction of the packet.
         */
-       snprintf(handle->errbuf, sizeof(handle->errbuf),
+       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
            "Setting direction is not supported on SOCK_PACKET sockets");
        return -1;
 }
@@ -1095,7 +1266,7 @@ static void map_arphrd_to_dlt(pcap_t *handle, int arptype, int cooked_ok)
                 * XXX - are there any sorts of "fake Ethernet" that have
                 * ARPHRD_ETHER but that *shouldn't offer DLT_DOCSIS as
                 * a Cisco CMTS won't put traffic onto it or get traffic
-                * bridged onto it?  ISDN is handled in "live_open_new()",
+                * bridged onto it?  ISDN is handled in "activate_new()",
                 * as we fall back on cooked mode there; are there any
                 * others?
                 */
@@ -1362,238 +1533,251 @@ static void map_arphrd_to_dlt(pcap_t *handle, int arptype, int cooked_ok)
 /* ===== Functions to interface to the newer kernels ================== */
 
 /*
- *  Try to open a packet socket using the new kernel interface.
- *  Returns 0 on failure.
- *  FIXME: 0 uses to mean success (Sebastian)
+ * Try to open a packet socket using the new kernel PF_PACKET interface.
+ * Returns 1 on success, 0 on an error that means the new interface isn't
+ * present (so the old SOCK_PACKET interface should be tried), and a
+ * PCAP_ERROR_ value on an error that means that the old mechanism won't
+ * work either (so it shouldn't be tried).
  */
 static int
-live_open_new(pcap_t *handle, const char *device, int promisc,
-             int to_ms, char *ebuf)
+activate_new(pcap_t *handle)
 {
 #ifdef HAVE_PF_PACKET_SOCKETS
        int                     sock_fd = -1, arptype;
-       int                     err;
-       int                     fatal_err = 0;
+       int                     err = 0;
        struct packet_mreq      mr;
+       const char* device = handle->opt.source;
 
-       /* One shot loop used for error handling - bail out with break */
-
-       do {
-               /*
-                * Open a socket with protocol family packet. If a device is
-                * given we try to open it in raw mode otherwise we use
-                * the cooked interface.
-                */
-               sock_fd = device ?
-                       socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
-                     : socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
-
-               if (sock_fd == -1) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "socket: %s",
-                                pcap_strerror(errno) );
-                       break;
-               }
+       /*
+        * Open a socket with protocol family packet. If a device is
+        * given we try to open it in raw mode otherwise we use
+        * the cooked interface.
+        */
+       sock_fd = device ?
+               socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
+             : socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
 
-               /* It seems the kernel supports the new interface. */
-               handle->md.sock_packet = 0;
+       if (sock_fd == -1) {
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
+                        pcap_strerror(errno) );
+               return 0;       /* try old mechanism */
+       }
 
-               /*
-                * Get the interface index of the loopback device.
-                * If the attempt fails, don't fail, just set the
-                * "md.lo_ifindex" to -1.
-                *
-                * XXX - can there be more than one device that loops
-                * packets back, i.e. devices other than "lo"?  If so,
-                * we'd need to find them all, and have an array of
-                * indices for them, and check all of them in
-                * "pcap_read_packet()".
-                */
-               handle->md.lo_ifindex = iface_get_id(sock_fd, "lo", ebuf);
+       /* It seems the kernel supports the new interface. */
+       handle->md.sock_packet = 0;
 
-               /*
-                * Default value for offset to align link-layer payload
-                * on a 4-byte boundary.
-                */
-               handle->offset   = 0;
+       /*
+        * Get the interface index of the loopback device.
+        * If the attempt fails, don't fail, just set the
+        * "md.lo_ifindex" to -1.
+        *
+        * XXX - can there be more than one device that loops
+        * packets back, i.e. devices other than "lo"?  If so,
+        * we'd need to find them all, and have an array of
+        * indices for them, and check all of them in
+        * "pcap_read_packet()".
+        */
+       handle->md.lo_ifindex = iface_get_id(sock_fd, "lo", handle->errbuf);
 
-               /*
-                * What kind of frames do we have to deal with? Fall back
-                * to cooked mode if we have an unknown interface type.
-                */
+       /*
+        * Default value for offset to align link-layer payload
+        * on a 4-byte boundary.
+        */
+       handle->offset   = 0;
 
-               if (device) {
-                       /* Assume for now we don't need cooked mode. */
-                       handle->md.cooked = 0;
+       /*
+        * What kind of frames do we have to deal with? Fall back
+        * to cooked mode if we have an unknown interface type
+        * or a type we know doesn't work well in raw mode.
+        */
+       if (device) {
+               /* Assume for now we don't need cooked mode. */
+               handle->md.cooked = 0;
 
-                       arptype = iface_get_arptype(sock_fd, device, ebuf);
-                       if (arptype == -1) {
-                               fatal_err = 1;
-                               break;
+               if (handle->opt.rfmon) {
+                       /*
+                        * We were asked to turn on monitor mode.
+                        * Do so before we get the link-layer type,
+                        * because entering monitor mode could change
+                        * the link-layer type.
+                        */
+                       err = enter_rfmon_mode_wext(handle, sock_fd, device);
+                       if (err < 0) {
+                               /* Hard failure */
+                               close(sock_fd);
+                               return err;
                        }
-                       map_arphrd_to_dlt(handle, arptype, 1);
-                       if (handle->linktype == -1 ||
-                           handle->linktype == DLT_LINUX_SLL ||
-                           handle->linktype == DLT_LINUX_IRDA ||
-                           handle->linktype == DLT_LINUX_LAPD ||
-                           (handle->linktype == DLT_EN10MB &&
-                            (strncmp("isdn", device, 4) == 0 ||
-                             strncmp("isdY", device, 4) == 0))) {
-                               /*
-                                * Unknown interface type (-1), or a
-                                * device we explicitly chose to run
-                                * in cooked mode (e.g., PPP devices),
-                                * or an ISDN device (whose link-layer
-                                * type we can only determine by using
-                                * APIs that may be different on different
-                                * kernels) - reopen in cooked mode.
-                                */
-                               if (close(sock_fd) == -1) {
-                                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                                "close: %s", pcap_strerror(errno));
-                                       break;
-                               }
-                               sock_fd = socket(PF_PACKET, SOCK_DGRAM,
-                                                htons(ETH_P_ALL));
-                               if (sock_fd == -1) {
-                                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                                "socket: %s", pcap_strerror(errno));
-                                       break;
-                               }
-                               handle->md.cooked = 1;
-
+                       if (err == 0) {
                                /*
-                                * Get rid of any link-layer type list
-                                * we allocated - this only supports cooked
-                                * capture.
+                                * Nothing worked for turning monitor mode
+                                * on.
                                 */
-                               if (handle->dlt_list != NULL) {
-                                       free(handle->dlt_list);
-                                       handle->dlt_list = NULL;
-                                       handle->dlt_count = 0;
-                               }
-
-                               if (handle->linktype == -1) {
-                                       /*
-                                        * Warn that we're falling back on
-                                        * cooked mode; we may want to
-                                        * update "map_arphrd_to_dlt()"
-                                        * to handle the new type.
-                                        */
-                                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                               "arptype %d not "
-                                               "supported by libpcap - "
-                                               "falling back to cooked "
-                                               "socket",
-                                               arptype);
-                               }
-                               /* IrDA capture is not a real "cooked" capture,
-                                * it's IrLAP frames, not IP packets. */
-                               if (handle->linktype != DLT_LINUX_IRDA &&
-                                       handle->linktype != DLT_LINUX_LAPD)
-                                       handle->linktype = DLT_LINUX_SLL;
-                       }
-
-                       handle->md.ifindex = iface_get_id(sock_fd, device, ebuf);
-                       if (handle->md.ifindex == -1)
-                               break;
-
-                       if ((err = iface_bind(sock_fd, handle->md.ifindex,
-                           ebuf)) < 0) {
-                               if (err == -2)
-                                       fatal_err = 1;
-                               break;
+                               close(sock_fd);
+                               return PCAP_ERROR_RFMON_NOTSUP;
                        }
-               } else {
+               }
+               arptype = iface_get_arptype(sock_fd, device, handle->errbuf);
+               if (arptype < 0) {
+                       close(sock_fd);
+                       return arptype;
+               }
+               map_arphrd_to_dlt(handle, arptype, 1);
+               if (handle->linktype == -1 ||
+                   handle->linktype == DLT_LINUX_SLL ||
+                   handle->linktype == DLT_LINUX_IRDA ||
+                   handle->linktype == DLT_LINUX_LAPD ||
+                   (handle->linktype == DLT_EN10MB &&
+                    (strncmp("isdn", device, 4) == 0 ||
+                     strncmp("isdY", device, 4) == 0))) {
                        /*
-                        * This is cooked mode.
+                        * Unknown interface type (-1), or a
+                        * device we explicitly chose to run
+                        * in cooked mode (e.g., PPP devices),
+                        * or an ISDN device (whose link-layer
+                        * type we can only determine by using
+                        * APIs that may be different on different
+                        * kernels) - reopen in cooked mode.
                         */
+                       if (close(sock_fd) == -1) {
+                               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                        "close: %s", pcap_strerror(errno));
+                               return PCAP_ERROR;
+                       }
+                       sock_fd = socket(PF_PACKET, SOCK_DGRAM,
+                           htons(ETH_P_ALL));
+                       if (sock_fd == -1) {
+                               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                   "socket: %s", pcap_strerror(errno));
+                               return PCAP_ERROR;
+                       }
                        handle->md.cooked = 1;
-                       handle->linktype = DLT_LINUX_SLL;
 
                        /*
-                        * We're not bound to a device.
-                        * XXX - true?  Or true only if we're using
-                        * the "any" device?
-                        * For now, we're using this as an indication
-                        * that we can't transmit; stop doing that only
-                        * if we figure out how to transmit in cooked
-                        * mode.
+                        * Get rid of any link-layer type list
+                        * we allocated - this only supports cooked
+                        * capture.
+                        */
+                       if (handle->dlt_list != NULL) {
+                               free(handle->dlt_list);
+                               handle->dlt_list = NULL;
+                               handle->dlt_count = 0;
+                       }
+
+                       if (handle->linktype == -1) {
+                               /*
+                                * Warn that we're falling back on
+                                * cooked mode; we may want to
+                                * update "map_arphrd_to_dlt()"
+                                * to handle the new type.
+                                */
+                               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                       "arptype %d not "
+                                       "supported by libpcap - "
+                                       "falling back to cooked "
+                                       "socket",
+                                       arptype);
+                       }
+
+                       /*
+                        * IrDA capture is not a real "cooked" capture,
+                        * it's IrLAP frames, not IP packets.  The
+                        * same applies to LAPD capture.
                         */
-                       handle->md.ifindex = -1;
+                       if (handle->linktype != DLT_LINUX_IRDA &&
+                           handle->linktype != DLT_LINUX_LAPD)
+                               handle->linktype = DLT_LINUX_SLL;
                }
 
-               /*
-                * Select promiscuous mode on if "promisc" is set.
-                *
-                * Do not turn allmulti mode on if we don't select
-                * promiscuous mode - on some devices (e.g., Orinoco
-                * wireless interfaces), allmulti mode isn't supported
-                * and the driver implements it by turning promiscuous
-                * mode on, and that screws up the operation of the
-                * card as a normal networking interface, and on no
-                * other platform I know of does starting a non-
-                * promiscuous capture affect which multicast packets
-                * are received by the interface.
-                */
+               handle->md.ifindex = iface_get_id(sock_fd, device,
+                   handle->errbuf);
+               if (handle->md.ifindex == -1) {
+                       close(sock_fd);
+                       return PCAP_ERROR;
+               }
 
+               if ((err = iface_bind(sock_fd, handle->md.ifindex,
+                   handle->errbuf)) < 0) {
+                       close(sock_fd);
+                       if (err == -2)
+                               return PCAP_ERROR;
+                       else
+                               return 0;       /* try old mechanism */
+               }
+       } else {
                /*
-                * Hmm, how can we set promiscuous mode on all interfaces?
-                * I am not sure if that is possible at all.
+                * This is cooked mode.
                 */
-
-               if (device && promisc) {
-                       memset(&mr, 0, sizeof(mr));
-                       mr.mr_ifindex = handle->md.ifindex;
-                       mr.mr_type    = PACKET_MR_PROMISC;
-                       if (setsockopt(sock_fd, SOL_PACKET,
-                               PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1)
-                       {
-                               snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                       "setsockopt: %s", pcap_strerror(errno));
-                               break;
-                       }
-               }
+               handle->md.cooked = 1;
+               handle->linktype = DLT_LINUX_SLL;
 
                /*
-                * This is a 2.2[.x] or later kernel (we know that
-                * because we're not using a SOCK_PACKET socket -
-                * PF_PACKET is supported only in 2.2 and later
-                * kernels).
-                *
-                * We can safely pass "recvfrom()" a byte count
-                * based on the snapshot length.
-                *
-                * If we're in cooked mode, make the snapshot length
-                * large enough to hold a "cooked mode" header plus
-                * 1 byte of packet data (so we don't pass a byte
-                * count of 0 to "recvfrom()").
+                * We're not bound to a device.
+                * XXX - true?  Or true only if we're using
+                * the "any" device?
+                * For now, we're using this as an indication
+                * that we can't transmit; stop doing that only
+                * if we figure out how to transmit in cooked
+                * mode.
                 */
-               if (handle->md.cooked) {
-                       if (handle->snapshot < SLL_HDR_LEN + 1)
-                               handle->snapshot = SLL_HDR_LEN + 1;
-               }
-               handle->bufsize = handle->snapshot;
+               handle->md.ifindex = -1;
+       }
 
-               /* Save the socket FD in the pcap structure */
+       /*
+        * Select promiscuous mode on if "promisc" is set.
+        *
+        * Do not turn allmulti mode on if we don't select
+        * promiscuous mode - on some devices (e.g., Orinoco
+        * wireless interfaces), allmulti mode isn't supported
+        * and the driver implements it by turning promiscuous
+        * mode on, and that screws up the operation of the
+        * card as a normal networking interface, and on no
+        * other platform I know of does starting a non-
+        * promiscuous capture affect which multicast packets
+        * are received by the interface.
+        */
 
-               handle->fd       = sock_fd;
+       /*
+        * Hmm, how can we set promiscuous mode on all interfaces?
+        * I am not sure if that is possible at all.
+        */
 
-               return 1;
+       if (device && handle->opt.promisc) {
+               memset(&mr, 0, sizeof(mr));
+               mr.mr_ifindex = handle->md.ifindex;
+               mr.mr_type    = PACKET_MR_PROMISC;
+               if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
+                   &mr, sizeof(mr)) == -1) {
+                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                               "setsockopt: %s", pcap_strerror(errno));
+                       close(sock_fd);
+                       return PCAP_ERROR;
+               }
+       }
 
-       } while(0);
+       /*
+        * This is a 2.2[.x] or later kernel (we know that
+        * because we're not using a SOCK_PACKET socket -
+        * PF_PACKET is supported only in 2.2 and later
+        * kernels).
+        *
+        * We can safely pass "recvfrom()" a byte count
+        * based on the snapshot length.
+        *
+        * If we're in cooked mode, make the snapshot length
+        * large enough to hold a "cooked mode" header plus
+        * 1 byte of packet data (so we don't pass a byte
+        * count of 0 to "recvfrom()").
+        */
+       if (handle->md.cooked) {
+               if (handle->snapshot < SLL_HDR_LEN + 1)
+                       handle->snapshot = SLL_HDR_LEN + 1;
+       }
+       handle->bufsize = handle->snapshot;
 
-       if (sock_fd != -1)
-               close(sock_fd);
+       /* Save the socket FD in the pcap structure */
+       handle->fd       = sock_fd;
 
-       if (fatal_err) {
-               /*
-                * Get rid of any link-layer type list we allocated.
-                */
-               if (handle->dlt_list != NULL)
-                       free(handle->dlt_list);
-               return -2;
-       } else
-               return 0;
+       return 1;
 #else
        strncpy(ebuf,
                "New packet capturing interface not supported by build "
@@ -1603,16 +1787,21 @@ live_open_new(pcap_t *handle, const char *device, int promisc,
 }
 
 static int 
-live_open_mmap(pcap_t* handle, char* errmsg)
+activate_mmap(pcap_t *handle)
 {
 #ifdef HAVE_PACKET_RING
-       /* by default request 4M for the ring buffer */
-       int ret = create_ring(handle, 4*1024*1024, errmsg);
+       int ret;
+
+       if (handle->opt.buffer_size == 0) {
+               /* by default request 2M for the ring buffer */
+               handle->opt.buffer_size = 2*1024*1024;
+       }
+       ret = create_ring(handle);
        if (ret == 0)
                return ret;
 
        /* override some defaults and inherit the other fields from
-        * open_live_new
+        * activate_new
         * handle->offset is used to get the current position into the rx ring 
         * handle->cc is used to store the ring size */
        handle->read_op = pcap_read_linux_mmap;
@@ -1644,7 +1833,7 @@ compute_ring_block(int frame_size, unsigned *block_size, unsigned *frames_per_bl
 }
 
 static int
-create_ring(pcap_t* handle, unsigned size, char* errmsg)
+create_ring(pcap_t *handle)
 {
        unsigned i, j, ringsize, frames_per_block;
        struct tpacket_req req;
@@ -1655,7 +1844,7 @@ create_ring(pcap_t* handle, unsigned size, char* errmsg)
         * The snap len should be carefully chosen to achive best
         * performance */
        req.tp_frame_size = TPACKET_ALIGN(handle->snapshot+TPACKET_HDRLEN);
-       req.tp_frame_nr = size/req.tp_frame_size;
+       req.tp_frame_nr = handle->opt.buffer_size/req.tp_frame_size;
        compute_ring_block(req.tp_frame_size, &req.tp_block_size, &frames_per_block);
        req.tp_block_nr = req.tp_frame_nr / frames_per_block;
 
@@ -1672,7 +1861,7 @@ retry:
                        req.tp_block_nr = req.tp_frame_nr/frames_per_block;
                        goto retry;
                }
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "can't create rx ring on "
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't create rx ring on "
                                "packet socket %d: %d-%s", handle->fd, errno, 
                                pcap_strerror(errno));
                return 0;
@@ -1683,7 +1872,7 @@ retry:
        handle->bp = mmap(0, ringsize, PROT_READ| PROT_WRITE, MAP_SHARED, 
                                        handle->fd, 0);
        if (handle->bp == MAP_FAILED) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "can't mmap rx ring: %d-%s",
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "can't mmap rx ring: %d-%s",
                        errno, pcap_strerror(errno));
 
                /* clear the allocated ring on error*/
@@ -1761,7 +1950,7 @@ static int
 pcap_setnonblock_mmap(pcap_t *p, int nonblock, char *errbuf)
 {
        /* map each value to the corresponding 2's complement, to 
-        * preserve the timeout value provided with pcap_open_live */
+        * preserve the timeout value provided with pcap_set_timeout */
        if (nonblock) {
                if (p->md.timeout > 0)
                        p->md.timeout = p->md.timeout*-1 - 1;
@@ -2010,307 +2199,738 @@ iface_bind(int fd, int ifindex, char *ebuf)
        return 0;
 }
 
+/*
+ * Check whether the device supports the Wireless Extensions.
+ * Returns 1 if it does, 0 if it doesn't, PCAP_ERROR_NO_SUCH_DEVICE
+ * if the device doesn't even exist.
+ */
+static int
+has_wext(int sock_fd, const char *device)
+{
+#ifdef IW_MODE_MONITOR
+       struct iwreq ireq;
+
+       strncpy(ireq.ifr_ifrn.ifrn_name, device,
+           sizeof ireq.ifr_ifrn.ifrn_name);
+       ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+       if (ioctl(sock_fd, SIOCGIWNAME, &ireq) >= 0)
+               return 1;       /* yes */
+       if (errno == ENODEV)
+               return PCAP_ERROR_NO_SUCH_DEVICE;
 #endif
-
-
-/* ===== Functions to interface to the older kernels ================== */
+       return 0;
+}
 
 /*
- * With older kernels promiscuous mode is kind of interesting because we
- * have to reset the interface before exiting. The problem can't really
- * be solved without some daemon taking care of managing usage counts.
- * If we put the interface into promiscuous mode, we set a flag indicating
- * that we must take it out of that mode when the interface is closed,
- * and, when closing the interface, if that flag is set we take it out
- * of promiscuous mode.
+ * Per me si va ne la citta dolente,
+ * Per me si va ne l'etterno dolore,
+ *     ...
+ * Lasciate ogne speranza, voi ch'intrate.
  */
+typedef enum {
+       MONITOR_WEXT,
+       MONITOR_HOSTAP,
+       MONITOR_PRISM,
+       MONITOR_PRISM54,
+       MONITOR_ACX100,
+       MONITOR_RT2500,
+       MONITOR_RT2570,
+       MONITOR_RT73,
+       MONITOR_RTL8XXX
+} monitor_type;
 
 /*
- * List of pcaps for which we turned promiscuous mode on by hand.
- * If there are any such pcaps, we arrange to call "pcap_close_all()"
- * when we exit, and have it close all of them to turn promiscuous mode
- * off.
+ * Use the Wireless Extensions, if we have them, to try to turn monitor mode
+ * on if it's not already on.
+ *
+ * Returns 1 on success, 0 if we don't support the Wireless Extensions
+ * on this device, or a PCAP_ERROR_ value if we do support them but
+ * we weren't able to turn monitor mode on.
  */
-static struct pcap *pcaps_to_close;
+static int
+enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
+{
+#ifdef IW_MODE_MONITOR
+       /*
+        * XXX - at least some adapters require non-Wireless Extensions
+        * mechanisms to turn monitor mode on.
+        *
+        * Atheros cards might require that a separate "monitor virtual access
+        * point" be created, with later versions of the madwifi driver.
+        *
+        * Some Intel Centrino adapters might require private ioctls to get
+        * radio headers; the ipw2200 and ipw3945 drivers allow you to
+        * configure a separate "rtapN" interface to capture in monitor
+        * mode without preventing the adapter from operating normally.
+        *
+        * It would be Truly Wonderful if mac80211 and nl80211 cleaned this
+        * up, and if all drivers were converted to mac80211 drivers.
+        */
+       int err;
+       struct iwreq ireq;
+       struct iw_priv_args *priv;
+       monitor_type montype;
+       int i;
+       __u32 cmd;
+       int args[2];
+       int channel;
 
-/*
- * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to
- * be called on exit.
- */
-static int did_atexit;
+       /*
+        * Does this device *support* the Wireless Extensions?
+        */
+       err = has_wext(sock_fd, device);
+       if (err <= 0)
+               return err;     /* either it doesn't or the device doesn't even exist */
+       /*
+        * Try to get all the Wireless Extensions private ioctls
+        * supported by this device.
+        *
+        * First, get the size of the buffer we need, by supplying no
+        * buffer and a length of 0.  If the device supports private
+        * ioctls, it should return E2BIG, with ireq.u.data.length set
+        * to the length we need.  If it doesn't support them, it should
+        * return EOPNOTSUPP.
+        */
+       memset(&ireq, 0, sizeof ireq);
+       strncpy(ireq.ifr_ifrn.ifrn_name, device,
+           sizeof ireq.ifr_ifrn.ifrn_name);
+       ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+       ireq.u.data.pointer = args;
+       ireq.u.data.length = 0;
+       ireq.u.data.flags = 0;
+       if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) != -1) {
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                   "%s: SIOCGIWPRIV with a zero-length buffer didn't fail!",
+                   device);
+               return PCAP_ERROR;
+       }
+       if (errno == EOPNOTSUPP) {
+               /*
+                * No private ioctls, so we assume that there's only one
+                * DLT_ for monitor mode.
+                */
+               return 0;
+       }
+       if (errno != E2BIG) {
+               /*
+                * Failed.
+                */
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                   "%s: SIOCGIWPRIV: %s", device, pcap_strerror(errno));
+               return PCAP_ERROR;
+       }
+       priv = malloc(ireq.u.data.length);
+       if (priv == NULL) {
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                        "malloc: %s", pcap_strerror(errno));
+               return PCAP_ERROR;
+       }
+       ireq.u.data.pointer = priv;
+       if (ioctl(sock_fd, SIOCGIWPRIV, &ireq) == -1) {
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                   "%s: SIOCGIWPRIV: %s", device, pcap_strerror(errno));
+               return PCAP_ERROR;
+       }
 
-static void    pcap_close_all(void)
-{
-       struct pcap *handle;
+       /*
+        * Look for private ioctls to turn monitor mode on or, if
+        * monitor mode is on, to set the header type.
+        */
+       montype = MONITOR_WEXT;
+       cmd = 0;
+       for (i = 0; i < ireq.u.data.length; i++) {
+               if (strcmp(priv[i].name, "monitor_type") == 0) {
+                       /*
+                        * Hostap driver, use this one.
+                        * Set monitor mode first.
+                        * You can set it to 0 to get DLT_IEEE80211,
+                        * 1 to get DLT_PRISM, or 2 to get
+                        * DLT_IEEE80211_RADIO_AVS.
+                        */
+                       if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
+                               break;
+                       if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
+                               break;
+                       if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
+                               break;
+                       montype = MONITOR_HOSTAP;
+                       cmd = priv[i].cmd;
+                       break;
+               }
+               if (strcmp(priv[i].name, "set_prismhdr") == 0) {
+                       /*
+                        * Prism54 driver, use this one.
+                        * Set monitor mode first.
+                        * You can set it to 2 to get DLT_IEEE80211
+                        * or 3 or get DLT_PRISM.
+                        */
+                       if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
+                               break;
+                       if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
+                               break;
+                       if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
+                               break;
+                       montype = MONITOR_PRISM54;
+                       cmd = priv[i].cmd;
+                       break;
+               }
+               if (strcmp(priv[i].name, "forceprismheader") == 0) {
+                       /*
+                        * RT2570 driver, use this one.
+                        * Do this after turning monitor mode on.
+                        * You can set it to 1 to get DLT_PRISM or 2
+                        * to get DLT_IEEE80211.
+                        */
+                       if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
+                               break;
+                       if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
+                               break;
+                       if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
+                               break;
+                       montype = MONITOR_RT2570;
+                       cmd = priv[i].cmd;
+                       break;
+               }
+               if (strcmp(priv[i].name, "forceprism") == 0) {
+                       /*
+                        * RT73 driver, use this one.
+                        * Do this after turning monitor mode on.
+                        * Its argument is a *string*; you can
+                        * set it to "1" to get DLT_PRISM or "2"
+                        * to get DLT_IEEE80211.
+                        */
+                       if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_CHAR)
+                               break;
+                       if (priv[i].set_args & IW_PRIV_SIZE_FIXED)
+                               break;
+                       montype = MONITOR_RT73;
+                       cmd = priv[i].cmd;
+                       break;
+               }
+               if (strcmp(priv[i].name, "prismhdr") == 0) {
+                       /*
+                        * One of the RTL8xxx drivers, use this one.
+                        * It can only be done after monitor mode
+                        * has been turned on.  You can set it to 1
+                        * to get DLT_PRISM or 0 to get DLT_IEEE80211.
+                        */
+                       if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
+                               break;
+                       if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
+                               break;
+                       if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 1)
+                               break;
+                       montype = MONITOR_RTL8XXX;
+                       cmd = priv[i].cmd;
+                       break;
+               }
+               if (strcmp(priv[i].name, "rfmontx") == 0) {
+                       /*
+                        * RT2500 or RT61 driver, use this one.
+                        * It has one one-byte parameter; set
+                        * u.data.length to 1 and u.data.pointer to
+                        * point to the parameter.
+                        * It doesn't itself turn monitor mode on.
+                        * You can set it to 1 to allow transmitting
+                        * in monitor mode(?) and get DLT_IEEE80211,
+                        * or set it to 0 to disallow transmitting in
+                        * monitor mode(?) and get DLT_PRISM.
+                        */
+                       if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
+                               break;
+                       if ((priv[i].set_args & IW_PRIV_SIZE_MASK) != 2)
+                               break;
+                       montype = MONITOR_RT2500;
+                       cmd = priv[i].cmd;
+                       break;
+               }
+               if (strcmp(priv[i].name, "monitor") == 0) {
+                       /*
+                        * Either ACX100 or hostap, use this one.
+                        * It turns monitor mode on.
+                        * If it takes two arguments, it's ACX100;
+                        * the first argument is 1 for DLT_PRISM
+                        * or 2 for DLT_IEEE80211, and the second
+                        * argument is the channel on which to
+                        * run.  If it takes one argument, it's
+                        * HostAP, and the argument is 2 for
+                        * DLT_IEEE80211 and 3 for DLT_PRISM.
+                        *
+                        * If we see this, we don't quit, as this
+                        * might be a version of the hostap driver
+                        * that also supports "monitor_type".
+                        */
+                       if ((priv[i].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT)
+                               break;
+                       if (!(priv[i].set_args & IW_PRIV_SIZE_FIXED))
+                               break;
+                       switch (priv[i].set_args & IW_PRIV_SIZE_MASK) {
 
-       while ((handle = pcaps_to_close) != NULL)
-               pcap_close(handle);
-}
+                       case 1:
+                               montype = MONITOR_PRISM;
+                               cmd = priv[i].cmd;
+                               break;
 
-static void    pcap_close_linux( pcap_t *handle )
-{
-       struct pcap     *p, *prevp;
-       struct ifreq    ifr;
+                       case 2:
+                               montype = MONITOR_ACX100;
+                               cmd = priv[i].cmd;
+                               break;
+
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * XXX - ipw3945?  islism?
+        */
+
+       /*
+        * Get the old mode.
+        */
+       strncpy(ireq.ifr_ifrn.ifrn_name, device,
+           sizeof ireq.ifr_ifrn.ifrn_name);
+       ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+       if (ioctl(sock_fd, SIOCGIWMODE, &ireq) == -1) {
+               /*
+                * We probably won't be able to set the mode, either.
+                */
+               return PCAP_ERROR_RFMON_NOTSUP;
+       }
+
+       /*
+        * Is it currently in monitor mode?
+        */
+       if (ireq.u.mode == IW_MODE_MONITOR) {
+               /*
+                * Yes.  Just leave things as they are.
+                * We don't offer multiple link-layer types, as
+                * changing the link-layer type out from under
+                * somebody else capturing in monitor mode would
+                * be considered rude.
+                */
+               return 1;
+       }
+       /*
+        * No.  We have to put the adapter into rfmon mode.
+        */
+
+       /*
+        * If we haven't already done so, arrange to have
+        * "pcap_close_all()" called when we exit.
+        */
+       if (!pcap_do_addexit(handle)) {
+               /*
+                * "atexit()" failed; don't put the interface
+                * in rfmon mode, just give up.
+                */
+               return PCAP_ERROR_RFMON_NOTSUP;
+       }
+
+       /*
+        * Save the old mode.
+        */
+       handle->md.oldmode = ireq.u.mode;
 
-       if (handle->md.clear_promisc) {
+       /*
+        * Put the adapter in rfmon mode.  How we do this depends
+        * on whether we have a special private ioctl or not.
+        */
+       if (montype == MONITOR_PRISM) {
                /*
-                * We put the interface into promiscuous mode; take
-                * it out of promiscuous mode.
+                * We have the "monitor" private ioctl, but none of
+                * the other private ioctls.  Use this, and select
+                * the Prism header.
                 *
-                * XXX - if somebody else wants it in promiscuous mode,
-                * this code cannot know that, so it'll take it out
-                * of promiscuous mode.  That's not fixable in 2.0[.x]
-                * kernels.
+                * If it fails, just fall back on SIOCSIWMODE.
                 */
-               memset(&ifr, 0, sizeof(ifr));
-               strncpy(ifr.ifr_name, handle->md.device, sizeof(ifr.ifr_name));
-               if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
-                       fprintf(stderr,
-                           "Can't restore interface flags (SIOCGIFFLAGS failed: %s).\n"
-                           "Please adjust manually.\n"
-                           "Hint: This can't happen with Linux >= 2.2.0.\n",
-                           strerror(errno));
-               } else {
-                       if (ifr.ifr_flags & IFF_PROMISC) {
-                               /*
-                                * Promiscuous mode is currently on; turn it
-                                * off.
-                                */
-                               ifr.ifr_flags &= ~IFF_PROMISC;
-                               if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
-                                       fprintf(stderr,
-                                           "Can't restore interface flags (SIOCSIFFLAGS failed: %s).\n"
-                                           "Please adjust manually.\n"
-                                           "Hint: This can't happen with Linux >= 2.2.0.\n",
-                                           strerror(errno));
-                               }
-                       }
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               ireq.u.data.length = 1; /* 1 argument */
+               args[0] = 3;    /* request Prism header */
+               memcpy(ireq.u.name, args, IFNAMSIZ);
+               if (ioctl(sock_fd, cmd, &ireq) != -1) {
+                       /*
+                        * Success.
+                        * Note that we have to put the old mode back
+                        * when we close the device.
+                        */
+                       handle->md.must_clear |= MUST_CLEAR_RFMON;
+
+                       /*
+                        * Add this to the list of pcaps to close
+                        * when we exit.
+                        */
+                       pcap_add_to_pcaps_to_close(handle);
+
+                       return 1;
                }
 
                /*
-                * Take this pcap out of the list of pcaps for which we
-                * have to take the interface out of promiscuous mode.
+                * Failure.  Fall back on SIOCSIWMODE.
                 */
-               for (p = pcaps_to_close, prevp = NULL; p != NULL;
-                   prevp = p, p = p->md.next) {
-                       if (p == handle) {
-                               /*
-                                * Found it.  Remove it from the list.
-                                */
-                               if (prevp == NULL) {
-                                       /*
-                                        * It was at the head of the list.
-                                        */
-                                       pcaps_to_close = p->md.next;
-                               } else {
-                                       /*
-                                        * It was in the middle of the list.
-                                        */
-                                       prevp->md.next = p->md.next;
-                               }
-                               break;
-                       }
+       }
+
+       /*
+        * First, turn monitor mode on.
+        */
+       strncpy(ireq.ifr_ifrn.ifrn_name, device,
+           sizeof ireq.ifr_ifrn.ifrn_name);
+       ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+       ireq.u.mode = IW_MODE_MONITOR;
+       if (ioctl(sock_fd, SIOCSIWMODE, &ireq) == -1) {
+               /*
+                * Scientist, you've failed.
+                */
+               return PCAP_ERROR_RFMON_NOTSUP;
+       }
+
+       /*
+        * Now select the appropriate radio header.
+        */
+       switch (montype) {
+
+       case MONITOR_WEXT:
+               /*
+                * We don't have any private ioctl to set the header.
+                */
+               break;
+
+       case MONITOR_HOSTAP:
+               /*
+                * Select the AVS header if we can, otherwise
+                * select the Prism header.
+                */
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               args[0] = 2;    /* request AVS header */
+               memcpy(ireq.u.name, args, sizeof (int));
+               if (ioctl(sock_fd, cmd, &ireq) == -1) {
+                       /*
+                        * Failure - try the Prism header.
+                        */
+                       memset(&ireq, 0, sizeof ireq);
+                       strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                           sizeof ireq.ifr_ifrn.ifrn_name);
+                       ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+                       args[0] = 1;    /* request Prism header */
+                       memcpy(ireq.u.name, args, sizeof (int));
+                       ioctl(sock_fd, cmd, &ireq);
+               }
+               break;
+
+       case MONITOR_PRISM:
+               /*
+                * The private ioctl failed.
+                */
+               break;
+
+       case MONITOR_PRISM54:
+               /*
+                * Select the Prism header.
+                */
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               args[0] = 3;    /* request Prism header */
+               memcpy(ireq.u.name, args, sizeof (int));
+               ioctl(sock_fd, cmd, &ireq);
+               break;
+
+       case MONITOR_ACX100:
+               /*
+                * Get the current channel.
+                */
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               if (ioctl(sock_fd, SIOCGIWFREQ, &ireq) == -1) {
+                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                           "%s: SIOCGIWFREQ: %s", device,
+                           pcap_strerror(errno));
+                       return PCAP_ERROR;
                }
+               channel = ireq.u.freq.m;
+
+               /*
+                * Select the Prism header, and set the channel to the
+                * current value.
+                */
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               args[0] = 1;            /* request Prism header */
+               args[1] = channel;      /* set channel */
+               memcpy(ireq.u.name, args, 2*sizeof (int));
+               ioctl(sock_fd, cmd, &ireq);
+               break;
+
+       case MONITOR_RT2500:
+               /*
+                * Disallow transmission - that turns on the
+                * Prism header.
+                */
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               args[0] = 0;    /* disallow transmitting */
+               memcpy(ireq.u.name, args, sizeof (int));
+               ioctl(sock_fd, cmd, &ireq);
+               break;
+
+       case MONITOR_RT2570:
+               /*
+                * Force the Prism header.
+                */
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               args[0] = 1;    /* request Prism header */
+               memcpy(ireq.u.name, args, sizeof (int));
+               ioctl(sock_fd, cmd, &ireq);
+               break;
+
+       case MONITOR_RT73:
+               /*
+                * Force the Prism header.
+                */
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               ireq.u.data.length = 1; /* 1 argument */
+               ireq.u.data.pointer = "1";
+               ireq.u.data.flags = 0;
+               ioctl(sock_fd, cmd, &ireq);
+               break;
+
+       case MONITOR_RTL8XXX:
+               /*
+                * Force the Prism header.
+                */
+               memset(&ireq, 0, sizeof ireq);
+               strncpy(ireq.ifr_ifrn.ifrn_name, device,
+                   sizeof ireq.ifr_ifrn.ifrn_name);
+               ireq.ifr_ifrn.ifrn_name[sizeof ireq.ifr_ifrn.ifrn_name - 1] = 0;
+               args[0] = 1;    /* request Prism header */
+               memcpy(ireq.u.name, args, sizeof (int));
+               ioctl(sock_fd, cmd, &ireq);
+               break;
        }
 
-       if (handle->md.device != NULL)
-               free(handle->md.device);
-       handle->md.device = NULL;
-       pcap_close_common(handle);
+       /*
+        * Note that we have to put the old mode back when we
+        * close the device.
+        */
+       handle->md.must_clear |= MUST_CLEAR_RFMON;
+
+       /*
+        * Add this to the list of pcaps to close when we exit.
+        */
+       pcap_add_to_pcaps_to_close(handle);
+
+       return 1;
+#else
+       /*
+        * We don't have the Wireless Extensions available, so we can't
+        * do monitor mode.
+        */
+       return 0;
+#endif
 }
 
+#endif /* HAVE_PF_PACKET_SOCKETS */
+
+/* ===== Functions to interface to the older kernels ================== */
+
 /*
- *  Try to open a packet socket using the old kernel interface.
- *  Returns 0 on failure.
- *  FIXME: 0 uses to mean success (Sebastian)
+ * Try to open a packet socket using the old kernel interface.
+ * Returns 1 on success and a PCAP_ERROR_ value on an error.
  */
 static int
-live_open_old(pcap_t *handle, const char *device, int promisc,
-             int to_ms, char *ebuf)
+activate_old(pcap_t *handle)
 {
        int             arptype;
        struct ifreq    ifr;
+       const char      *device = handle->opt.source;
        struct utsname  utsname;
        int             mtu;
 
-       do {
-               /* Open the socket */
+       /* Open the socket */
 
-               handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
-               if (handle->fd == -1) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                "socket: %s", pcap_strerror(errno));
-                       break;
-               }
+       handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
+       if (handle->fd == -1) {
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                        "socket: %s", pcap_strerror(errno));
+               return PCAP_ERROR;
+       }
 
-               /* It worked - we are using the old interface */
-               handle->md.sock_packet = 1;
+       /* It worked - we are using the old interface */
+       handle->md.sock_packet = 1;
 
-               /* ...which means we get the link-layer header. */
-               handle->md.cooked = 0;
+       /* ...which means we get the link-layer header. */
+       handle->md.cooked = 0;
 
-               /* Bind to the given device */
+       /* Bind to the given device */
 
-               if (!device) {
-                       strncpy(ebuf, "pcap_open_live: The \"any\" device isn't supported on 2.0[.x]-kernel systems",
-                               PCAP_ERRBUF_SIZE);
-                       break;
-               }
-               if (iface_bind_old(handle->fd, device, ebuf) == -1)
-                       break;
+       if (!device) {
+               strncpy(handle->errbuf, "pcap_activate: The \"any\" device isn't supported on 2.0[.x]-kernel systems",
+                       PCAP_ERRBUF_SIZE);
+               return PCAP_ERROR;
+       }
+       if (iface_bind_old(handle->fd, device, handle->errbuf) == -1)
+               return PCAP_ERROR;
 
-               /*
-                * Try to get the link-layer type.
-                */
-               arptype = iface_get_arptype(handle->fd, device, ebuf);
-               if (arptype == -1)
-                       break;
+       /*
+        * Try to get the link-layer type.
+        */
+       arptype = iface_get_arptype(handle->fd, device, handle->errbuf);
+       if (arptype < 0)
+               return PCAP_ERROR;
 
-               /*
-                * Try to find the DLT_ type corresponding to that
-                * link-layer type.
-                */
-               map_arphrd_to_dlt(handle, arptype, 0);
-               if (handle->linktype == -1) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                "unknown arptype %d", arptype);
-                       break;
-               }
+       /*
+        * Try to find the DLT_ type corresponding to that
+        * link-layer type.
+        */
+       map_arphrd_to_dlt(handle, arptype, 0);
+       if (handle->linktype == -1) {
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                        "unknown arptype %d", arptype);
+               return PCAP_ERROR;
+       }
 
-               /* Go to promisc mode if requested */
+       /* Go to promisc mode if requested */
 
-               if (promisc) {
-                       memset(&ifr, 0, sizeof(ifr));
-                       strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
-                       if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
-                               snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                        "SIOCGIFFLAGS: %s", pcap_strerror(errno));
-                               break;
-                       }
-                       if ((ifr.ifr_flags & IFF_PROMISC) == 0) {
-                               /*
-                                * Promiscuous mode isn't currently on,
-                                * so turn it on, and remember that
-                                * we should turn it off when the
-                                * pcap_t is closed.
-                                */
+       if (handle->opt.promisc) {
+               memset(&ifr, 0, sizeof(ifr));
+               strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+               if (ioctl(handle->fd, SIOCGIFFLAGS, &ifr) == -1) {
+                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                "SIOCGIFFLAGS: %s", pcap_strerror(errno));
+                       return PCAP_ERROR;
+               }
+               if ((ifr.ifr_flags & IFF_PROMISC) == 0) {
+                       /*
+                        * Promiscuous mode isn't currently on,
+                        * so turn it on, and remember that
+                        * we should turn it off when the
+                        * pcap_t is closed.
+                        */
 
+                       /*
+                        * If we haven't already done so, arrange
+                        * to have "pcap_close_all()" called when
+                        * we exit.
+                        */
+                       if (!pcap_do_addexit(handle)) {
                                /*
-                                * If we haven't already done so, arrange
-                                * to have "pcap_close_all()" called when
-                                * we exit.
+                                * "atexit()" failed; don't put
+                                * the interface in promiscuous
+                                * mode, just give up.
                                 */
-                               if (!did_atexit) {
-                                       if (atexit(pcap_close_all) == -1) {
-                                               /*
-                                                * "atexit()" failed; don't
-                                                * put the interface in
-                                                * promiscuous mode, just
-                                                * give up.
-                                                */
-                                               strncpy(ebuf, "atexit failed",
-                                                       PCAP_ERRBUF_SIZE);
-                                               break;
-                                       }
-                                       did_atexit = 1;
-                               }
-
-                               ifr.ifr_flags |= IFF_PROMISC;
-                               if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
-                                       snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                                                "SIOCSIFFLAGS: %s",
-                                                pcap_strerror(errno));
-                                       break;
-                               }
-                               handle->md.clear_promisc = 1;
+                               return PCAP_ERROR;
+                       }
 
-                               /*
-                                * Add this to the list of pcaps
-                                * to close when we exit.
-                                */
-                               handle->md.next = pcaps_to_close;
-                               pcaps_to_close = handle;
+                       ifr.ifr_flags |= IFF_PROMISC;
+                       if (ioctl(handle->fd, SIOCSIFFLAGS, &ifr) == -1) {
+                               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                        "SIOCSIFFLAGS: %s",
+                                        pcap_strerror(errno));
+                               return PCAP_ERROR;
                        }
+                       handle->md.must_clear |= MUST_CLEAR_PROMISC;
+
+                       /*
+                        * Add this to the list of pcaps
+                        * to close when we exit.
+                        */
+                       pcap_add_to_pcaps_to_close(handle);
                }
+       }
 
+       /*
+        * Compute the buffer size.
+        *
+        * We're using SOCK_PACKET, so this might be a 2.0[.x]
+        * kernel, and might require special handling - check.
+        */
+       if (uname(&utsname) < 0 ||
+           strncmp(utsname.release, "2.0", 3) == 0) {
                /*
-                * Compute the buffer size.
+                * Either we couldn't find out what kernel release
+                * this is, or it's a 2.0[.x] kernel.
+                *
+                * In the 2.0[.x] kernel, a "recvfrom()" on
+                * a SOCK_PACKET socket, with MSG_TRUNC set, will
+                * return the number of bytes read, so if we pass
+                * a length based on the snapshot length, it'll
+                * return the number of bytes from the packet
+                * copied to userland, not the actual length
+                * of the packet.
+                *
+                * This means that, for example, the IP dissector
+                * in tcpdump will get handed a packet length less
+                * than the length in the IP header, and will
+                * complain about "truncated-ip".
+                *
+                * So we don't bother trying to copy from the
+                * kernel only the bytes in which we're interested,
+                * but instead copy them all, just as the older
+                * versions of libpcap for Linux did.
+                *
+                * The buffer therefore needs to be big enough to
+                * hold the largest packet we can get from this
+                * device.  Unfortunately, we can't get the MRU
+                * of the network; we can only get the MTU.  The
+                * MTU may be too small, in which case a packet larger
+                * than the buffer size will be truncated *and* we
+                * won't get the actual packet size.
                 *
-                * We're using SOCK_PACKET, so this might be a 2.0[.x]
-                * kernel, and might require special handling - check.
+                * However, if the snapshot length is larger than
+                * the buffer size based on the MTU, we use the
+                * snapshot length as the buffer size, instead;
+                * this means that with a sufficiently large snapshot
+                * length we won't artificially truncate packets
+                * to the MTU-based size.
+                *
+                * This mess just one of many problems with packet
+                * capture on 2.0[.x] kernels; you really want a
+                * 2.2[.x] or later kernel if you want packet capture
+                * to work well.
                 */
-               if (uname(&utsname) < 0 ||
-                   strncmp(utsname.release, "2.0", 3) == 0) {
-                       /*
-                        * Either we couldn't find out what kernel release
-                        * this is, or it's a 2.0[.x] kernel.
-                        *
-                        * In the 2.0[.x] kernel, a "recvfrom()" on
-                        * a SOCK_PACKET socket, with MSG_TRUNC set, will
-                        * return the number of bytes read, so if we pass
-                        * a length based on the snapshot length, it'll
-                        * return the number of bytes from the packet
-                        * copied to userland, not the actual length
-                        * of the packet.
-                        *
-                        * This means that, for example, the IP dissector
-                        * in tcpdump will get handed a packet length less
-                        * than the length in the IP header, and will
-                        * complain about "truncated-ip".
-                        *
-                        * So we don't bother trying to copy from the
-                        * kernel only the bytes in which we're interested,
-                        * but instead copy them all, just as the older
-                        * versions of libpcap for Linux did.
-                        *
-                        * The buffer therefore needs to be big enough to
-                        * hold the largest packet we can get from this
-                        * device.  Unfortunately, we can't get the MRU
-                        * of the network; we can only get the MTU.  The
-                        * MTU may be too small, in which case a packet larger
-                        * than the buffer size will be truncated *and* we
-                        * won't get the actual packet size.
-                        *
-                        * However, if the snapshot length is larger than
-                        * the buffer size based on the MTU, we use the
-                        * snapshot length as the buffer size, instead;
-                        * this means that with a sufficiently large snapshot
-                        * length we won't artificially truncate packets
-                        * to the MTU-based size.
-                        *
-                        * This mess just one of many problems with packet
-                        * capture on 2.0[.x] kernels; you really want a
-                        * 2.2[.x] or later kernel if you want packet capture
-                        * to work well.
-                        */
-                       mtu = iface_get_mtu(handle->fd, device, ebuf);
-                       if (mtu == -1)
-                               break;
-                       handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
-                       if (handle->bufsize < handle->snapshot)
-                               handle->bufsize = handle->snapshot;
-               } else {
-                       /*
-                        * This is a 2.2[.x] or later kernel.
-                        *
-                        * We can safely pass "recvfrom()" a byte count
-                        * based on the snapshot length.
-                        */
+               mtu = iface_get_mtu(handle->fd, device, handle->errbuf);
+               if (mtu == -1)
+                       return PCAP_ERROR;
+               handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
+               if (handle->bufsize < handle->snapshot)
                        handle->bufsize = handle->snapshot;
-               }
-
+       } else {
                /*
-                * Default value for offset to align link-layer payload
-                * on a 4-byte boundary.
+                * This is a 2.2[.x] or later kernel.
+                *
+                * We can safely pass "recvfrom()" a byte count
+                * based on the snapshot length.
                 */
-               handle->offset   = 0;
-
-               return 1;
+               handle->bufsize = handle->snapshot;
+       }
 
-       } while (0);
+       /*
+        * Default value for offset to align link-layer payload
+        * on a 4-byte boundary.
+        */
+       handle->offset   = 0;
 
-       pcap_close_linux(handle);
-       return 0;
+       return 1;
 }
 
 /*
@@ -2387,9 +3007,15 @@ iface_get_arptype(int fd, const char *device, char *ebuf)
        strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
 
        if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
+               if (errno == ENODEV) {
+                       /*
+                        * No such device.
+                        */
+                       return PCAP_ERROR_NO_SUCH_DEVICE;
+               }
                snprintf(ebuf, PCAP_ERRBUF_SIZE,
                         "SIOCGIFHWADDR: %s", pcap_strerror(errno));
-               return -1;
+               return PCAP_ERROR;
        }
 
        return ifr.ifr_hwaddr.sa_family;
@@ -2413,7 +3039,7 @@ fix_program(pcap_t *handle, struct sock_fprog *fcode)
        len = handle->fcode.bf_len;
        f = (struct bpf_insn *)malloc(prog_size);
        if (f == NULL) {
-               snprintf(handle->errbuf, sizeof(handle->errbuf),
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                         "malloc: %s", pcap_strerror(errno));
                return -1;
        }
@@ -2585,7 +3211,7 @@ set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode)
                        if (save_errno != EAGAIN) {
                                /* Fatal error */
                                reset_kernel_filter(handle);
-                               snprintf(handle->errbuf, sizeof(handle->errbuf),
+                               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                                 "recv: %s", pcap_strerror(save_errno));
                                return -2;
                        }
index 3b38583aeb0aa383f3e0216fa090ef4cdcdb9d86..df1d2846738eab661476f7cca9b48938a41c5a86 100644 (file)
@@ -20,7 +20,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.58.2.2 2008-02-02 20:58:31 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.58.2.3 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -237,51 +237,43 @@ nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
        return (0);
 }
 
-static void
-pcap_close_nit(pcap_t *p)
-{
-       pcap_close_common(p);
-       if (p->device != NULL)
-               free(p->device);
-}
-
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+static int
+pcap_activate_nit(pcap_t *p)
 {
        int fd;
        struct sockaddr_nit snit;
-       register pcap_t *p;
 
-       p = (pcap_t *)malloc(sizeof(*p));
-       if (p == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
-               return (NULL);
+       if (p->opt.rfmon) {
+               /*
+                * No monitor mode on SunOS 3.x or earlier (no
+                * Wi-Fi *devices* for the hardware that supported
+                * them!).
+                */
+               return (PCAP_ERROR_RFMON_NOTSUP);
        }
 
-       if (snaplen < 96)
+       if (p->snapshot < 96)
                /*
                 * NIT requires a snapshot length of at least 96.
                 */
-               snaplen = 96;
+               p->snapshot = 96;
 
        memset(p, 0, sizeof(*p));
        p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
        if (fd < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "socket: %s", pcap_strerror(errno));
                goto bad;
        }
        snit.snit_family = AF_NIT;
-       (void)strncpy(snit.snit_ifname, device, NITIFSIZ);
+       (void)strncpy(snit.snit_ifname, p->opt.source, NITIFSIZ);
 
        if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
                    "bind: %s: %s", snit.snit_ifname, pcap_strerror(errno));
                goto bad;
        }
-       p->snapshot = snaplen;
-       nit_setflags(p->fd, promisc, to_ms, ebuf);
+       nit_setflags(p->fd, p->opt.promisc, p->md.timeout, p->errbuf);
 
        /*
         * NIT supports only ethernets.
@@ -291,17 +283,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->bufsize = BUFSPACE;
        p->buffer = (u_char *)malloc(p->bufsize);
        if (p->buffer == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
-               goto bad;
-       }
-
-       /*
-        * We need the device name in order to send packets.
-        */
-       p->device = strdup(device);
-       if (p->device == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
-               free(p->buffer);
+               strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
                goto bad;
        }
 
@@ -338,14 +320,26 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->getnonblock_op = pcap_getnonblock_fd;
        p->setnonblock_op = pcap_setnonblock_fd;
        p->stats_op = pcap_stats_nit;
-       p->close_op = pcap_close_nit;
+       p->close_op = pcap_close_common;
 
-       return (p);
+       return (0);
  bad:
        if (fd >= 0)
                close(fd);
-       free(p);
-       return (NULL);
+       return (PCAP_ERROR);
+}
+
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_nit;
+       return (p);
 }
 
 int
index 7831632782fe694e8d9c92f5dcb73a54ce80d487..f72a0c3c4e09d0920a860d22fbd9aa0e1ca2b9b7 100644 (file)
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 #ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-null.c,v 1.7.1.1 1999-10-07 23:46:40 mcr Exp $ (LBL)";
+static const char rcsid[] _U_ =
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-null.c,v 1.21.4.1 2008-04-04 19:39:06 guy Exp $ (LBL)";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
 #endif
 
 #include <sys/param.h>                 /* optionally get BSD define */
 
 #include <string.h>
 
-#include "gnuc.h"
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
 #endif
@@ -36,38 +39,15 @@ static const char rcsid[] =
 
 static char nosup[] = "live packet capture not supported on this system";
 
-int
-pcap_stats(pcap_t *p, struct pcap_stat *ps)
-{
-
-       (void)sprintf(p->errbuf, "pcap_stats: %s", nosup);
-       return (-1);
-}
-
-int
-pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
-{
-
-       (void)sprintf(p->errbuf, "pcap_read: %s", nosup);
-       return (-1);
-}
-
 pcap_t *
-pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+pcap_activate(pcap_t *p)
 {
-
-       (void)strcpy(ebuf, nosup);
+       (void)strlcpy(p->errbuf, nosup, PCAP_ERRBUF_SIZE);
        return (NULL);
 }
 
 int
-pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
 {
-
-       if (p->sf.rfile == NULL) {
-               (void)sprintf(p->errbuf, "pcap_setfilter: %s", nosup);
-               return (-1);
-       }
-       p->fcode = *fp;
        return (0);
 }
index d8fae3aaeb03670a6dd0d1c51019b811dac58a5c..afcaf396117d5b86416a95b834e07f2b2f931775 100644 (file)
--- a/pcap-pf.c
+++ b/pcap-pf.c
@@ -24,7 +24,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.94.2.1 2007-12-05 23:38:11 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.94.2.2 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -291,23 +291,14 @@ pcap_stats_pf(pcap_t *p, struct pcap_stat *ps)
 #define DLT_DOCSIS     143
 #endif
 
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+static int
+pcap_activate_pf(pcap_t *p)
 {
-       pcap_t *p;
        short enmode;
        int backlog = -1;       /* request the most */
        struct enfilter Filter;
        struct endevp devparams;
 
-       p = (pcap_t *)malloc(sizeof(*p));
-       if (p == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
-                   "pcap_open_live: %s", pcap_strerror(errno));
-               return (0);
-       }
-       memset(p, 0, sizeof(*p));
        /*
         * Initially try a read/write open (to allow the inject
         * method to work).  If that fails due to permission
@@ -327,21 +318,21 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         * "const char *" as its first argument.  That appears to be
         * the case, at least on Digital UNIX 4.0.
         */
-       p->fd = pfopen(device, O_RDWR);
+       p->fd = pfopen(p->opt.source, O_RDWR);
        if (p->fd == -1 && errno == EACCES)
-               p->fd = pfopen(device, O_RDONLY);
+               p->fd = pfopen(p->opt.source, O_RDONLY);
        if (p->fd < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\
 your system may not be properly configured; see the packetfilter(4) man page\n",
-                       device, pcap_strerror(errno));
+                       p->opt.source, pcap_strerror(errno));
                goto bad;
        }
        p->md.OrigMissed = -1;
        enmode = ENTSTAMP|ENBATCH|ENNONEXCL;
-       if (promisc)
+       if (p->opt.promisc)
                enmode |= ENPROMISC;
        if (ioctl(p->fd, EIOCMBIS, (caddr_t)&enmode) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCMBIS: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCMBIS: %s",
                    pcap_strerror(errno));
                goto bad;
        }
@@ -352,13 +343,13 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
 #endif
        /* set the backlog */
        if (ioctl(p->fd, EIOCSETW, (caddr_t)&backlog) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSETW: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSETW: %s",
                    pcap_strerror(errno));
                goto bad;
        }
        /* discover interface type */
        if (ioctl(p->fd, EIOCDEVP, (caddr_t)&devparams) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCDEVP: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCDEVP: %s",
                    pcap_strerror(errno));
                goto bad;
        }
@@ -440,8 +431,8 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
                 * framing", there's not much we can do, as that
                 * doesn't specify a particular type of header.
                 */
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown data-link type %u",
-                   devparams.end_dev_type);
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "unknown data-link type %u", devparams.end_dev_type);
                goto bad;
        }
        /* set truncation */
@@ -450,32 +441,31 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
                p->fddipad = PCAP_FDDIPAD;
 
                /* packetfilter includes the padding in the snapshot */
-               snaplen += PCAP_FDDIPAD;
+               p->snapshot += PCAP_FDDIPAD;
        } else
                p->fddipad = 0;
 #endif
-       if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&snaplen) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s",
+       if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&p->snapshot) < 0) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s",
                    pcap_strerror(errno));
                goto bad;
        }
-       p->snapshot = snaplen;
        /* accept all packets */
        memset(&Filter, 0, sizeof(Filter));
        Filter.enf_Priority = 37;       /* anything > 2 */
        Filter.enf_FilterLen = 0;       /* means "always true" */
        if (ioctl(p->fd, EIOCSETF, (caddr_t)&Filter) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSETF: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSETF: %s",
                    pcap_strerror(errno));
                goto bad;
        }
 
-       if (to_ms != 0) {
+       if (p->md.timeout != 0) {
                struct timeval timeout;
-               timeout.tv_sec = to_ms / 1000;
-               timeout.tv_usec = (to_ms * 1000) % 1000000;
+               timeout.tv_sec = p->md.timeout / 1000;
+               timeout.tv_usec = (p->md.timeout * 1000) % 1000000;
                if (ioctl(p->fd, EIOCSRTIMEOUT, (caddr_t)&timeout) < 0) {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCSRTIMEOUT: %s",
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "EIOCSRTIMEOUT: %s",
                                pcap_strerror(errno));
                        goto bad;
                }
@@ -484,7 +474,7 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
        p->bufsize = BUFSPACE;
        p->buffer = (u_char*)malloc(p->bufsize + p->offset);
        if (p->buffer == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
+               strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
                goto bad;
        }
 
@@ -503,17 +493,24 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
        p->stats_op = pcap_stats_pf;
        p->close_op = pcap_close_common;
 
-       return (p);
+       return (0);
  bad:
        if (p->fd >= 0)
                close(p->fd);
-       /*
-        * Get rid of any link-layer type list we allocated.
-        */
-       if (p->dlt_list != NULL)
-               free(p->dlt_list);
-       free(p);
-       return (NULL);
+       return (PCAP_ERROR);
+}
+
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_pf;
+       return (p);
 }
 
 int
diff --git a/pcap-septel.c b/pcap-septel.c
new file mode 100644 (file)
index 0000000..4c63323
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * pcap-septel.c: Packet capture interface for Intel/Septel card.
+ *
+ * The functionality of this code attempts to mimic that of pcap-linux as much
+ * as possible.  This code is compiled in several different ways depending on
+ * whether SEPTEL_ONLY and HAVE_SEPTEL_API are defined.  If HAVE_SEPTEL_API is
+ * not defined it should not get compiled in, otherwise if SEPTEL_ONLY is
+ * defined then the 'septel_' function calls are renamed to 'pcap_'
+ * equivalents.  If SEPTEL_ONLY is not defined then nothing is altered - the
+ * septel_ functions will be called as required from their
+ * pcap-linux/equivalents.
+ *
+ * Authors: Gilbert HOYEK ([email protected]), Elias M. KHOURY
+ * (+961 3 485243)
+ */
+
+#ifndef lint
+static const char rcsid[] _U_ =
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-septel.c,v 1.2.2.1 2008-04-04 19:39:06 guy Exp $";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/param.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "pcap-int.h"
+
+#include <ctype.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef HAVE_SEPTEL_API
+#include <msg.h>
+#include <ss7_inc.h>
+#include <sysgct.h>
+#include <pack.h>
+#include <system.h>
+#endif /* HAVE_SEPTEL_API */
+
+#ifdef SEPTEL_ONLY
+/* This code is required when compiling for a Septel device only. */
+#include "pcap-septel.h"
+
+/* Replace septel function names with pcap equivalent. */
+#define septel_create pcap_create
+#define septel_platform_finddevs pcap_platform_finddevs
+#endif /* SEPTEL_ONLY */
+
+static int septel_setfilter(pcap_t *p, struct bpf_program *fp);
+static int septel_stats(pcap_t *p, struct pcap_stat *ps);
+static int septel_setnonblock(pcap_t *p, int nonblock, char *errbuf);
+
+static void septel_platform_close(pcap_t *p) {
+
+}
+
+
+
+/*
+ *  Read at most max_packets from the capture queue and call the callback
+ *  for each of them. Returns the number of packets handled, -1 if an
+ *  error occured, or -2 if we were told to break out of the loop.
+ */
+static int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {
+
+  HDR *h;
+  MSG *m;
+  int processed = 0 ;
+  int t = 0 ;
+
+  /* identifier for the message queue of the module(upe) from which we are capturing
+   * packets.These IDs are defined in system.txt . By default it is set to 0x2d
+   * so change it to 0xdd for technical reason and therefore the module id for upe becomes:
+   * LOCAL        0xdd           * upe - Example user part task */
+  unsigned int id = 0xdd;
+
+  /* process the packets */
+  do  {
+
+    unsigned short packet_len = 0;
+    int caplen = 0;
+    int counter = 0;
+    struct pcap_pkthdr   pcap_header;
+    u_char *dp ;
+
+    /*
+     * Has "pcap_breakloop()" been called?
+     */
+loop:
+    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;
+    }
+
+    /*repeat until a packet is read
+     *a NULL message means :
+     * when no packet is in queue or all packets in queue already read */
+    do  {
+      /* receive packet in non-blocking mode
+       * GCT_grab is defined in the septel library software */
+      h = GCT_grab(id);
+
+      m = (MSG*)h;
+      /* a couter is added here to avoid an infinite loop
+       * that will cause our capture program GUI to freeze while waiting
+       * for a packet*/
+      counter++ ;
+
+    }
+    while  ((m == NULL)&& (counter< 100)) ;
+
+    if (m != NULL) {
+
+      t = h->type ;
+
+      /* catch only messages with type = 0xcf00 or 0x8f01 corrsponding to ss7 messages*/
+      /* XXX = why not use API_MSG_TX_REQ for 0xcf00 and API_MSG_RX_IND
+       * for 0x8f01? */
+      if ((t != 0xcf00) && (t != 0x8f01)) {
+        relm(h);
+        goto loop ;
+      }
+
+      /* XXX - is API_MSG_RX_IND for an MTP2 or MTP3 message? */
+      dp = get_param(m);/* get pointer to MSG parameter area (m->param) */
+      packet_len = m->len;
+      caplen =  p->snapshot ;
+
+
+      if (caplen > packet_len) {
+
+        caplen = packet_len;
+      }
+      /* Run the packet filter if there is one. */
+      if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
+
+
+        /*  get a time stamp , consisting of :
+         *
+         *  pcap_header.ts.tv_sec:
+         *  ----------------------
+         *   a UNIX format time-in-seconds when he packet was captured,
+         *   i.e. the number of seconds since Epoch time (January 1,1970, 00:00:00 GMT)
+         *
+         *  pcap_header.ts.tv_usec :
+         *  ------------------------
+         *   the number of microseconds since that second
+         *   when the packet was captured
+         */
+
+        (void)gettimeofday(&pcap_header.ts, NULL);
+
+        /* Fill in our own header data */
+        pcap_header.caplen = caplen;
+        pcap_header.len = packet_len;
+
+        /* Count the packet. */
+        p->md.stat.ps_recv++;
+
+        /* Call the user supplied callback function */
+        callback(user, &pcap_header, dp);
+
+        processed++ ;
+
+      }
+      /* after being processed the packet must be
+       *released in order to receive another one */
+      relm(h);
+    }else
+      processed++;
+
+  }
+  while (processed < cnt) ;
+
+  return processed ;
+}
+
+
+static int
+septel_inject(pcap_t *handle, const void *buf _U_, size_t size _U_)
+{
+  strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards",
+          PCAP_ERRBUF_SIZE);
+  return (-1);
+}
+
+/*
+ *  Activate a handle for a live capture from the given Septel device.  Always pass a NULL device
+ *  The promisc flag is ignored because Septel cards have built-in tracing.
+ *  The timeout is also ignored as it is not supported in hardware.
+ *
+ *  See also pcap(3).
+ */
+static pcap_t *septel_activate(pcap_t* handle) {
+  /* Initialize some components of the pcap structure. */  
+  handle->linktype = DLT_MTP2;
+  
+  handle->bufsize = 0;
+
+  /*
+   * "select()" and "poll()" don't work on Septel queues
+   */
+  handle->selectable_fd = -1;
+
+  handle->read_op = septel_read;
+  handle->inject_op = septel_inject;
+  handle->setfilter_op = septel_setfilter;
+  handle->set_datalink_op = NULL; /* can't change data link type */
+  handle->getnonblock_op = pcap_getnonblock_fd;
+  handle->setnonblock_op = septel_setnonblock;
+  handle->stats_op = septel_stats;
+  handle->close_op = septel_platform_close;
+
+  return 0;
+}
+
+pcap_t *septel_create(const char *device, char *ebuf) {
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return NULL;
+
+       p->activate_op = septel_activate;
+       return p;
+}
+
+static int septel_stats(pcap_t *p, struct pcap_stat *ps) {
+  /*p->md.stat.ps_recv = 0;*/
+  /*p->md.stat.ps_drop = 0;*/
+  
+  *ps = p->md.stat;
+  return 0;
+}
+
+
+int
+septel_platform_finddevs(pcap_if_t **devlistp, char *errbuf)
+{
+unsigned char *p;
+  const char description[512]= "Intel/Septel device";
+  char name[512]="septel" ;
+  int ret = 0;
+  pcap_add_if(devlistp,name,0,description,errbuf);
+
+  return (ret); 
+}
+
+
+/*
+ * Installs the given bpf filter program in the given pcap structure.  There is
+ * no attempt to store the filter in kernel memory as that is not supported
+ * with Septel cards.
+ */
+static int septel_setfilter(pcap_t *p, struct bpf_program *fp) {
+  if (!p)
+    return -1;
+  if (!fp) {
+    strncpy(p->errbuf, "setfilter: No filter specified",
+           sizeof(p->errbuf));
+    return -1;
+  }
+
+  /* Make our private copy of the filter */
+
+  if (install_bpf_program(p, fp) < 0) {
+    snprintf(p->errbuf, sizeof(p->errbuf),
+            "malloc: %s", pcap_strerror(errno));
+    return -1;
+  }
+
+  p->md.use_bpf = 0;
+
+  return (0);
+}
+
+
+static int
+septel_setnonblock(pcap_t *p, int nonblock, char *errbuf)
+{
+  return (0);
+}
diff --git a/pcap-septel.h b/pcap-septel.h
new file mode 100644 (file)
index 0000000..c916797
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * pcap-septel.c: Packet capture interface for Intel Septel card
+ *
+ * The functionality of this code attempts to mimic that of pcap-linux as much
+ * as possible.  This code is only needed when compiling in the Intel/Septel
+ * card code at the same time as another type of device.
+ *
+ * Authors: Gilbert HOYEK ([email protected]), Elias M. KHOURY
+ * (+961 3 485343);
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-septel.h,v 1.1.4.1 2008-04-04 19:39:06 guy Exp $
+ */
+
+pcap_t *septel_create(const char *device, char *ebuf);
+
index 658362c75811dd4155e89abccd0dc771c1d83414..8634922fb215610848b42c57a5711c49efc305a1 100644 (file)
@@ -917,25 +917,19 @@ static int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback,
        return 1;
 }
 
-pcap_t *pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf) {
-       pcap_t          *handle;
+static int pcap_activate_sita(pcap_t *handle) {
        int             fd;
 
-       /* Allocate a handle for this session. */
-
-       handle = malloc(sizeof(*handle));
-       if (handle == NULL) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
-                        pcap_strerror(errno));
-               return NULL;
+       if (handle->opt.rfmon) {
+               /*
+                * No monitor mode on SITA devices (they're not Wi-Fi
+                * devices).
+                */
+               return PCAP_ERROR_RFMON_NOTSUP;
        }
 
        /* Initialize some components of the pcap structure. */
 
-       memset(handle, 0, sizeof(*handle));
-       handle->snapshot        = snaplen;
-       handle->md.timeout      = to_ms;
-
        handle->inject_op = pcap_inject_acn;
        handle->setfilter_op = pcap_setfilter_acn;
        handle->setdirection_op = pcap_setdirection_acn;
@@ -946,12 +940,11 @@ pcap_t *pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        handle->read_op = pcap_read_acn;
        handle->stats_op = pcap_stats_acn;
 
-       fd = acn_open_live(device, ebuf, &handle->linktype);
-       if (fd == -1) {
-               free(handle);
-               return NULL;
-       }
-       handle->md.clear_promisc = promisc;
+       fd = acn_open_live(handle->opt.source, handle->errbuf,
+           &handle->linktype);
+       if (fd == -1)
+               return PCAP_ERROR;
+       handle->md.clear_promisc = handle->md.promisc;
        handle->fd = fd;
        handle->bufsize = handle->snapshot;
 
@@ -959,11 +952,10 @@ pcap_t *pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
 
        handle->buffer   = malloc(handle->bufsize + handle->offset);
        if (!handle->buffer) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                         "malloc: %s", pcap_strerror(errno));
                pcap_close_acn(handle);
-               free(handle);
-               return NULL;
+               return PCAP_ERROR;
        }
 
        /*
@@ -972,5 +964,16 @@ pcap_t *pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
         */
        handle->selectable_fd = handle->fd;
 
-       return handle;
+       return 0;
+}
+
+pcap_t *pcap_create(const char *device, char *ebuf) {
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_sita;
+       return (p);
 }
index e97948c7e1d645618939ce22711d1bb0a0ed68e2..1c82460fd9de082d6b82faa567ab2e6839fef870 100644 (file)
@@ -25,7 +25,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-snit.c,v 1.73.2.2 2008-02-02 20:58:31 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-snit.c,v 1.73.2.3 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -260,30 +260,29 @@ nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
        return (0);
 }
 
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+static int
+pcap_activate_snit(pcap_t *p)
 {
        struct strioctl si;             /* struct for ioctl() */
        struct ifreq ifr;               /* interface request struct */
        int chunksize = CHUNKSIZE;
        int fd;
        static char dev[] = "/dev/nit";
-       register pcap_t *p;
 
-       p = (pcap_t *)malloc(sizeof(*p));
-       if (p == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
-               return (NULL);
+       if (p->opt.rfmon) {
+               /*
+                * No monitor mode on SunOS 4.x (no Wi-Fi devices on
+                * hardware supported by SunOS 4.x).
+                */
+               return (PCAP_ERROR_RFMON_NOTSUP);
        }
 
-       if (snaplen < 96)
+       if (p->snapshot < 96)
                /*
                 * NIT requires a snapshot length of at least 96.
                 */
-               snaplen = 96;
+               p->snapshot = 96;
 
-       memset(p, 0, sizeof(*p));
        /*
         * Initially try a read/write open (to allow the inject
         * method to work).  If that fails due to permission
@@ -302,19 +301,19 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        if (fd < 0 && errno == EACCES)
                p->fd = fd = open(dev, O_RDONLY);
        if (fd < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dev,
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dev,
                    pcap_strerror(errno));
                goto bad;
        }
 
        /* arrange to get discrete messages from the STREAM and use NIT_BUF */
        if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "I_SRDOPT: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "I_SRDOPT: %s",
                    pcap_strerror(errno));
                goto bad;
        }
        if (ioctl(fd, I_PUSH, "nbuf") < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "push nbuf: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "push nbuf: %s",
                    pcap_strerror(errno));
                goto bad;
        }
@@ -324,34 +323,33 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        si.ic_len = sizeof(chunksize);
        si.ic_dp = (char *)&chunksize;
        if (ioctl(fd, I_STR, (char *)&si) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "NIOCSCHUNK: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSCHUNK: %s",
                    pcap_strerror(errno));
                goto bad;
        }
 
        /* request the interface */
-       strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+       strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name));
        ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
        si.ic_cmd = NIOCBIND;
        si.ic_len = sizeof(ifr);
        si.ic_dp = (char *)&ifr;
        if (ioctl(fd, I_STR, (char *)&si) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "NIOCBIND: %s: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCBIND: %s: %s",
                        ifr.ifr_name, pcap_strerror(errno));
                goto bad;
        }
 
        /* set the snapshot length */
        si.ic_cmd = NIOCSSNAP;
-       si.ic_len = sizeof(snaplen);
-       si.ic_dp = (char *)&snaplen;
+       si.ic_len = sizeof(p->snapshot);
+       si.ic_dp = (char *)&p->snapshot;
        if (ioctl(fd, I_STR, (char *)&si) < 0) {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "NIOCSSNAP: %s",
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "NIOCSSNAP: %s",
                    pcap_strerror(errno));
                goto bad;
        }
-       p->snapshot = snaplen;
-       if (nit_setflags(p->fd, promisc, to_ms, ebuf) < 0)
+       if (nit_setflags(p->fd, p->opt.promisc, p->md.timeout, p->errbuf) < 0)
                goto bad;
 
        (void)ioctl(fd, I_FLUSH, (char *)FLUSHR);
@@ -363,7 +361,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->bufsize = BUFSPACE;
        p->buffer = (u_char *)malloc(p->bufsize);
        if (p->buffer == NULL) {
-               strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
+               strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
                goto bad;
        }
 
@@ -403,12 +401,24 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->stats_op = pcap_stats_snit;
        p->close_op = pcap_close_common;
 
-       return (p);
+       return (0);
  bad:
        if (fd >= 0)
                close(fd);
-       free(p);
-       return (NULL);
+       return (PCAP_ERROR);
+}
+
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_snit;
+       return (p);
 }
 
 int
index be913390b409646fa38e449d28a56533e9057101..9404a4b75b40da02d69485b178a2c303e0d01edc 100644 (file)
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 #ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.20.1.1 1999-10-07 23:46:40 mcr Exp $ (LBL)";
+static const char rcsid[] _U_ =
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.55.2.1 2008-04-04 19:39:06 guy Exp $ (LBL)";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
 #endif
 
 #include <sys/param.h>
@@ -50,45 +54,79 @@ static const char rcsid[] =
 
 #include "pcap-int.h"
 
-#include "gnuc.h"
 #ifdef HAVE_OS_PROTO_H
 #include "os-proto.h"
 #endif
 
-int
-pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+static int
+pcap_read_snoop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
 {
        int cc;
        register struct snoopheader *sh;
-       register int datalen;
-       register int caplen;
+       register u_int datalen;
+       register u_int caplen;
        register u_char *cp;
 
 again:
+       /*
+        * 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);
+       }
        cc = read(p->fd, (char *)p->buffer, p->bufsize);
        if (cc < 0) {
                /* Don't choke when we get ptraced */
                switch (errno) {
 
                case EINTR:
-                               goto again;
+                       goto again;
 
                case EWOULDBLOCK:
                        return (0);                     /* XXX */
                }
-               sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
+               snprintf(p->errbuf, sizeof(p->errbuf),
+                   "read: %s", pcap_strerror(errno));
                return (-1);
        }
        sh = (struct snoopheader *)p->buffer;
        datalen = sh->snoop_packetlen;
+
+       /*
+        * XXX - Sigh, snoop_packetlen is a 16 bit quantity.  If we
+        * got a short length, but read a full sized snoop pakcet,
+        * assume we overflowed and add back the 64K...
+        */
+       if (cc == (p->snapshot + sizeof(struct snoopheader)) &&
+           (datalen < p->snapshot))
+               datalen += (64 * 1024);
+
        caplen = (datalen < p->snapshot) ? datalen : p->snapshot;
        cp = (u_char *)(sh + 1) + p->offset;            /* XXX */
 
+       /* 
+        * XXX unfortunately snoop loopback isn't exactly like
+        * BSD's.  The address family is encoded in the first 2
+        * bytes rather than the first 4 bytes!  Luckily the last
+        * two snoop loopback bytes are zeroed.
+        */
+       if (p->linktype == DLT_NULL && *((short *)(cp + 2)) == 0) {
+               u_int *uip = (u_int *)cp;
+               *uip >>= 16;
+       }
+
        if (p->fcode.bf_insns == NULL ||
            bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) {
                struct pcap_pkthdr h;
                ++p->md.stat.ps_recv;
-               h.ts = sh->snoop_timestamp;
+               h.ts.tv_sec = sh->snoop_timestamp.tv_sec;
+               h.ts.tv_usec = sh->snoop_timestamp.tv_usec;
                h.len = datalen;
                h.caplen = caplen;
                (*callback)(user, &h, cp);
@@ -97,120 +135,276 @@ again:
        return (0);
 }
 
-int
-pcap_stats(pcap_t *p, struct pcap_stat *ps)
+static int
+pcap_inject_snoop(pcap_t *p, const void *buf, size_t size)
+{
+       int ret;
+
+       /*
+        * XXX - libnet overwrites the source address with what I
+        * presume is the interface's address; is that required?
+        */
+       ret = write(p->fd, buf, size);
+       if (ret == -1) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
+                   pcap_strerror(errno));
+               return (-1);
+       }
+       return (ret);
+}                           
+
+static int
+pcap_stats_snoop(pcap_t *p, struct pcap_stat *ps)
 {
        register struct rawstats *rs;
        struct rawstats rawstats;
 
        rs = &rawstats;
-       bzero((char *)rs, sizeof(*rs));
+       memset(rs, 0, sizeof(*rs));
        if (ioctl(p->fd, SIOCRAWSTATS, (char *)rs) < 0) {
-               sprintf(p->errbuf, "SIOCRAWSTATS: %s", pcap_strerror(errno));
+               snprintf(p->errbuf, sizeof(p->errbuf),
+                   "SIOCRAWSTATS: %s", pcap_strerror(errno));
                return (-1);
        }
 
+       /*
+        * "ifdrops" are those dropped by the network interface
+        * due to resource shortages or hardware errors.
+        *
+        * "sbdrops" are those dropped due to socket buffer limits.
+        *
+        * As filter is done in userland, "sbdrops" counts packets
+        * regardless of whether they would've passed the filter.
+        *
+        * XXX - does this count *all* Snoop or Drain sockets,
+        * rather than just this socket?  If not, why does it have
+        * both Snoop and Drain statistics?
+        */
        p->md.stat.ps_drop =
            rs->rs_snoop.ss_ifdrops + rs->rs_snoop.ss_sbdrops +
            rs->rs_drain.ds_ifdrops + rs->rs_drain.ds_sbdrops;
 
+       /*
+        * "ps_recv" counts only packets that passed the filter.
+        * As filtering is done in userland, this does not include
+        * packets dropped because we ran out of buffer space.
+        */
        *ps = p->md.stat;
        return (0);
 }
 
 /* XXX can't disable promiscuous */
-pcap_t *
-pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
+static int
+pcap_activate_snoop(pcap_t *p)
 {
        int fd;
        struct sockaddr_raw sr;
        struct snoopfilter sf;
        u_int v;
-       pcap_t *p;
+       int ll_hdrlen;
+       int snooplen;
+       struct ifreq ifr;
 
-       p = (pcap_t *)malloc(sizeof(*p));
-       if (p == NULL) {
-               sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
-               return (NULL);
+       if (p->opt.rfmon) {
+               /*
+                * No monitor mode on Irix (no Wi-Fi devices on
+                * hardware supported by Irix).
+                */
+               return (PCAP_ERROR_RFMON_NOTSUP);
        }
-       bzero((char *)p, sizeof(*p));
+
        fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_SNOOP);
        if (fd < 0) {
-               sprintf(ebuf, "snoop socket: %s", pcap_strerror(errno));
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop socket: %s",
+                   pcap_strerror(errno));
                goto bad;
        }
        p->fd = fd;
-       bzero((char *)&sr, sizeof(sr));
+       memset(&sr, 0, sizeof(sr));
        sr.sr_family = AF_RAW;
-       (void)strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname));
+       (void)strncpy(sr.sr_ifname, p->opt.source, sizeof(sr.sr_ifname));
        if (bind(fd, (struct sockaddr *)&sr, sizeof(sr))) {
-               sprintf(ebuf, "snoop bind: %s", pcap_strerror(errno));
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snoop bind: %s",
+                   pcap_strerror(errno));
                goto bad;
        }
-       bzero((char *)&sf, sizeof(sf));
+       memset(&sf, 0, sizeof(sf));
        if (ioctl(fd, SIOCADDSNOOP, &sf) < 0) {
-               sprintf(ebuf, "SIOCADDSNOOP: %s", pcap_strerror(errno));
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCADDSNOOP: %s",
+                   pcap_strerror(errno));
                goto bad;
        }
        v = 64 * 1024;
        (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&v, sizeof(v));
-       if (ioctl(fd, SIOCSNOOPLEN, &snaplen) < 0) {
-               sprintf(ebuf, "SIOCSNOOPLEN: %s", pcap_strerror(errno));
-               goto bad;
-       }
-       p->snapshot = snaplen;
-       v = 1;
-       if (ioctl(fd, SIOCSNOOPING, &v) < 0) {
-               sprintf(ebuf, "SIOCSNOOPING: %s", pcap_strerror(errno));
-               goto bad;
-       }
        /*
         * XXX hack - map device name to link layer type
         */
-       if (strncmp("et", device, 2) == 0 ||    /* Challenge 10 Mbit */
-           strncmp("ec", device, 2) == 0 ||    /* Indigo/Indy 10 Mbit,
-                                                  O2 10/100 */
-           strncmp("ef", device, 2) == 0 ||    /* O200/2000 10/100 Mbit */
-           strncmp("gfe", device, 3) == 0 ||   /* GIO 100 Mbit */
-           strncmp("fxp", device, 3) == 0 ||   /* Challenge VME Enet */
-           strncmp("ep", device, 2) == 0 ||    /* Challenge 8x10 Mbit EPLEX */
-           strncmp("vfe", device, 3) == 0 ||   /* Challenge VME 100Mbit */
-           strncmp("fa", device, 2) == 0 ||
-           strncmp("qaa", device, 3) == 0) {
+       if (strncmp("et", p->opt.source, 2) == 0 ||     /* Challenge 10 Mbit */
+           strncmp("ec", p->opt.source, 2) == 0 ||     /* Indigo/Indy 10 Mbit,
+                                                          O2 10/100 */
+           strncmp("ef", p->opt.source, 2) == 0 ||     /* O200/2000 10/100 Mbit */
+           strncmp("eg", p->opt.source, 2) == 0 ||     /* Octane/O2xxx/O3xxx Gigabit */
+           strncmp("gfe", p->opt.source, 3) == 0 ||    /* GIO 100 Mbit */
+           strncmp("fxp", p->opt.source, 3) == 0 ||    /* Challenge VME Enet */
+           strncmp("ep", p->opt.source, 2) == 0 ||     /* Challenge 8x10 Mbit EPLEX */
+           strncmp("vfe", p->opt.source, 3) == 0 ||    /* Challenge VME 100Mbit */
+           strncmp("fa", p->opt.source, 2) == 0 ||
+           strncmp("qaa", p->opt.source, 3) == 0 ||
+           strncmp("cip", p->opt.source, 3) == 0 ||
+           strncmp("el", p->opt.source, 2) == 0) {
                p->linktype = DLT_EN10MB;
                p->offset = RAW_HDRPAD(sizeof(struct ether_header));
-       } else if (strncmp("ipg", device, 3) == 0 ||
-                  strncmp("rns", device, 3) == 0 ||    /* O2/200/2000 FDDI */
-                  strncmp("xpi", device, 3) == 0) {
+               ll_hdrlen = sizeof(struct ether_header);
+               /*
+                * 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).
+                *
+                * XXX - are there any sorts of "fake Ethernet" that have
+                * Ethernet link-layer headers but that *shouldn't offer
+                * DLT_DOCSIS as a Cisco CMTS won't put traffic onto it
+                * or get traffic bridged onto it?  "el" is for ATM LANE
+                * Ethernet devices, so that might be the case for them;
+                * the same applies for "qaa" classical IP devices.  If
+                * "fa" devices are for FORE SPANS, that'd apply to them
+                * as well; what are "cip" devices - some other ATM
+                * Classical IP devices?
+                */
+               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;
+               }
+       } else if (strncmp("ipg", p->opt.source, 3) == 0 ||
+                  strncmp("rns", p->opt.source, 3) == 0 ||     /* O2/200/2000 FDDI */
+                  strncmp("xpi", p->opt.source, 3) == 0) {
                p->linktype = DLT_FDDI;
                p->offset = 3;                          /* XXX yeah? */
-       } else if (strncmp("ppp", device, 3) == 0) {
+               ll_hdrlen = 13;
+       } else if (strncmp("ppp", p->opt.source, 3) == 0) {
+               p->linktype = DLT_RAW;
+               ll_hdrlen = 0;  /* DLT_RAW meaning "no PPP header, just the IP packet"? */
+       } else if (strncmp("qfa", p->opt.source, 3) == 0) {
+               p->linktype = DLT_IP_OVER_FC;
+               ll_hdrlen = 24;
+       } else if (strncmp("pl", p->opt.source, 2) == 0) {
                p->linktype = DLT_RAW;
-       } else if (strncmp("lo", device, 2) == 0) {
+               ll_hdrlen = 0;  /* Cray UNICOS/mp pseudo link */
+       } else if (strncmp("lo", p->opt.source, 2) == 0) {
                p->linktype = DLT_NULL;
+               ll_hdrlen = 4;
        } else {
-               sprintf(ebuf, "snoop: unknown physical layer type");
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+                   "snoop: unknown physical layer type");
+               goto bad;
+       }
+#ifdef SIOCGIFMTU
+       /*
+        * XXX - IRIX appears to give you an error if you try to set the
+        * capture length to be greater than the MTU, so let's try to get
+        * the MTU first and, if that succeeds, trim the snap length
+        * to be no greater than the MTU.
+        */
+       (void)strncpy(ifr.ifr_name, p->opt.source, sizeof(ifr.ifr_name));
+       if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCGIFMTU: %s",
+                   pcap_strerror(errno));
+               goto bad;
+       }
+       /*
+        * OK, we got it.
+        *
+        * XXX - some versions of IRIX 6.5 define "ifr_mtu" and have an
+        * "ifru_metric" member of the "ifr_ifru" union in an "ifreq"
+        * structure, others don't.
+        *
+        * I've no idea what's going on, so, if "ifr_mtu" isn't defined,
+        * we define it as "ifr_metric", as using that field appears to
+        * work on the versions that lack "ifr_mtu" (and, on those that
+        * don't lack it, "ifru_metric" and "ifru_mtu" are both "int"
+        * members of the "ifr_ifru" union, which suggests that they
+        * may be interchangeable in this case).
+        */
+#ifndef ifr_mtu
+#define ifr_mtu        ifr_metric
+#endif
+       if (p->snapshot > ifr.ifr_mtu + ll_hdrlen)
+               p->snapshot = ifr.ifr_mtu + ll_hdrlen;
+#endif
+
+       /*
+        * The argument to SIOCSNOOPLEN is the number of link-layer
+        * payload bytes to capture - it doesn't count link-layer
+        * header bytes.
+        */
+       snooplen = p->snapshot - ll_hdrlen;
+       if (snooplen < 0)
+               snooplen = 0;
+       if (ioctl(fd, SIOCSNOOPLEN, &snooplen) < 0) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPLEN: %s",
+                   pcap_strerror(errno));
+               goto bad;
+       }
+       v = 1;
+       if (ioctl(fd, SIOCSNOOPING, &v) < 0) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNOOPING: %s",
+                   pcap_strerror(errno));
                goto bad;
        }
 
        p->bufsize = 4096;                              /* XXX */
        p->buffer = (u_char *)malloc(p->bufsize);
        if (p->buffer == NULL) {
-               sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+                   pcap_strerror(errno));
                goto bad;
        }
 
-       return (p);
+       /*
+        * "p->fd" is a socket, so "select()" should work on it.
+        */
+       p->selectable_fd = p->fd;
+
+       p->read_op = pcap_read_snoop;
+       p->inject_op = pcap_inject_snoop;
+       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_snoop;
+       p->close_op = pcap_close_common;
+
+       return (0);
  bad:
        (void)close(fd);
-       free(p);
-       return (NULL);
+       return (PCAP_ERROR);
 }
 
-int
-pcap_setfilter(pcap_t *p, struct bpf_program *fp)
+pcap_t *
+pcap_create(const char *device, char *ebuf)
 {
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_snoop;
+       return (p);
+}
 
-       p->fcode = *fp;
+int
+pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
+{
        return (0);
 }
index e147d3ebc113424f42f925ef2e0969a4f0e27d12..e796b506da9c9c19d6364ee13e7a93fcd00c0ec1 100644 (file)
@@ -34,7 +34,7 @@
  */
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-usb-linux.c,v 1.16.2.5 2008-02-02 20:51:00 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-usb-linux.c,v 1.16.2.6 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
  
 #ifdef HAVE_CONFIG_H
@@ -117,6 +117,7 @@ struct mon_bin_mfetch {
 #define MON_BIN_ERROR  0x8
 
 /* forward declaration */
+static int usb_activate(pcap_t *);
 static int usb_stats_linux(pcap_t *, struct pcap_stat *);
 static int usb_stats_linux_bin(pcap_t *, struct pcap_stat *);
 static int usb_read_linux(pcap_t *, int , pcap_handler , u_char *);
@@ -183,25 +184,26 @@ int usb_mmap(pcap_t* handle)
        return handle->buffer != MAP_FAILED;
 }
 
-pcap_t*
-usb_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errmsg)
+pcap_t *
+usb_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = usb_activate;
+       return (p);
+}
+
+static int
+usb_activate(pcap_t* handle)
 {
        char            full_path[USB_LINE_LEN];
-       pcap_t          *handle;
-
-       /* Allocate a handle for this session. */
-       handle = malloc(sizeof(*handle));
-       if (handle == NULL) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE, "malloc: %s",
-                       pcap_strerror(errno));
-               return NULL;
-       }
 
        /* Initialize some components of the pcap structure. */
-       memset(handle, 0, sizeof(*handle));
-       handle->snapshot        = snaplen;
-       handle->md.timeout      = to_ms;
-       handle->bufsize = snaplen;
+       handle->bufsize = handle->snapshot;
        handle->offset = 0;
        handle->linktype = DLT_USB_LINUX;
 
@@ -214,12 +216,11 @@ usb_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errms
        handle->close_op = usb_close_linux;
 
        /*get usb bus index from device name */
-       if (sscanf(bus, USB_IFACE"%d", &handle->md.ifindex) != 1)
+       if (sscanf(handle->opt.source, USB_IFACE"%d", &handle->md.ifindex) != 1)
        {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE,
-                       "Can't get USB bus index from %s", bus);
-               free(handle);
-               return NULL;
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                       "Can't get USB bus index from %s", handle->opt.source);
+               return -1;
        }
 
        /*now select the read method: try to open binary interface */
@@ -238,7 +239,7 @@ usb_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errms
                         * "poll()" work on it.
                         */
                        handle->selectable_fd = handle->fd;
-                       return handle;
+                       return 0;
                }
 
                /* can't mmap, use plain binary interface access */
@@ -252,10 +253,9 @@ usb_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errms
                if (handle->fd < 0)
                {
                        /* no more fallback, give it up*/
-                       snprintf(errmsg, PCAP_ERRBUF_SIZE,
+                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                                "Can't open USB bus file %s: %s", full_path, strerror(errno));
-                       free(handle);
-                       return NULL;
+                       return -1;
                }
                handle->stats_op = usb_stats_linux;
                handle->read_op = usb_read_linux;
@@ -271,12 +271,12 @@ usb_open_live(const char* bus, int snaplen, int promisc , int to_ms, char* errms
         * buffer */
        handle->buffer = malloc(handle->bufsize);
        if (!handle->buffer) {
-               snprintf(errmsg, PCAP_ERRBUF_SIZE,
+               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                         "malloc: %s", pcap_strerror(errno));
-               usb_close_linux(handle);
-               return NULL;
+               close(handle->fd);
+               return -1;
        }
-       return handle;
+       return 0;
 }
 
 static inline int 
diff --git a/pcap-usb-linux.h b/pcap-usb-linux.h
new file mode 100644 (file)
index 0000000..a157907
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006 Paolo Abeni (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote 
+ * products derived from this software without specific prior written 
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * USB sniffing API implementation for Linux platform
+ * By Paolo Abeni <[email protected]>
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-usb-linux.h,v 1.4.2.1 2008-04-04 19:39:06 guy Exp $ (LBL)
+ */
+
+/*
+ * Prototypes for USB-related functions
+ */
+int usb_platform_finddevs(pcap_if_t **alldevsp, char *err_str);
+pcap_t *usb_create(const char *device, char *ebuf);
index e9cb1d46403a78608ad348a6aad5c069291c8883..695dacd7315031022a648d9f13ef58390cedd839 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.34.2.2 2007-11-13 21:56:04 gianluca Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.34.2.3 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 #include <pcap-int.h>
@@ -430,39 +430,36 @@ pcap_close_win32(pcap_t *p)
        }
 }
 
-pcap_t *
-pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
-    char *ebuf)
+static int
+pcap_activate_win32(pcap_t *p)
 {
-       register pcap_t *p;
        NetType type;
 
+       if (p->opt.rfmon) {
+               /*
+                * No monitor mode on Windows.  It could be done on
+                * Vista with drivers that support the native 802.11
+                * mechanism and monitor mode.
+                */
+               return (PCAP_ERROR_RFMON_NOTSUP);
+       }
+
        /* Init WinSock */
        wsockinit();
 
-       p = (pcap_t *)malloc(sizeof(*p));
-       if (p == NULL) 
-       {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
-               return (NULL);
-       }
-       memset(p, 0, sizeof(*p));
-       p->adapter=NULL;
-
-       p->adapter = PacketOpenAdapter((char*)device);
+       p->adapter = PacketOpenAdapter(p->opt.source);
        
        if (p->adapter == NULL)
        {
-               free(p);
                /* Adapter detected but we are not able to open it. Return failure. */
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror());
-               return NULL;
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror());
+               return PCAP_ERROR;
        }
        
        /*get network type*/
        if(PacketGetNetType (p->adapter,&type) == FALSE)
        {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror());
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror());
                goto bad;
        }
        
@@ -546,12 +543,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        }
 
        /* Set promiscuous mode */
-       if (promisc) 
+       if (p->opt.promisc) 
        {
 
                if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)
                {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode");
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode");
                        goto bad;
                }
        }
@@ -559,7 +556,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        {
                if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE)
                {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode");
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode");
                        goto bad;
                }
        }
@@ -568,12 +565,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->bufsize = PcapBufSize;
 
        /* Store the timeout. Used by pcap_setnonblock() */
-       p->timeout= to_ms;
+       p->md.timeout= to_ms;
 
        /* allocate Packet structure used during the capture */
        if((p->Packet = PacketAllocatePacket())==NULL)
        {
-               snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure");
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure");
                goto bad;
        }
 
@@ -582,11 +579,22 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        /* 
         * Traditional Adapter 
         */
+               /*
+                * If the buffer size wasn't explicitly set, default to
+                * SIZE_BUF.
+                */
+               if (p->opt.buffer_size == 0)
+                       p->opt.buffer_size = SIZE_BUF;
+               if(PacketSetBuff(p->adapter,p->opt.buffer_size)==FALSE)
+               {
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
+                       goto bad;
+               }
                
                p->buffer = (u_char *)malloc(PcapBufSize);
                if (p->buffer == NULL) 
                {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
                        goto bad;
                }
                
@@ -597,14 +605,14 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                /* allocate the standard buffer in the driver */
                if(PacketSetBuff( p->adapter, SIZE_BUF)==FALSE)
                {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE,"driver error: not enough memory to allocate the kernel buffer\n");
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"driver error: not enough memory to allocate the kernel buffer\n");
                        goto bad;
                }
                
                /* tell the driver to copy the buffer only if it contains at least 16K */
                if(PacketSetMinToCopy(p->adapter,16000)==FALSE)
                {
-                       snprintf(ebuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s\n", pcap_win32strerror());
+                       snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s\n", pcap_win32strerror());
                        goto bad;
                }
        }
@@ -623,7 +631,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
                
                snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s", 
                        "SYSTEM\\CurrentControlSet\\Services\\DAG",
-                       strstr(_strlwr((char*)device), "dag"));
+                       strstr(_strlwr(p->opt.source), "dag"));
                do
                {
                        status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey);
@@ -687,23 +695,31 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
        p->setmintocopy_op = pcap_setmintocopy_win32;
        p->close_op = pcap_close_win32;
 
-       return (p);
+       return (0);
 bad:
        if (p->adapter)
            PacketCloseAdapter(p->adapter);
-       if (p->buffer != NULL)
+       if (p->buffer != NULL) {
                free(p->buffer);
+               p->buffer = NULL;
+       }
        if(p->Packet)
                PacketFreePacket(p->Packet);
-       /*
-        * Get rid of any link-layer type list we allocated.
-        */
-       if (p->dlt_list != NULL)
-               free(p->dlt_list);
-       free(p);
-       return (NULL);
+       return (PCAP_ERROR);
 }
 
+pcap_t *
+pcap_create(const char *device, char *ebuf)
+{
+       pcap_t *p;
+
+       p = pcap_create_common(device, ebuf);
+       if (p == NULL)
+               return (NULL);
+
+       p->activate_op = pcap_activate_win32;
+       return (p);
+}
 
 static int
 pcap_setfilter_win32_npf(pcap_t *p, struct bpf_program *fp)
@@ -780,7 +796,7 @@ pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf)
                 * (Note that this may be -1, in which case we're not
                 * really leaving non-blocking mode.)
                 */
-               newtimeout = p->timeout;
+               newtimeout = p->md.timeout;
        }
        if (!PacketSetReadTimeout(p->adapter, newtimeout)) {
                snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
diff --git a/pcap.c b/pcap.c
index c48a4410bf140fd340d80b37c7ef18375671f680..02f400800f067831cffe88e7ae5f8e413c769fbd 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -33,7 +33,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.112.2.2 2007-11-06 16:21:20 gianluca Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.112.2.3 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -70,10 +70,192 @@ static const char rcsid[] _U_ =
 #include <dagapi.h>
 #endif
 
+int 
+pcap_not_initialized(pcap_t *pcap)
+{
+       /* this means 'not initialized' */
+       return PCAP_ERROR_NOT_ACTIVATED;
+}
+
+/*
+ * Returns 1 if rfmon mode can be set on the pcap_t, 0 if it can't,
+ * a PCAP_ERROR value on an error.
+ */
 int
-pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+pcap_can_set_rfmon(pcap_t *p)
+{
+       return (p->can_set_rfmon_op(p));
+}
+
+/*
+ * For systems where rfmon mode is never supported.
+ */
+static int
+pcap_cant_set_rfmon(pcap_t *p _U_)
+{
+       return (0);
+}
+
+pcap_t *
+pcap_create_common(const char *source, char *ebuf)
+{
+       pcap_t *p;
+
+       p = malloc(sizeof(*p));
+       if (p == NULL) {
+               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+                   pcap_strerror(errno));
+               return (NULL);
+       }
+       memset(p, 0, sizeof(*p));
+
+       p->opt.source = strdup(source);
+       if (p->opt.source == NULL) {
+               snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
+                   pcap_strerror(errno));
+               free(p);
+               return (NULL);
+       }
+
+       /*
+        * Default to "can't set rfmon mode"; if it's supported by
+        * a platform, it can set the op to its routine to check
+        * whether a particular device supports it.
+        */
+       p->can_set_rfmon_op = pcap_cant_set_rfmon;
+
+       /*
+        * Some operations can be performed only on activated pcap_t's;
+        * have those operations handled by a "not supported" handler
+        * until the pcap_t is activated.
+        */
+       p->read_op = (read_op_t)pcap_not_initialized;
+       p->inject_op = (inject_op_t)pcap_not_initialized;
+       p->setfilter_op = (setfilter_op_t)pcap_not_initialized;
+       p->setdirection_op = (setdirection_op_t)pcap_not_initialized;
+       p->set_datalink_op = (set_datalink_op_t)pcap_not_initialized;
+       p->getnonblock_op = (getnonblock_op_t)pcap_not_initialized;
+       p->setnonblock_op = (setnonblock_op_t)pcap_not_initialized;
+       p->stats_op = (stats_op_t)pcap_not_initialized;
+#ifdef WIN32
+       p->setbuff_op = (setbuff_op_t)pcap_not_initialized;
+       p->setmode_op = (setmode_op_t)pcap_not_initialized;
+       p->setmintocopy_op = (setmintocopy_op_t)pcap_not_initialized;
+#endif
+       p->close_op = (close_op_t)pcap_close_common;
+
+       /* put in some defaults*/
+       pcap_set_timeout(p, 0);
+       pcap_set_snaplen(p, 65535);     /* max packet size */
+       p->opt.promisc = 0;
+       p->opt.buffer_size = 0;
+       return (p);
+}
+
+int
+pcap_check_activated(pcap_t *p)
+{
+       if (p->activated) {
+               snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "
+                       " operation on activated capture");
+               return -1;
+       }
+       return 0;
+}
+
+int
+pcap_set_snaplen(pcap_t *p, int snaplen)
+{
+       if (pcap_check_activated(p))
+               return PCAP_ERROR_ACTIVATED;
+       p->snapshot = snaplen;
+       return 0;
+}
+
+int
+pcap_set_promisc(pcap_t *p, int promisc)
+{
+       if (pcap_check_activated(p))
+               return PCAP_ERROR_ACTIVATED;
+       p->opt.promisc = promisc;
+       return 0;
+}
+
+int
+pcap_set_rfmon(pcap_t *p, int rfmon)
 {
+       if (pcap_check_activated(p))
+               return PCAP_ERROR_ACTIVATED;
+       p->opt.rfmon = rfmon;
+       return 0;
+}
 
+int
+pcap_set_timeout(pcap_t *p, int timeout_ms)
+{
+       if (pcap_check_activated(p))
+               return PCAP_ERROR_ACTIVATED;
+       p->md.timeout = timeout_ms;
+       return 0;
+}
+
+int
+pcap_set_buffer_size(pcap_t *p, int buffer_size)
+{
+       if (pcap_check_activated(p))
+               return PCAP_ERROR_ACTIVATED;
+       p->opt.buffer_size = buffer_size;
+       return 0;
+}
+
+int
+pcap_activate(pcap_t *p)
+{
+       int err;
+
+       err = p->activate_op(p);
+       if (err == 0)
+               p->activated = 1;
+       return (err);
+}
+
+pcap_t *
+pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *errbuf)
+{
+       pcap_t *p;
+
+       p = pcap_create(source, errbuf);
+       if (p == NULL)
+               return (NULL);
+       if (pcap_set_snaplen(p, snaplen))
+               goto fail;
+       if (pcap_set_promisc(p, promisc))
+               goto fail;
+       if (pcap_set_timeout(p, to_ms))
+               goto fail;
+       /*
+        * Mark this as opened with pcap_open_live(), so that, for
+        * example, we show the full list of DLT_ values, rather
+        * than just the ones that are compatible with capturing
+        * when not in monitor mode.  That allows existing applications
+        * to work the way they used to work, but allows new applications
+        * that know about the new open API to, for example, find out the
+        * DLT_ values that they can select without changing whether
+        * the adapter is in monitor mode or not.
+        */
+       p->oldstyle = 1;
+       if (pcap_activate(p))
+               goto fail;
+       return (p);
+fail:
+       strncpy(errbuf, p->errbuf, PCAP_ERRBUF_SIZE);
+       pcap_close(p);
+       return (NULL);
+}
+
+int
+pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
+{
        return p->read_op(p, cnt, callback, user);
 }
 
@@ -702,22 +884,57 @@ pcap_win32strerror(void)
 
 /*
  * Not all systems have strerror().
+ * We also use this to generate error strings for PCAP_ERROR_ values.
  */
 const char *
 pcap_strerror(int errnum)
 {
-#ifdef HAVE_STRERROR
-       return (strerror(errnum));
-#else
+       static char ebuf[128+1];
+#ifndef HAVE_STRERROR
        extern int sys_nerr;
        extern const char *const sys_errlist[];
-       static char ebuf[20];
+#endif
+
+       switch (errnum) {
+
+       case PCAP_ERROR:
+               (void)snprintf(ebuf, sizeof ebuf, "Generic error");
+               return(ebuf);
 
-       if ((unsigned int)errnum < sys_nerr)
-               return ((char *)sys_errlist[errnum]);
+       case PCAP_ERROR_BREAK:
+               (void)snprintf(ebuf, sizeof ebuf, "Loop terminated by pcap_breakloop");
+               return(ebuf);
+
+       case PCAP_ERROR_NOT_ACTIVATED:
+               (void)snprintf(ebuf, sizeof ebuf, "The pcap_t has not been activated");
+               return(ebuf);
+
+       case PCAP_ERROR_ACTIVATED:
+               (void)snprintf(ebuf, sizeof ebuf, "The setting can't be changed after the pcap_t is activated");
+               return(ebuf);
+
+       case PCAP_ERROR_NO_SUCH_DEVICE:
+               (void)snprintf(ebuf, sizeof ebuf, "No such device exists");
+               return(ebuf);
+
+       case PCAP_ERROR_RFMON_NOTSUP:
+               (void)snprintf(ebuf, sizeof ebuf, "That device doesn't support monitor mode");
+               return(ebuf);
+
+       case PCAP_ERROR_NOT_RFMON:
+               (void)snprintf(ebuf, sizeof ebuf, "That operation is supported only in monitor mode");
+               return(ebuf);
+       }
+       if (errnum >= 0) {
+#ifdef HAVE_STRERROR
+               return (strerror(errnum));
+#else
+               if ((unsigned int)errnum < sys_nerr)
+                       return ((char *)sys_errlist[errnum]);
+#endif
+       }
        (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
        return(ebuf);
-#endif
 }
 
 int
@@ -801,11 +1018,102 @@ pcap_setmintocopy_dead(pcap_t *p, int size)
 }
 #endif
 
+/*
+ * On some platforms, we need to clean up promiscuous or monitor mode
+ * when we close a device - and we want that to happen even if the
+ * application just exits without explicitl closing devices.
+ * On those platforms, we need to register a "close all the pcaps"
+ * routine to be called when we exit, and need to maintain a list of
+ * pcaps that need to be closed to clean up modes.
+ *
+ * XXX - not thread-safe.
+ */
+
+/*
+ * List of pcaps on which we've done something that needs to be
+ * cleaned up.
+ * If there are any such pcaps, we arrange to call "pcap_close_all()"
+ * when we exit, and have it close all of them.
+ */
+static struct pcap *pcaps_to_close;
+
+/*
+ * TRUE if we've already called "atexit()" to cause "pcap_close_all()" to
+ * be called on exit.
+ */
+static int did_atexit;
+
+static void
+pcap_close_all(void)
+{
+       struct pcap *handle;
+
+       while ((handle = pcaps_to_close) != NULL)
+               pcap_close(handle);
+}
+
+int
+pcap_do_addexit(pcap_t *p)
+{
+       /*
+        * If we haven't already done so, arrange to have
+        * "pcap_close_all()" called when we exit.
+        */
+       if (!did_atexit) {
+               if (atexit(pcap_close_all) == -1) {
+                       /*
+                        * "atexit()" failed; let our caller know.
+                        */
+                       strncpy(p->errbuf, "atexit failed",
+                           PCAP_ERRBUF_SIZE);
+                       return (0);
+               }
+               did_atexit = 1;
+       }
+       return (1);
+}
+
+void
+pcap_add_to_pcaps_to_close(pcap_t *p)
+{
+       p->md.next = pcaps_to_close;
+       pcaps_to_close = p;
+}
+
+void
+pcap_remove_from_pcaps_to_close(pcap_t *p)
+{
+       pcap_t *pc, *prevpc;
+
+       for (pc = pcaps_to_close, prevpc = NULL; pc != NULL;
+           prevpc = pc, pc = pc->md.next) {
+               if (pc == p) {
+                       /*
+                        * Found it.  Remove it from the list.
+                        */
+                       if (prevpc == NULL) {
+                               /*
+                                * It was at the head of the list.
+                                */
+                               pcaps_to_close = pc->md.next;
+                       } else {
+                               /*
+                                * It was in the middle of the list.
+                                */
+                               prevpc->md.next = pc->md.next;
+                       }
+                       break;
+               }
+       }
+}
+
 void
 pcap_close_common(pcap_t *p)
 {
        if (p->buffer != NULL)
                free(p->buffer);
+       if (p->opt.source != NULL);
+               free(p->opt.source);
 #if !defined(WIN32) && !defined(MSDOS)
        if (p->fd >= 0)
                close(p->fd);
@@ -836,6 +1144,7 @@ pcap_open_dead(int linktype, int snaplen)
        p->setmintocopy_op = pcap_setmintocopy_dead;
 #endif
        p->close_op = pcap_close_dead;
+       p->activated = 1;
        return p;
 }
 
index 7f62ec328cdeb93f721eef0945362bdc1011f7a8..8d2f04971b4c7a44c4038f55b3e09a9c31e155b3 100644 (file)
@@ -31,7 +31,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.1 2008-01-02 04:22:16 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.2 2008-04-04 19:39:06 guy Exp $ (LBL)
  */
 
 #ifndef lib_pcap_pcap_h
@@ -226,8 +226,27 @@ struct pcap_addr {
 typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
                             const u_char *);
 
+/* list of known error code for pcap API */
+#define PCAP_ERROR                     -1      /* generic error code */
+#define PCAP_ERROR_BREAK               -2      /* loop terminated by pcap_breakloop */
+#define PCAP_ERROR_NOT_ACTIVATED       -3      /* the capture needs to be activated */
+#define PCAP_ERROR_ACTIVATED           -4      /* the operation can't be performed on already activated captures */
+#define PCAP_ERROR_NO_SUCH_DEVICE      -5      /* no such device exists */
+#define PCAP_ERROR_RFMON_NOTSUP                -6      /* this device doesn't support rfmon (monitor) mode */
+#define PCAP_ERROR_NOT_RFMON           -7      /* operation supported only in monitor mode */
+
 char   *pcap_lookupdev(char *);
 int    pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
+
+pcap_t *pcap_create(const char *, char *);
+int    pcap_set_snaplen(pcap_t *, int);
+int    pcap_set_promisc(pcap_t *, int);
+int    pcap_can_set_rfmon(pcap_t *);
+int    pcap_set_rfmon(pcap_t *, int);
+int    pcap_set_timeout(pcap_t *, int);
+int    pcap_set_buffer_size(pcap_t *, int);
+int    pcap_activate(pcap_t *);
+
 pcap_t *pcap_open_live(const char *, int, int, int, char *);
 pcap_t *pcap_open_dead(int, int);
 pcap_t *pcap_open_offline(const char *, char *);
index 04bab17a38a8a42aa3315f32d930d42f874d4733..1923a0cd484f2ddd45f07be88fd901502d32dead 100644 (file)
@@ -30,7 +30,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.168.2.4 2008-02-18 20:21:28 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.168.2.5 2008-04-04 19:39:06 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -1310,6 +1310,7 @@ pcap_fopen_offline(FILE *fp, char *errbuf)
        p->setmintocopy_op = sf_setmintocopy;
 #endif
        p->close_op = sf_close;
+       p->activated = 1;
 
        return (p);
  bad: