dect
/
libpcap
Archived
13
0
Fork 0

Merge branch 'master' of git+ssh://guy@bpf.tcpdump.org/tcpdump/master/git/libpcap

This commit is contained in:
Guy Harris 2009-06-01 10:20:09 -07:00
commit 33aa345694
6 changed files with 648 additions and 25 deletions

View File

@ -56,6 +56,9 @@
/* if libdlpi exists */
#undef HAVE_LIBDLPI
/* if libnl exists */
#undef HAVE_LIBNL
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H

76
configure vendored
View File

@ -6716,6 +6716,82 @@ fi
done
if test "$ac_cv_header_linux_wireless_h" = yes; then
#
# We have the wireless extensions; check whether
# we have libnl.
#
{ echo "$as_me:$LINENO: checking for nl_handle_alloc in -lnl" >&5
echo $ECHO_N "checking for nl_handle_alloc in -lnl... $ECHO_C" >&6; }
if test "${ac_cv_lib_nl_nl_handle_alloc+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lnl $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char nl_handle_alloc ();
int
main ()
{
return nl_handle_alloc ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext &&
$as_test_x conftest$ac_exeext; then
ac_cv_lib_nl_nl_handle_alloc=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_lib_nl_nl_handle_alloc=no
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ echo "$as_me:$LINENO: result: $ac_cv_lib_nl_nl_handle_alloc" >&5
echo "${ECHO_T}$ac_cv_lib_nl_nl_handle_alloc" >&6; }
if test $ac_cv_lib_nl_nl_handle_alloc = yes; then
V_LIBS="-lnl $V_LIBS"
cat >>confdefs.h <<\_ACEOF
#define HAVE_LIBNL 1
_ACEOF
fi
fi
{ 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

View File

@ -375,6 +375,15 @@ linux)
#include <linux/if.h>
#include <linux/types.h>
])
if test "$ac_cv_header_linux_wireless_h" = yes; then
#
# We have the wireless extensions; check whether
# we have libnl.
#
AC_CHECK_LIB(nl, nl_handle_alloc,
V_LIBS="-lnl $V_LIBS"
AC_DEFINE(HAVE_LIBNL,1,[if libnl exists]),)
fi
AC_LBL_TPACKET_STATS
AC_LBL_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI
;;

View File

@ -1148,13 +1148,13 @@ pcap_cleanup_bpf(pcap_t *p)
struct ifreq ifr;
#endif
if (p->md.must_clear != 0) {
if (p->md.must_do_on_close != 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) {
if (p->md.must_do_on_close & MUST_CLEAR_RFMON) {
/*
* We put the interface into rfmon mode;
* take it out of rfmon mode.
@ -1209,7 +1209,7 @@ pcap_cleanup_bpf(pcap_t *p)
* have to take the interface out of some mode.
*/
pcap_remove_from_pcaps_to_close(p);
p->md.must_clear = 0;
p->md.must_do_on_close = 0;
}
#ifdef HAVE_ZEROCOPY_BPF
@ -2207,7 +2207,7 @@ monitor_mode(pcap_t *p, int set)
return (PCAP_ERROR);
}
p->md.must_clear |= MUST_CLEAR_RFMON;
p->md.must_do_on_close |= MUST_CLEAR_RFMON;
/*
* Add this to the list of pcaps to close when we exit.

View File

@ -131,7 +131,7 @@ struct pcap_md {
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 */
int must_do_on_close; /* stuff we must do 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 */
@ -140,6 +140,7 @@ struct pcap_md {
int lo_ifindex; /* interface index of the loopback device */
u_int packets_read; /* count of packets read with recvfrom() */
bpf_u_int32 oldmode; /* mode to restore when turning monitor mode off */
char *mondevice; /* mac80211 monitor device we created */
u_int tp_version; /* version of tpacket_hdr for mmaped ring */
u_int tp_hdrlen; /* hdrlen of tpacket_hdr for mmaped ring */
union thdr prev_pkt; /* previous packet handed to the callback */
@ -186,10 +187,11 @@ struct pcap_md {
};
/*
* Stuff to clear when we close.
* Stuff to do when we close.
*/
#define MUST_CLEAR_PROMISC 0x00000001 /* promiscuous mode */
#define MUST_CLEAR_RFMON 0x00000002 /* rfmon (monitor) mode */
#define MUST_CLEAR_PROMISC 0x00000001 /* clear promiscuous mode */
#define MUST_CLEAR_RFMON 0x00000002 /* clear rfmon (monitor) mode */
#define MUST_DELETE_MONIF 0x00000004 /* delete monitor-mode interface */
struct pcap_opt {
int buffer_size;

View File

@ -30,6 +30,39 @@
* based on previous works of:
* Simon Patarin <patarin@cs.unibo.it>
* Phil Wood <cpw@lanl.gov>
*
* Monitor-mode support for mac80211 includes code taken from the iw
* command; the copyright notice for that code is
*
* Copyright (c) 2007, 2008 Johannes Berg
* Copyright (c) 2007 Andy Lutomirski
* Copyright (c) 2007 Mike Kershaw
* Copyright (c) 2008 Gábor Stefanik
*
* 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 AUTHOR ``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 AUTHOR 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.
*/
#ifndef lint
@ -80,15 +113,19 @@ static const char rcsid[] _U_ =
*/
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <limits.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
@ -104,7 +141,21 @@ static const char rcsid[] _U_ =
*/
#ifdef HAVE_LINUX_WIRELESS_H
#include <linux/wireless.h>
#endif
/*
* Got libnl?
*/
#ifdef HAVE_LIBNL
#include <linux/nl80211.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#endif /* HAVE_LIBNL */
#endif /* HAVE_LINUX_WIRELESS_H */
#include "pcap-int.h"
#include "pcap/sll.h"
@ -271,7 +322,7 @@ static int iface_bind(int fd, int ifindex, char *ebuf);
#ifdef IW_MODE_MONITOR
static int has_wext(int sock_fd, const char *device, char *ebuf);
#endif /* IW_MODE_MONITOR */
static int enter_rfmon_mode_wext(pcap_t *handle, int sock_fd,
static int enter_rfmon_mode(pcap_t *handle, int sock_fd,
const char *device);
#endif /* HAVE_PF_PACKET_SOCKETS */
static int iface_bind_old(int fd, const char *device, char *ebuf);
@ -357,6 +408,10 @@ pcap_can_set_rfmon_linux(pcap_t *p)
* 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.)
*
* This also presumes that the mac80211 framework supports the
* Wireless Extensions, which appears to be the case at least
* as far back as the 2.6.22.6 kernel.
*/
sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock_fd == -1) {
@ -388,6 +443,225 @@ pcap_can_set_rfmon_linux(pcap_t *p)
return 0;
}
#if defined(IW_MODE_MONITOR) && defined(HAVE_LIBNL)
struct nl80211_state {
struct nl_handle *nl_handle;
struct nl_cache *nl_cache;
struct genl_family *nl80211;
};
static int
nl80211_init(pcap_t *handle, struct nl80211_state *state, const char *device)
{
state->nl_handle = nl_handle_alloc();
if (!state->nl_handle) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to allocate netlink handle", device);
return PCAP_ERROR;
}
if (genl_connect(state->nl_handle)) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to connect to generic netlink", device);
goto out_handle_destroy;
}
state->nl_cache = genl_ctrl_alloc_cache(state->nl_handle);
if (!state->nl_cache) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to allocate generic netlink cache", device);
goto out_handle_destroy;
}
state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
if (!state->nl80211) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl80211 not found", device);
goto out_cache_free;
}
return 0;
out_cache_free:
nl_cache_free(state->nl_cache);
out_handle_destroy:
nl_handle_destroy(state->nl_handle);
return PCAP_ERROR;
}
static void
nl80211_cleanup(struct nl80211_state *state)
{
genl_family_put(state->nl80211);
nl_cache_free(state->nl_cache);
nl_handle_destroy(state->nl_handle);
}
static int
add_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
const char *device, const char *mondevice)
{
int ifindex;
struct nl_msg *msg;
int err;
ifindex = iface_get_id(sock_fd, device, handle->errbuf);
if (ifindex == -1)
return PCAP_ERROR;
msg = nlmsg_alloc();
if (!msg) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to allocate netlink msg", device);
return PCAP_ERROR;
}
genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
0, NL80211_CMD_NEW_INTERFACE, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice);
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
err = nl_send_auto_complete(state->nl_handle, msg);
if (err < 0) {
if (err == -ENFILE) {
/*
* Device not available; our caller should just
* keep trying.
*/
nlmsg_free(msg);
return 0;
} else {
/*
* Real failure, not just "that device is not
* available.
*/
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_send_auto_complete failed adding %s interface: %s",
device, mondevice, strerror(-err));
nlmsg_free(msg);
return PCAP_ERROR;
}
}
err = nl_wait_for_ack(state->nl_handle);
if (err < 0) {
if (err == -ENFILE) {
/*
* Device not available; our caller should just
* keep trying.
*/
nlmsg_free(msg);
return 0;
} else {
/*
* Real failure, not just "that device is not
* available.
*/
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_wait_for_ack failed adding %s interface: %s",
device, mondevice, strerror(-err));
nlmsg_free(msg);
return PCAP_ERROR;
}
}
/*
* Success.
*/
nlmsg_free(msg);
return 1;
nla_put_failure:
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_put failed adding %s interface",
device, mondevice);
nlmsg_free(msg);
return PCAP_ERROR;
}
static int
del_mon_if(pcap_t *handle, int sock_fd, struct nl80211_state *state,
const char *device, const char *mondevice)
{
int ifindex;
struct nl_msg *msg;
int err;
ifindex = iface_get_id(sock_fd, mondevice, handle->errbuf);
if (ifindex == -1)
return PCAP_ERROR;
msg = nlmsg_alloc();
if (!msg) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: failed to allocate netlink msg", device);
return PCAP_ERROR;
}
genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
0, NL80211_CMD_DEL_INTERFACE, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
err = nl_send_auto_complete(state->nl_handle, msg);
if (err < 0) {
if (err == -ENFILE) {
/*
* Device not available; our caller should just
* keep trying.
*/
nlmsg_free(msg);
return 0;
} else {
/*
* Real failure, not just "that device is not
* available.
*/
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_send_auto_complete failed deleting %s interface: %s",
device, mondevice, strerror(-err));
nlmsg_free(msg);
return PCAP_ERROR;
}
}
err = nl_wait_for_ack(state->nl_handle);
if (err < 0) {
if (err == -ENFILE) {
/*
* Device not available; our caller should just
* keep trying.
*/
nlmsg_free(msg);
return 0;
} else {
/*
* Real failure, not just "that device is not
* available.
*/
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_wait_for_ack failed adding %s interface: %s",
device, mondevice, strerror(-err));
nlmsg_free(msg);
return PCAP_ERROR;
}
}
/*
* Success.
*/
nlmsg_free(msg);
return 1;
nla_put_failure:
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: nl_put failed deleting %s interface",
device, mondevice);
nlmsg_free(msg);
return PCAP_ERROR;
}
#endif /* defined(IW_MODE_MONITOR) && defined(HAVE_LIBNL) */
/*
* With older kernels promiscuous mode is kind of interesting because we
* have to reset the interface before exiting. The problem can't really
@ -404,15 +678,19 @@ static void pcap_cleanup_linux( pcap_t *handle )
{
struct ifreq ifr;
#ifdef IW_MODE_MONITOR
#ifdef HAVE_LIBNL
struct nl80211_state nlstate;
int ret;
#endif /* HAVE_LIBNL */
struct iwreq ireq;
#endif
#endif /* IW_MODE_MONITOR */
if (handle->md.must_clear != 0) {
if (handle->md.must_do_on_close != 0) {
/*
* There's something we have to do when closing this
* pcap_t.
*/
if (handle->md.must_clear & MUST_CLEAR_PROMISC) {
if (handle->md.must_do_on_close & MUST_CLEAR_PROMISC) {
/*
* We put the interface into promiscuous mode;
* take it out of promiscuous mode.
@ -451,7 +729,24 @@ static void pcap_cleanup_linux( pcap_t *handle )
}
#ifdef IW_MODE_MONITOR
if (handle->md.must_clear & MUST_CLEAR_RFMON) {
#ifdef HAVE_LIBNL
if (handle->md.must_do_on_close & MUST_DELETE_MONIF) {
ret = nl80211_init(handle, &nlstate, handle->md.device);
if (ret >= 0) {
ret = del_mon_if(handle, handle->fd, &nlstate,
handle->md.device, handle->md.mondevice);
nl80211_cleanup(&nlstate);
}
if (ret < 0) {
fprintf(stderr,
"Can't delete monitor interface %s (%s).\n"
"Please delete manually.\n",
handle->md.mondevice, handle->errbuf);
}
}
#endif /* HAVE_LIBNL */
if (handle->md.must_do_on_close & MUST_CLEAR_RFMON) {
/*
* We put the interface into rfmon mode;
* take it out of rfmon mode.
@ -475,7 +770,7 @@ static void pcap_cleanup_linux( pcap_t *handle )
strerror(errno));
}
}
#endif
#endif /* IW_MODE_MONITOR */
/*
* Take this pcap out of the list of pcaps for which we
@ -484,6 +779,10 @@ static void pcap_cleanup_linux( pcap_t *handle )
pcap_remove_from_pcaps_to_close(handle);
}
if (handle->md.mondevice != NULL) {
free(handle->md.mondevice);
handle->md.mondevice = NULL;
}
if (handle->md.device != NULL) {
free(handle->md.device);
handle->md.device = NULL;
@ -1745,7 +2044,7 @@ activate_new(pcap_t *handle)
* because entering monitor mode could change
* the link-layer type.
*/
err = enter_rfmon_mode_wext(handle, sock_fd, device);
err = enter_rfmon_mode(handle, sock_fd, device);
if (err < 0) {
/* Hard failure */
close(sock_fd);
@ -1759,6 +2058,15 @@ activate_new(pcap_t *handle)
close(sock_fd);
return PCAP_ERROR_RFMON_NOTSUP;
}
/*
* Either monitor mode has been turned on for
* the device, or we've been given a different
* device to open for monitor mode. If we've
* been given a different device, use it.
*/
if (handle->md.mondevice != NULL)
device = handle->md.mondevice;
}
arptype = iface_get_arptype(sock_fd, device, handle->errbuf);
if (arptype < 0) {
@ -2624,7 +2932,6 @@ has_wext(int sock_fd, const char *device, char *ebuf)
return PCAP_ERROR_NO_SUCH_DEVICE;
return 0;
}
#endif
/*
* Per me si va ne la citta dolente,
@ -2647,6 +2954,207 @@ typedef enum {
MONITOR_RTL8XXX
} monitor_type;
/*
*
* If interface {if} is a mac80211 driver, the file
* /sys/class/net/{if}/phy80211 is a symlink to
* /sys/class/ieee80211/{phydev}, for some {phydev}.
*
* On Fedora 9, with a 2.6.26.3-29 kernel, my Zydas stick, at
* least, has a "wmaster0" device and a "wlan0" device; the
* latter is the one with the IP address. Both show up in
* "tcpdump -D" output. Capturing on the wmaster0 device
* captures with 802.11 headers.
*
* airmon-ng searches through /sys/class/net for devices named
* monN, starting with mon0; as soon as one *doesn't* exist,
* it chooses that as the monitor device name. If the "iw"
* command exists, it does "iw dev {if} interface add {monif}
* type monitor", where {monif} is the monitor device. It
* then (sigh) sleeps .1 second, and then configures the
* device up. Otherwise, if /sys/class/ieee80211/{phydev}/add_iface
* is a file, it writes {mondev}, without a newline, to that file,
* and again (sigh) sleeps .1 second, and then iwconfig's that
* device into monitor mode and configures it up. Otherwise,
* you can't do monitor mode.
*
* All these devices are "glued" together by having the
* /sys/class/net/{device}/phy80211 links pointing to the same
* place, so, given a wmaster, wlan, or mon device, you can
* find the other devices by looking for devices with
* the same phy80211 link.
*
* To turn monitor mode off, delete the monitor interface,
* either with "iw dev {monif} interface del" or by sending
* {monif}, with no NL, down /sys/class/ieee80211/{phydev}/remove_iface
*
* Note: if you try to create a monitor device named "monN", and
* there's already a "monN" device, it fails, as least with
* the netlink interface (which is what iw uses), with a return
* value of -ENFILE. (Return values are negative errnos.) We
* could probably use that to find an unused device.
*
* Yes, you can have multiple monitor devices for a given
* physical device.
*/
#ifdef HAVE_LIBNL
/*
* Is this a mac80211 device? If so, fill in the physical device path and
* return 1; if not, return 0. On an error, fill in handle->errbuf and
* return PCAP_ERROR.
*/
static int
get_mac80211_phydev(pcap_t *handle, const char *device, char *phydev_path,
size_t phydev_max_pathlen)
{
char *pathstr;
ssize_t bytes_read;
/*
* Generate the path string for the symlink to the physical device.
*/
if (asprintf(&pathstr, "/sys/class/net/%s/phy80211", device) == -1) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: Can't generate path name string for /sys/class/net device",
device);
return PCAP_ERROR;
}
bytes_read = readlink(pathstr, phydev_path, phydev_max_pathlen);
if (bytes_read == -1) {
if (errno == ENOENT || errno == EINVAL) {
/*
* Doesn't exist, or not a symlink; assume that
* means it's not a mac80211 device.
*/
free(pathstr);
return 0;
}
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: Can't readlink %s: %s", device, pathstr,
strerror(errno));
free(pathstr);
return PCAP_ERROR;
}
free(pathstr);
phydev_path[bytes_read] = '\0';
return 1;
}
static int
enter_rfmon_mode_mac80211(pcap_t *handle, int sock_fd, const char *device)
{
int ret;
char phydev_path[PATH_MAX+1];
struct nl80211_state nlstate;
struct ifreq ifr;
u_int n;
/*
* Is this a mac80211 device?
*/
ret = get_mac80211_phydev(handle, device, phydev_path, PATH_MAX);
if (ret < 0)
return ret; /* error */
if (ret == 0)
return 0; /* no error, but not mac80211 device */
/*
* XXX - is this already a monN device?
* If so, we're done.
* Is that determined by old Wireless Extensions ioctls?
*/
/*
* OK, it's apparently a mac80211 device.
* Try to find an unused monN device for it.
*/
ret = nl80211_init(handle, &nlstate, device);
if (ret != 0)
return ret;
for (n = 0; n < UINT_MAX; n++) {
/*
* Try mon{n}.
*/
char mondevice[3+10+1]; /* mon{UINT_MAX}\0 */
snprintf(mondevice, sizeof mondevice, "mon%u", n);
ret = add_mon_if(handle, sock_fd, &nlstate, device, mondevice);
if (ret == 1) {
handle->md.mondevice = strdup(mondevice);
goto added;
}
if (ret < 0) {
/*
* Hard failure. Just return ret; handle->errbuf
* has already been set.
*/
nl80211_cleanup(&nlstate);
return ret;
}
}
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: No free monN interfaces", device);
nl80211_cleanup(&nlstate);
return PCAP_ERROR;
added:
#if 0
/*
* Sleep for .1 seconds.
*/
delay.tv_sec = 0;
delay.tv_nsec = 500000000;
nanosleep(&delay, NULL);
#endif
/*
* Now configure the monitor interface up.
*/
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, handle->md.mondevice, sizeof(ifr.ifr_name));
if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: Can't get flags for %s: %s", device,
handle->md.mondevice, strerror(errno));
del_mon_if(handle, sock_fd, &nlstate, device,
handle->md.mondevice);
nl80211_cleanup(&nlstate);
return PCAP_ERROR;
}
ifr.ifr_flags |= IFF_UP|IFF_RUNNING;
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"%s: Can't set flags for %s: %s", device,
handle->md.mondevice, strerror(errno));
del_mon_if(handle, sock_fd, &nlstate, device,
handle->md.mondevice);
nl80211_cleanup(&nlstate);
return PCAP_ERROR;
}
/*
* Success. Clean up the libnl state.
*/
nl80211_cleanup(&nlstate);
/*
* Note that we have to delete the monitor device when we close
* the handle.
*/
handle->md.must_do_on_close |= MUST_DELETE_MONIF;
/*
* Add this to the list of pcaps to close when we exit.
*/
pcap_add_to_pcaps_to_close(handle);
return 1;
}
#endif /* HAVE_LIBNL */
/*
* Use the Wireless Extensions, if we have them, to try to turn monitor mode
* on if it's not already on.
@ -2658,7 +3166,6 @@ typedef enum {
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.
@ -3013,7 +3520,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
* Note that we have to put the old mode back
* when we close the device.
*/
handle->md.must_clear |= MUST_CLEAR_RFMON;
handle->md.must_do_on_close |= MUST_CLEAR_RFMON;
/*
* Add this to the list of pcaps to close
@ -3205,7 +3712,7 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
* Note that we have to put the old mode back when we
* close the device.
*/
handle->md.must_clear |= MUST_CLEAR_RFMON;
handle->md.must_do_on_close |= MUST_CLEAR_RFMON;
/*
* Add this to the list of pcaps to close when we exit.
@ -3213,13 +3720,39 @@ enter_rfmon_mode_wext(pcap_t *handle, int sock_fd, const char *device)
pcap_add_to_pcaps_to_close(handle);
return 1;
#else
}
#endif /* IW_MODE_MONITOR */
/*
* Try various mechanisms to enter monitor mode.
*/
static int
enter_rfmon_mode(pcap_t *handle, int sock_fd, const char *device)
{
#ifdef IW_MODE_MONITOR
int ret;
#ifdef HAVE_LIBNL
ret = enter_rfmon_mode_mac80211(handle, sock_fd, device);
if (ret < 0)
return ret; /* error attempting to do so */
if (ret == 1)
return 1; /* success */
#endif /* HAVE_LIBNL */
ret = enter_rfmon_mode_wext(handle, sock_fd, device);
if (ret < 0)
return ret; /* error attempting to do so */
if (ret == 1)
return 1; /* success */
#endif /* IW_MODE_MONITOR */
/*
* We don't have the Wireless Extensions available, so we can't
* do monitor mode.
* Either none of the mechanisms we know about work or none
* of those mechanisms are available, so we can't do monitor
* mode.
*/
return 0;
#endif
}
#endif /* HAVE_PF_PACKET_SOCKETS */
@ -3321,7 +3854,7 @@ activate_old(pcap_t *handle)
pcap_strerror(errno));
return PCAP_ERROR;
}
handle->md.must_clear |= MUST_CLEAR_PROMISC;
handle->md.must_do_on_close |= MUST_CLEAR_PROMISC;
/*
* Add this to the list of pcaps