/* 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
/* 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
#! /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.
#
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
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"
;;
-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.
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)
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"
;;
*/
#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
* 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;
#endif
default:
- snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown mactype %u",
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype %u",
mactype);
retv = -1;
}
* 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;
/* 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;
}
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;
}
}
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;
}
* 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);
}
/*
- * @(#) $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
*/
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
*/
#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
#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
#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)
{
}
#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.
/*
* 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
break;
}
#endif
-#ifdef PCAP_FDDIPAD
- if (v == DLT_FDDI)
- p->fddipad = PCAP_FDDIPAD;
- else
- p->fddipad = 0;
-#endif
- p->linktype = v;
#ifdef BIOCGDLTLIST
/*
* 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,
* 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.
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)
/*
* 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;
}
}
*/
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
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;
}
* 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.
*/
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
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)
{
*/
#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
#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 *);
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;
/* 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;
}
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
--- /dev/null
+/*
+ * 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
+ *
+ * @(#) $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);
#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
/* 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 */
* 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;
#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/");
/* 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;
}
*/
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;
}
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;
}
/* 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 */
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;
}
}
}
}
- 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;
}
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
*
* 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
#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
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;
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;
/*
** 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));
* 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';
*/
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;
}
* 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
* 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;
/* 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;
}
* 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;
}
#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
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
** 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) {
/*
** 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 */
** 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 */
** 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;
/*
** 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
}
/*
#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;
}
** 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
** 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
** 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
** 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
#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
** 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;
/*
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);
}
/*
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);
+}
* 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>
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);
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);
}
/*
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)
{
/* 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);
{
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);
}
if (p)
{
p->wait_proc = yield;
- p->inter_packet_wait = wait;
+ p->md.timeout = wait;
}
}
/*
- * 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)
{
* 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
MAYBE_SWAPPED
} swapped_type_t;
+/*
+ * Used when reading a savefile.
+ */
struct pcap_sf {
FILE *rfile;
int swapped;
u_char *base;
};
+/*
+ * Used when doing a live capture.
+ */
struct pcap_md {
struct pcap_stat stat;
/*XXX*/
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
#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
#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;
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 */
#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.
/*
* 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.
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()".
#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
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;
}
}
/* 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;
/*
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);
}
/*
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);
+}
#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
/*
#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"
#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.
#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);
#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 *);
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);
= { 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;
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");
}
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;
}
/*
* 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;
}
/*
*/
handle->selectable_fd = handle->fd;
- return handle;
+ return 0;
}
/*
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;
}
/* 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;
}
return -1;
if (!filter) {
strncpy(handle->errbuf, "setfilter: No filter specified",
- sizeof(handle->errbuf));
+ PCAP_ERRBUF_SIZE);
return -1;
}
* 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;
}
* 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?
*/
/* ===== 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 "
}
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;
}
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;
* 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;
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;
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*/
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;
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;
}
/*
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;
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;
}
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;
}
*/
#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
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.
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;
}
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
* 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
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);
}
#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
#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
* "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;
}
#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;
}
* 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 */
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;
}
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;
}
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
--- /dev/null
+/*
+ * 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.
+ *
+ * (+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);
+}
--- /dev/null
+/*
+ * 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.
+ *
+ * (+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);
+
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;
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;
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;
}
/*
*/
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);
}
#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
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
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;
}
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 *)𝔦
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);
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;
}
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
* 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>
#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);
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);
}
*/
#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
#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 *);
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;
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 */
* "poll()" work on it.
*/
handle->selectable_fd = handle->fd;
- return handle;
+ return 0;
}
/* can't mmap, use plain binary interface access */
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;
* 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
--- /dev/null
+/*
+ * 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
+ *
+ * @(#) $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);
#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>
}
}
-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;
}
}
/* 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;
}
}
{
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;
}
}
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;
}
/*
* 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;
}
/* 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;
}
}
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);
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)
* (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,
#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
#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);
}
/*
* 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
}
#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);
p->setmintocopy_op = pcap_setmintocopy_dead;
#endif
p->close_op = pcap_close_dead;
+ p->activated = 1;
return p;
}
* 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
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 *);
#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
p->setmintocopy_op = sf_setmintocopy;
#endif
p->close_op = sf_close;
+ p->activated = 1;
return (p);
bad: