summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ConfigureChecks.cmake30
-rw-r--r--configure.ac11
-rw-r--r--dumpcap.c85
3 files changed, 124 insertions, 2 deletions
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index 69ca619068..de25c64874 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -53,6 +53,35 @@ check_include_file("unistd.h" HAVE_UNISTD_H)
check_include_file("windows.h" HAVE_WINDOWS_H)
check_include_file("winsock2.h" HAVE_WINSOCK2_H)
+#
+# On Linux, check for some additional headers, which we need as a
+# workaround for a bonding driver bug and for libpcap's current lack
+# of its own workaround for that bug.
+#
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ #
+ # Those header files require <sys/socket.h>.
+ #
+ check_c_source_compiles(
+ "#include <sys/socket.h>
+ #include <linux/sockios.h>
+ int main(void)
+ {
+ return 0;
+ }"
+ HAVE_LINUX_SOCKIOS_H
+ )
+ check_c_source_compiles(
+ "#include <sys/socket.h>
+ #include <linux/if_bonding.h>
+ int main(void)
+ {
+ return 0;
+ }"
+ HAVE_LINUX_IF_BONDING_H
+ )
+endif()
+
#Functions
include(CheckFunctionExists)
include(CheckSymbolExists)
@@ -107,7 +136,6 @@ check_struct_has_member("struct tm" tm_zone time.h HAVE_TM_ZONE)
check_symbol_exists(tzname "time.h" HAVE_TZNAME)
# Check for stuff that isn't testable via the tests above
-#include(CheckCSourceCompiles)
#
# *If* we found libnl, check if we can use nl80211 stuff with it.
diff --git a/configure.ac b/configure.ac
index 857e898089..085b663a52 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2606,6 +2606,17 @@ AC_CHECK_HEADERS(sys/ioctl.h sys/param.h sys/socket.h sys/sockio.h sys/stat.h sy
AC_CHECK_HEADERS(netinet/in.h)
AC_CHECK_HEADERS(arpa/inet.h arpa/nameser.h)
+#
+# On Linux, check for some additional headers, which we need as a
+# workaround for a bonding driver bug and for libpcap's current lack
+# of its own workaround for that bug.
+#
+case "$host_os" in
+linux*)
+ AC_CHECK_HEADERS(linux/sockios.h linux/if_bonding.h,,,[#include <sys/socket.h>])
+ ;;
+esac
+
dnl SSL Check
SSL_LIBS=''
AC_MSG_CHECKING(whether to use SSL library)
diff --git a/dumpcap.c b/dumpcap.c
index 1bdffabbdc..696f6f706d 100644
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -63,6 +63,39 @@
#include <sys/utsname.h>
#endif
+/*
+ * Linux bonding devices mishandle unknown ioctls; they fail
+ * with ENODEV rather than ENOTSUP, EOPNOTSUPP, or ENOTTY,
+ * so pcap_can_set_rfmon() returns a "no such device" indication
+ * if we try to do SIOCGIWMODE on them.
+ *
+ * So, on Linux, we check for bonding devices, if we can, before
+ * trying pcap_can_set_rfmon(), as pcap_can_set_rfmon() will
+ * end up trying SIOCGIWMODE on the device if that ioctl exists.
+ */
+#if defined(HAVE_PCAP_CREATE) && defined(__linux__)
+
+#include <sys/ioctl.h>
+
+/*
+ * If we're building for a Linux version that supports bonding,
+ * HAVE_BONDING will be defined.
+ */
+
+#ifdef HAVE_LINUX_SOCKIOS_H
+#include <linux/sockios.h>
+#endif
+
+#ifdef HAVE_LINUX_IF_BONDING_H
+#include <linux/if_bonding.h>
+#endif
+
+#if defined(BOND_INFO_QUERY_OLD) || defined(SIOCBONDINFOQUERY)
+#define HAVE_BONDING
+#endif
+
+#endif /* defined(HAVE_PCAP_CREATE) && defined(__linux__) */
+
#include <signal.h>
#include <errno.h>
@@ -1117,6 +1150,44 @@ create_data_link_info(int dlt)
return data_link_info;
}
+#ifdef HAVE_BONDING
+gboolean
+is_linux_bonding_device(const char *ifname)
+{
+ int fd;
+ struct ifreq ifr;
+ ifbond ifb;
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd == -1)
+ return FALSE;
+
+ memset(&ifr, 0, sizeof ifr);
+ g_strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
+ memset(&ifb, 0, sizeof ifb);
+ ifr.ifr_data = (caddr_t)&ifb;
+#if defined(SIOCBONDINFOQUERY)
+ if (ioctl(fd, SIOCBONDINFOQUERY, &ifr) == 0) {
+ close(fd);
+ return TRUE;
+ }
+#else
+ if (ioctl(fd, BOND_INFO_QUERY_OLD, &ifr) == 0) {
+ close(fd);
+ return TRUE;
+ }
+#endif
+
+ return FALSE;
+}
+#else
+static gboolean
+is_linux_bonding_device(const char *ifname _U_)
+{
+ return FALSE;
+}
+#endif
+
/*
* Get the capabilities of a network device.
*/
@@ -1177,7 +1248,19 @@ get_if_capabilities(const char *devicename, gboolean monitor_mode
g_free(caps);
return NULL;
}
- status = pcap_can_set_rfmon(pch);
+ if (is_linux_bonding_device(devicename)) {
+ /*
+ * Linux bonding device; not Wi-Fi, so no monitor mode, and
+ * calling pcap_can_set_rfmon() might get a "no such device"
+ * error.
+ */
+ status = 0;
+ } else {
+ /*
+ * Not a Linux bonding device, so go ahead.
+ */
+ status = pcap_can_set_rfmon(pch);
+ }
if (status < 0) {
/* Error. */
if (status == PCAP_ERROR)