aboutsummaryrefslogtreecommitdiffstats
path: root/caputils
diff options
context:
space:
mode:
Diffstat (limited to 'caputils')
-rw-r--r--caputils/CMakeLists.txt61
-rw-r--r--caputils/Makefile.am89
-rw-r--r--caputils/Makefile.common35
-rw-r--r--caputils/Makefile.nmake82
-rw-r--r--caputils/capture-pcap-util-int.h44
-rw-r--r--caputils/capture-pcap-util-unix.c434
-rw-r--r--caputils/capture-pcap-util.c639
-rw-r--r--caputils/capture-pcap-util.h74
-rw-r--r--caputils/capture-wpcap.c990
-rw-r--r--caputils/capture-wpcap.h42
-rw-r--r--caputils/capture_ifinfo.h121
-rw-r--r--caputils/capture_win_ifnames.c369
-rw-r--r--caputils/capture_win_ifnames.h46
-rw-r--r--caputils/capture_wpcap_packet.c331
-rw-r--r--caputils/capture_wpcap_packet.h51
-rw-r--r--caputils/doxygen.cfg.in81
-rw-r--r--caputils/ws80211_utils.c748
-rw-r--r--caputils/ws80211_utils.h61
18 files changed, 4298 insertions, 0 deletions
diff --git a/caputils/CMakeLists.txt b/caputils/CMakeLists.txt
new file mode 100644
index 0000000000..4c8dab086a
--- /dev/null
+++ b/caputils/CMakeLists.txt
@@ -0,0 +1,61 @@
+# CMakeLists.txt
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# Copyright 1998 Gerald Combs
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+
+if(UNIX)
+ set(PLATFORM_CAPUTILS_SRC
+ capture-pcap-util-unix.c
+ )
+endif()
+
+if(WIN32)
+ set(PLATFORM_CAPUTILS_SRC
+ capture_win_ifnames.c
+ capture-wpcap.c
+ capture_wpcap_packet.c
+ )
+endif()
+
+set(CAPUTILS_SRC
+ ${PLATFORM_CAPUTILS_SRC}
+ capture-pcap-util.c
+ ws80211_utils.c
+)
+
+set(CLEAN_FILES
+ ${CAPUTILS_SRC}
+)
+
+if (WERROR)
+ set_source_files_properties(
+ ${CLEAN_FILES}
+ PROPERTIES
+ COMPILE_FLAGS -Werror
+ )
+endif()
+
+
+add_library(caputils STATIC
+ ${CAPUTILS_SRC}
+)
+
+set_target_properties(caputils PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}")
+set_target_properties(caputils PROPERTIES FOLDER "CAPUTILS")
diff --git a/caputils/Makefile.am b/caputils/Makefile.am
new file mode 100644
index 0000000000..ad0326f5a5
--- /dev/null
+++ b/caputils/Makefile.am
@@ -0,0 +1,89 @@
+# Makefile.am
+# Automake file for the "capture utilities" routines for Wireshark
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# Copyright 1998 Gerald Combs
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include Makefile.common
+include ../Makefile.am.inc
+
+if HAVE_WARNINGS_AS_ERRORS
+AM_CLEAN_CFLAGS = -Werror
+endif
+
+noinst_LIBRARIES = libcaputils.a
+
+PLATFORM_CAPUTILS_SRC = \
+ capture-pcap-util-unix.c
+
+CLEANFILES = \
+ doxygen-caputils.tag \
+ libcaputils.a \
+ *~
+
+MAINTAINERCLEANFILES = \
+ $(GENERATED_FILES) \
+ Makefile.in
+
+# All sources that should be put in the source distribution tarball
+libcaputils_a_SOURCES = \
+ $(CAPUTILS_SRC) \
+ $(noinst_HEADERS)
+
+libcaputils_a_CFLAGS = $(AM_CLEAN_CFLAGS)
+
+libcaputils_a_DEPENDENCIES =
+
+# Common headers
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/wiretap $(LIBGCRYPT_CFLAGS) $(LIBGNUTLS_CFLAGS) $(PORTAUDIO_INCLUDES)
+
+
+doxygen:
+if HAVE_DOXYGEN
+ $(DOXYGEN) doxygen.cfg
+endif # HAVE_DOXYGEN
+
+wsar_html: doxygen.cfg ../doxygen_global.cfg
+if HAVE_DOXYGEN
+ (umask 022 ; $(DOXYGEN) doxygen.cfg)
+endif
+
+checkapi: checkapi-base checkapi-todo
+
+checkapi-base:
+ $(PERL) $(top_srcdir)/tools/checkAPIs.pl -g deprecated-gtk -build \
+ -sourcedir=$(srcdir) \
+ $(CAPUTILS_SRC)
+
+checkapi-todo:
+ $(PERL) $(top_srcdir)/tools/checkAPIs.pl -M -g deprecated-gtk-todo -build \
+ -sourcedir=$(srcdir) \
+ $(CAPUTILS_SRC)
+
+EXTRA_DIST = \
+ $(GENERATOR_FILES) \
+ capture_win_ifnames.c \
+ capture_win_ifnames.h \
+ capture-wpcap.c \
+ capture-wpcap.h \
+ capture_wpcap_packet.c \
+ capture_wpcap_packet.h \
+ CMakeLists.txt \
+ doxygen.cfg.in \
+ Makefile.common \
+ Makefile.nmake
diff --git a/caputils/Makefile.common b/caputils/Makefile.common
new file mode 100644
index 0000000000..57599380a7
--- /dev/null
+++ b/caputils/Makefile.common
@@ -0,0 +1,35 @@
+# Makefile.common
+# Contains the stuff from Makefile.am and Makefile.nmake that is
+# a) common to both files and
+# b) portable between both files
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# Copyright 1998 Gerald Combs
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+CAPUTILS_SRC = \
+ $(PLATFORM_CAPUTILS_SRC) \
+ capture-pcap-util.c \
+ ws80211_utils.c
+
+noinst_HEADERS = \
+ capture_ifinfo.h \
+ capture-pcap-util.h \
+ capture-pcap-util-int.h \
+ capture-wpcap.h \
+ capture_wpcap_packet.h \
+ ws80211_utils.h
diff --git a/caputils/Makefile.nmake b/caputils/Makefile.nmake
new file mode 100644
index 0000000000..55dd1a6fb1
--- /dev/null
+++ b/caputils/Makefile.nmake
@@ -0,0 +1,82 @@
+## Makefile for building wireshark.exe with Microsoft C and nmake
+## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
+#
+
+include ..\config.nmake
+include ..\Makefile.nmake.inc
+
+############### no need to modify below this line #########
+
+# We use GENERATED_CFLAGS to get around flex's non-LLP64-compliant output
+GENERATED_CFLAGS=\
+ $(STANDARD_CFLAGS) \
+ /Zm800 \
+ /I.. /I../wiretap $(GLIB_CFLAGS) $(GNUTLS_CFLAGS) \
+ /I$(PCAP_DIR)\WPCAP\LIBPCAP /I$(PCAP_DIR)\WPCAP\LIBPCAP\bpf \
+ /I$(PCAP_DIR)\WPCAP\LIBPCAP\lbl \
+ /I$(PCAP_DIR)\include $(AIRPCAP_CFLAGS) \
+ $(PORTAUDIO_CFLAGS) $(GEOIP_CFLAGS) $(WINSPARKLE_CFLAGS) \
+ $(HHC_CFLAGS)
+
+CFLAGS=$(WARNINGS_ARE_ERRORS) $(GENERATED_CFLAGS)
+
+.c.obj::
+ $(CC) $(CFLAGS) $(WSUG_CFLAGS) -Fd.\ -c $<
+
+PLATFORM_CAPUTILS_SRC = \
+ capture_win_ifnames.c \
+ capture-wpcap.c \
+ capture_wpcap_packet.c
+
+include Makefile.common
+
+
+# if you add files here, be sure to include them also in Makefile.am EXTRA_DIST
+CAPUTILS_OBJECTS = \
+ $(CAPUTILS_SRC:.c=.obj)
+
+RUNLEX=..\tools\runlex.sh
+
+libcaputils.lib : ..\config.h $(CAPUTILS_OBJECTS)
+ link /lib /out:libcaputils.lib $(CAPUTILS_OBJECTS)
+
+clean:
+ rm -f $(CAPUTILS_OBJECTS) $(WIRESHARK_TAP_OBJECTS) libcaputils.lib *.pdb *.sbr \
+ doxygen.cfg html/*.* wireshark-tap-register-cache.pkl
+ if exist html rmdir html
+
+distclean: clean
+
+maintainer-clean: distclean
+ rm -f $(GENERATED_FILES)
+
+# convert doxygen.cfg.in to doxygen.cfg with stamped version info
+doxygen.cfg: ..\config.nmake doxygen.cfg.in
+!IFDEF DOXYGEN
+ sed -e s/@VERSION@/$(VERSION)/ \
+ < doxygen.cfg.in > $@
+!ENDIF
+
+doxygen-run:
+!IFDEF DOXYGEN
+ $(DOXYGEN) doxygen.cfg
+!ENDIF
+
+# MS html help compiler hhc returns 1 on success, but as nmake expects 0 it would stop here.
+# the prepended -1 will raise the accepted error levels of nmake, so it will continue
+doxygen.chm:
+!IFDEF HHC
+ -1 $(HHC) html\index.hhp
+!ENDIF
+
+doxygen: doxygen.cfg doxygen-run doxygen.chm
+
+checkapi: checkapi-base checkapi-todo
+
+checkapi-base:
+ $(PERL) ../tools/checkAPIs.pl -g deprecated-gtk -build \
+ $(CAPUTILS_SRC)
+
+checkapi-todo:
+ $(PERL) ../tools/checkAPIs.pl -M -g deprecated-gtk-todo -build \
+ $(CAPUTILS_SRC)
diff --git a/caputils/capture-pcap-util-int.h b/caputils/capture-pcap-util-int.h
new file mode 100644
index 0000000000..d49a0cef04
--- /dev/null
+++ b/caputils/capture-pcap-util-int.h
@@ -0,0 +1,44 @@
+/* capture-pcap-util-int.h
+ * Definitions of routines internal to the libpcap/WinPcap utilities
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __PCAP_UTIL_INT_H__
+#define __PCAP_UTIL_INT_H__
+
+extern if_info_t *if_info_new(const char *name, const char *description,
+ gboolean loopback);
+extern void if_info_add_address(if_info_t *if_info, struct sockaddr *addr);
+#ifdef HAVE_PCAP_FINDALLDEVS
+#ifdef HAVE_PCAP_REMOTE
+extern GList *get_interface_list_findalldevs_ex(const char *source,
+ struct pcap_rmtauth *auth, int *err, char **err_str);
+#endif /* HAVE_PCAP_REMOTE */
+extern GList *get_interface_list_findalldevs(int *err, char **err_str);
+#endif /* HAVE_PCAP_FINDALLDEVS */
+
+/*
+ * Get an error message string for a CANT_GET_INTERFACE_LIST error from
+ * "get_interface_list()". This is used to let the error message string
+ * be platform-dependent.
+ */
+extern gchar *cant_get_if_list_error_message(const char *err_str);
+
+#endif /* __PCAP_UTIL_INT_H__ */
diff --git a/caputils/capture-pcap-util-unix.c b/caputils/capture-pcap-util-unix.c
new file mode 100644
index 0000000000..21e832b166
--- /dev/null
+++ b/caputils/capture-pcap-util-unix.c
@@ -0,0 +1,434 @@
+/* capture-pcap-util-unix.c
+ * UN*X-specific utility routines for packet capture
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+
+#ifdef HAVE_LIBPCAP
+
+#ifdef HAVE_PCAP_FINDALLDEVS
+
+#include <pcap.h>
+
+#else /* HAVE_PCAP_FINDALLDEVS */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * Keep Digital UNIX happy when including <net/if.h>.
+ */
+struct mbuf;
+struct rtentry;
+#include <net/if.h>
+
+#ifdef HAVE_SYS_SOCKIO_H
+# include <sys/sockio.h>
+#endif
+
+#include "caputils/capture-pcap-util.h"
+
+#endif /* HAVE_PCAP_FINDALLDEVS */
+
+#ifdef HAVE_LIBCAP
+# include <sys/capability.h>
+#endif
+
+#include "caputils/capture_ifinfo.h"
+#include "caputils/capture-pcap-util.h"
+#include "caputils/capture-pcap-util-int.h"
+
+#ifdef HAVE_PCAP_REMOTE
+GList *
+get_remote_interface_list(const char *hostname, const char *port,
+ int auth_type, const char *username,
+ const char *passwd, int *err, char **err_str)
+{
+ struct pcap_rmtauth auth;
+ char source[PCAP_BUF_SIZE];
+ char errbuf[PCAP_ERRBUF_SIZE];
+ GList *result;
+
+ if (pcap_createsrcstr(source, PCAP_SRC_IFREMOTE, hostname, port,
+ NULL, errbuf) == -1) {
+ *err = CANT_GET_INTERFACE_LIST;
+ if (err_str != NULL)
+ *err_str = cant_get_if_list_error_message(errbuf);
+ return NULL;
+ }
+
+ auth.type = auth_type;
+ auth.username = g_strdup(username);
+ auth.password = g_strdup(passwd);
+
+ result = get_interface_list_findalldevs_ex(source, &auth, err, err_str);
+ g_free(auth.username);
+ g_free(auth.password);
+
+ return result;
+}
+#endif
+
+#ifdef HAVE_PCAP_FINDALLDEVS
+GList *
+get_interface_list(int *err, char **err_str)
+{
+ return get_interface_list_findalldevs(err, err_str);
+}
+#else /* HAVE_PCAP_FINDALLDEVS */
+struct search_user_data {
+ char *name;
+ if_info_t *if_info;
+};
+
+static void
+search_for_if_cb(gpointer data, gpointer user_data)
+{
+ struct search_user_data *search_user_data = user_data;
+ if_info_t *if_info = data;
+
+ if (strcmp(if_info->name, search_user_data->name) == 0)
+ search_user_data->if_info = if_info;
+}
+
+GList *
+get_interface_list(int *err, char **err_str)
+{
+ GList *il = NULL;
+ gint nonloopback_pos = 0;
+ struct ifreq *ifr, *last;
+ struct ifconf ifc;
+ struct ifreq ifrflags;
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ struct search_user_data user_data;
+ pcap_t *pch;
+ int len, lastlen;
+ char *buf;
+ if_info_t *if_info;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ gboolean loopback;
+
+ if (sock < 0) {
+ *err = CANT_GET_INTERFACE_LIST;
+ if (err_str != NULL) {
+ *err_str = g_strdup_printf(
+ "Can't get list of interfaces: error opening socket: %s",
+ g_strerror(errno));
+ }
+ return NULL;
+ }
+
+ /*
+ * This code came from: W. Richard Stevens: "UNIX Network Programming",
+ * Networking APIs: Sockets and XTI, Vol 1, page 434.
+ */
+ lastlen = 0;
+ len = 100 * sizeof(struct ifreq);
+ for ( ; ; ) {
+ buf = g_malloc(len);
+ ifc.ifc_len = len;
+ ifc.ifc_buf = buf;
+ memset (buf, 0, len);
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ if (errno != EINVAL || lastlen != 0) {
+ if (err_str != NULL) {
+ *err_str = g_strdup_printf(
+ "Can't get list of interfaces: SIOCGIFCONF ioctl error: %s",
+ g_strerror(errno));
+ }
+ goto fail;
+ }
+ } else {
+ if ((unsigned int) ifc.ifc_len < sizeof(struct ifreq)) {
+ if (err_str != NULL) {
+ *err_str = g_strdup(
+ "Can't get list of interfaces: SIOCGIFCONF ioctl gave too small return buffer");
+ }
+ goto fail;
+ }
+ if (ifc.ifc_len == lastlen)
+ break; /* success, len has not changed */
+ lastlen = ifc.ifc_len;
+ }
+ len += 10 * sizeof(struct ifreq); /* increment */
+ g_free(buf);
+ }
+ ifr = (struct ifreq *) ifc.ifc_req;
+ last = (struct ifreq *) ((char *) ifr + ifc.ifc_len);
+ while (ifr < last) {
+ /*
+ * Skip entries that begin with "dummy", or that include
+ * a ":" (the latter are Solaris virtuals).
+ */
+ if (strncmp(ifr->ifr_name, "dummy", 5) == 0 ||
+ strchr(ifr->ifr_name, ':') != NULL)
+ goto next;
+
+ /*
+ * If we already have this interface name on the list,
+ * don't add it, but, if we don't already have an IP
+ * address for it, add that address (SIOCGIFCONF returns,
+ * at least on BSD-flavored systems, one entry per
+ * interface *address*; if an interface has multiple
+ * addresses, we get multiple entries for it).
+ */
+ user_data.name = ifr->ifr_name;
+ user_data.if_info = NULL;
+ g_list_foreach(il, search_for_if_cb, &user_data);
+ if (user_data.if_info != NULL) {
+ if_info_add_address(user_data.if_info, &ifr->ifr_addr);
+ goto next;
+ }
+
+ /*
+ * Get the interface flags.
+ */
+ memset(&ifrflags, 0, sizeof ifrflags);
+ g_strlcpy(ifrflags.ifr_name, ifr->ifr_name,
+ sizeof ifrflags.ifr_name);
+ if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifrflags) < 0) {
+ if (errno == ENXIO)
+ goto next;
+ if (err_str != NULL) {
+ *err_str = g_strdup_printf(
+ "Can't get list of interfaces: SIOCGIFFLAGS error getting flags for interface %s: %s",
+ ifr->ifr_name, g_strerror(errno));
+ }
+ goto fail;
+ }
+
+ /*
+ * Skip interfaces that aren't up.
+ */
+ if (!(ifrflags.ifr_flags & IFF_UP))
+ goto next;
+
+ /*
+ * Skip interfaces that we can't open with "libpcap".
+ * Open with the minimum packet size - it appears that the
+ * IRIX SIOCSNOOPLEN "ioctl" may fail if the capture length
+ * supplied is too large, rather than just truncating it.
+ */
+ pch = pcap_open_live(ifr->ifr_name, MIN_PACKET_SIZE, 0, 0,
+ errbuf);
+ if (pch == NULL)
+ goto next;
+ pcap_close(pch);
+
+ /*
+ * If it's a loopback interface, add it at the end of the
+ * list, otherwise add it after the last non-loopback
+ * interface, so all loopback interfaces go at the end - we
+ * don't want a loopback interface to be the default capture
+ * device unless there are no non-loopback devices.
+ */
+ loopback = ((ifrflags.ifr_flags & IFF_LOOPBACK) ||
+ strncmp(ifr->ifr_name, "lo", 2) == 0);
+ if_info = if_info_new(ifr->ifr_name, NULL, loopback);
+ if_info_add_address(if_info, &ifr->ifr_addr);
+ if (loopback)
+ il = g_list_append(il, if_info);
+ else {
+ il = g_list_insert(il, if_info, nonloopback_pos);
+ /*
+ * Insert the next non-loopback interface after this
+ * one.
+ */
+ nonloopback_pos++;
+ }
+
+ next:
+#ifdef HAVE_SA_LEN
+ ifr = (struct ifreq *) ((char *) ifr +
+ (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr) ?
+ ifr->ifr_addr.sa_len : sizeof(ifr->ifr_addr)) +
+ IFNAMSIZ);
+#else
+ ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq));
+#endif
+ }
+
+#ifdef linux
+ /*
+ * OK, maybe we have support for the "any" device, to do a cooked
+ * capture on all interfaces at once.
+ * Try opening it and, if that succeeds, add it to the end of
+ * the list of interfaces.
+ */
+ pch = pcap_open_live("any", MIN_PACKET_SIZE, 0, 0, errbuf);
+ if (pch != NULL) {
+ /*
+ * It worked; we can use the "any" device.
+ */
+ if_info = if_info_new("any",
+ "Pseudo-device that captures on all interfaces", FALSE);
+ il = g_list_insert(il, if_info, -1);
+ pcap_close(pch);
+ }
+#endif
+
+ g_free(ifc.ifc_buf);
+ close(sock);
+
+ if (il == NULL) {
+ /*
+ * No interfaces found.
+ */
+ *err = NO_INTERFACES_FOUND;
+ if (err_str != NULL)
+ *err_str = NULL;
+ }
+ return il;
+
+fail:
+ if (il != NULL)
+ free_interface_list(il);
+ g_free(ifc.ifc_buf);
+ close(sock);
+ *err = CANT_GET_INTERFACE_LIST;
+ return NULL;
+}
+#endif /* HAVE_PCAP_FINDALLDEVS */
+
+/*
+ * Get an error message string for a CANT_GET_INTERFACE_LIST error from
+ * "get_interface_list()".
+ */
+gchar *
+cant_get_if_list_error_message(const char *err_str)
+{
+ return g_strdup_printf("Can't get list of interfaces: %s", err_str);
+}
+
+/*
+ * Get the versions of libpcap, libpcap, and libnl with which we were
+ * compiled, and append them to a GString.
+ */
+void
+get_compiled_caplibs_version(GString *str)
+{
+ /*
+ * NOTE: in *some* flavors of UN*X, the data from a shared
+ * library might be linked into executable images that are
+ * linked with that shared library, in which case you could
+ * look at pcap_version[] to get the version with which
+ * the program was compiled.
+ *
+ * In other flavors of UN*X, that doesn't happen, so
+ * pcap_version[] gives you the version the program is
+ * running with, not the version it was built with, and,
+ * in at least some of them, if the length of a data item
+ * referred to by the executable - such as the pcap_version[]
+ * string - isn't the same in the version of the library
+ * with which the program was built and the version with
+ * which it was run, the run-time linker will complain,
+ * which is Not Good.
+ *
+ * So, for now, we just give up on reporting the version
+ * of libpcap with which we were compiled.
+ */
+ g_string_append(str, "with libpcap");
+
+ /*
+ * XXX - these libraries are actually used only by dumpcap,
+ * but we mention them here so that a user reporting a bug
+ * can get information about dumpcap's libraries without
+ * having to run dumpcap.
+ */
+ /* LIBCAP */
+ g_string_append(str, ", ");
+#ifdef HAVE_LIBCAP
+ g_string_append(str, "with POSIX capabilities");
+#ifdef _LINUX_CAPABILITY_VERSION
+ g_string_append(str, " (Linux)");
+#endif /* _LINUX_CAPABILITY_VERSION */
+#else /* HAVE_LIBCAP */
+ g_string_append(str, "without POSIX capabilities");
+#endif /* HAVE_LIBCAP */
+
+#ifdef __linux__
+ /* This is a Linux-specific library. */
+ /* LIBNL */
+ g_string_append(str, ", ");
+#if defined(HAVE_LIBNL1)
+ g_string_append(str, "with libnl 1");
+#elif defined(HAVE_LIBNL2)
+ g_string_append(str, "with libnl 2");
+#elif defined(HAVE_LIBNL3)
+ g_string_append(str, "with libnl 3");
+#else /* no libnl */
+ g_string_append(str, "without libnl");
+#endif /* libnl version */
+#endif /* __linux__ */
+}
+
+/*
+ * Append the version of libpcap with which we we're running to a GString.
+ */
+void
+get_runtime_caplibs_version(GString *str)
+{
+ g_string_append_printf(str, "with ");
+#ifdef HAVE_PCAP_LIB_VERSION
+ g_string_append(str, pcap_lib_version());
+#else
+ g_string_append(str, "libpcap (version unknown)");
+#endif
+}
+
+#else /* HAVE_LIBPCAP */
+
+/*
+ * Append an indication that we were not compiled with libpcap
+ * to a GString. Don't even bother mentioning the other
+ * libraries.
+ */
+void
+get_compiled_caplibs_version(GString *str)
+{
+ g_string_append(str, "without libpcap");
+}
+
+/*
+ * Don't append anything, as we weren't even compiled to use libpcap.
+ */
+void
+get_runtime_caplibs_version(GString *str _U_)
+{
+}
+
+#endif /* HAVE_LIBPCAP */
diff --git a/caputils/capture-pcap-util.c b/caputils/capture-pcap-util.c
new file mode 100644
index 0000000000..c4e7df3868
--- /dev/null
+++ b/caputils/capture-pcap-util.c
@@ -0,0 +1,639 @@
+/* capture-pcap-util.c
+ * Utility routines for packet capture
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LIBPCAP
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include <wtap.h>
+#include <libpcap.h>
+
+#include "caputils/capture_ifinfo.h"
+#include "caputils/capture-pcap-util.h"
+#include "caputils/capture-pcap-util-int.h"
+
+#include "wsutil/file_util.h"
+
+#ifndef _WIN32
+#include <netinet/in.h>
+#endif
+
+#ifdef _WIN32
+#include "caputils/capture_win_ifnames.h" /* windows friendly interface names */
+#endif
+
+/*
+ * Given an interface name, find the "friendly name" and interface
+ * type for the interface.
+ */
+
+#if defined(__APPLE__)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include <wsutil/cfutils.h>
+
+/*
+ * On OS X, we get the "friendly name" and interface type for the interface
+ * from the System Configuration framework.
+ *
+ * To find the System Configuration framework information for the
+ * interface, we get all the interfaces that the System Configuration
+ * framework knows about and look for the one with a "BSD name" matching
+ * the interface name.
+ *
+ * If we find it, we use its "localized display name", if it has one, as
+ * the "friendly name".
+ *
+ * As for the interface type:
+ *
+ * Yes, fetching all the network addresses for an interface gets you an
+ * AF_LINK address, of type "struct sockaddr_dl", and, yes, that includes
+ * an SNMP MIB-II ifType value.
+ *
+ * However, it's IFT_ETHER, i.e. Ethernet, for AirPort interfaces,
+ * not IFT_IEEE80211 (which isn't defined in OS X in any case).
+ *
+ * Perhaps some other BSD-flavored OSes won't make this mistake;
+ * however, FreeBSD 7.0 and OpenBSD 4.2, at least, appear to have
+ * made the same mistake, at least for my Belkin ZyDAS stick.
+ *
+ * SCNetworkInterfaceGetInterfaceType() will get the interface
+ * type. The interface type is a CFString, and:
+ *
+ * kSCNetworkInterfaceTypeIEEE80211 means IF_WIRELESS;
+ * kSCNetworkInterfaceTypeBluetooth means IF_BLUETOOTH;
+ * kSCNetworkInterfaceTypeModem or
+ * kSCNetworkInterfaceTypePPP or
+ * maybe kSCNetworkInterfaceTypeWWAN means IF_DIALUP
+ */
+static void
+add_unix_interface_ifinfo(if_info_t *if_info, const char *name,
+ const char *description _U_)
+{
+ CFStringRef name_CFString;
+ CFArrayRef interfaces;
+ CFIndex num_interfaces;
+ CFIndex i;
+ SCNetworkInterfaceRef interface;
+ CFStringRef bsdname_CFString;
+ CFStringRef friendly_name_CFString;
+ CFStringRef interface_type_CFString;
+
+ interfaces = SCNetworkInterfaceCopyAll();
+ if (interfaces == NULL) {
+ /*
+ * Couldn't get a list of interfaces.
+ */
+ return;
+ }
+
+ name_CFString = CFStringCreateWithCString(kCFAllocatorDefault,
+ name, kCFStringEncodingUTF8);
+ if (name_CFString == NULL) {
+ /*
+ * Couldn't convert the interface name to a CFString.
+ */
+ CFRelease(interfaces);
+ return;
+ }
+
+ num_interfaces = CFArrayGetCount(interfaces);
+ for (i = 0; i < num_interfaces; i++) {
+ interface = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(interfaces, i);
+ bsdname_CFString = SCNetworkInterfaceGetBSDName(interface);
+ if (bsdname_CFString == NULL) {
+ /*
+ * This interface has no BSD name, so it's not
+ * a regular network interface.
+ */
+ continue;
+ }
+ if (CFStringCompare(name_CFString, bsdname_CFString, 0) == 0) {
+ /*
+ * This is the interface.
+ * First, get the friendly name.
+ */
+ friendly_name_CFString = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+ if (friendly_name_CFString != NULL)
+ if_info->friendly_name = CFString_to_C_string(friendly_name_CFString);
+
+ /*
+ * Now get the interface type.
+ */
+ interface_type_CFString = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFStringCompare(interface_type_CFString,
+ kSCNetworkInterfaceTypeIEEE80211, 0) == kCFCompareEqualTo)
+ if_info->type = IF_WIRELESS;
+ else if (CFStringCompare(interface_type_CFString,
+ kSCNetworkInterfaceTypeBluetooth, 0) == kCFCompareEqualTo)
+ if_info->type = IF_BLUETOOTH;
+ else if (CFStringCompare(interface_type_CFString,
+ kSCNetworkInterfaceTypeModem, 0) == kCFCompareEqualTo)
+ if_info->type = IF_DIALUP;
+ else if (CFStringCompare(interface_type_CFString,
+ kSCNetworkInterfaceTypePPP, 0) == kCFCompareEqualTo)
+ if_info->type = IF_DIALUP;
+ else if (CFStringCompare(interface_type_CFString,
+ kSCNetworkInterfaceTypeWWAN, 0) == kCFCompareEqualTo)
+ if_info->type = IF_DIALUP;
+ else
+ if_info->type = IF_WIRED;
+ break;
+ }
+ }
+
+ CFRelease(interfaces);
+ CFRelease(name_CFString);
+}
+#elif defined(__linux__)
+/*
+ * Linux doesn't offer any form of "friendly name", but you can
+ * determine an interface type to some degree.
+ */
+static void
+add_unix_interface_ifinfo(if_info_t *if_info, const char *name,
+ const char *description _U_)
+{
+ char *wireless_path;
+ ws_statb64 statb;
+
+ /*
+ * Look for /sys/class/net/{device}/wireless. If it exists,
+ * it's a wireless interface.
+ */
+ wireless_path = g_strdup_printf("/sys/class/net/%s/wireless", name);
+ if (wireless_path != NULL) {
+ if (ws_stat64(wireless_path, &statb) == 0)
+ if_info->type = IF_WIRELESS;
+ g_free(wireless_path);
+ }
+ if (if_info->type == IF_WIRED) {
+ /*
+ * We still don't know what it is. Check for
+ * Bluetooth and USB devices.
+ */
+ if (strstr(name, "bluetooth") != NULL) {
+ /*
+ * XXX - this is for raw Bluetooth capture; what
+ * about IP-over-Bluetooth devices?
+ */
+ if_info->type = IF_BLUETOOTH;
+ } else if (strstr(name, "usbmon") != NULL)
+ if_info->type = IF_USB;
+ }
+}
+#else
+/*
+ * On other UN*Xes, if there is a description, it's a friendly
+ * name, and there is no vendor description. ("Other UN*Xes"
+ * currently means "FreeBSD and OpenBSD".)
+ */
+void
+add_unix_interface_ifinfo(if_info_t *if_info, const char *name _U_,
+ const char *description)
+{
+ if_info->friendly_name = g_strdup(description);
+}
+#endif
+
+if_info_t *
+if_info_new(const char *name, const char *description, gboolean loopback)
+{
+ if_info_t *if_info;
+#ifdef _WIN32
+ const char *guid_text;
+ GUID guid;
+#endif
+
+ if_info = (if_info_t *)g_malloc(sizeof (if_info_t));
+ if_info->name = g_strdup(name);
+ if_info->friendly_name = NULL; /* default - unknown */
+ if_info->vendor_description = NULL;
+ if_info->type = IF_WIRED; /* default */
+#ifdef _WIN32
+ /*
+ * Get the interface type.
+ *
+ * Much digging failed to reveal any obvious way to get something
+ * such as the SNMP MIB-II ifType value for an interface:
+ *
+ * http://www.iana.org/assignments/ianaiftype-mib
+ *
+ * by making some NDIS request. And even if there were such
+ * a way, there's no guarantee that the ifType reflects an
+ * interface type that a user would view as correct (for
+ * example, some systems report Wi-Fi interfaces as
+ * Ethernet interfaces).
+ *
+ * So we look for keywords in the vendor's interface
+ * description.
+ */
+ if (description && (strstr(description, "generic dialup") != NULL ||
+ strstr(description, "PPP/SLIP") != NULL)) {
+ if_info->type = IF_DIALUP;
+ } else if (description && (strstr(description, "Wireless") != NULL ||
+ strstr(description,"802.11") != NULL)) {
+ if_info->type = IF_WIRELESS;
+ } else if (description && strstr(description, "AirPcap") != NULL ||
+ strstr(name, "airpcap") != NULL) {
+ if_info->type = IF_AIRPCAP;
+ } else if (description && strstr(description, "Bluetooth") != NULL ) {
+ if_info->type = IF_BLUETOOTH;
+ } else if (description && strstr(description, "VMware") != NULL) {
+ /*
+ * Bridge, NAT, or host-only interface on a VMware host.
+ *
+ * XXX - what about guest interfaces?
+ */
+ if_info->type = IF_VIRTUAL;
+ }
+
+ /*
+ * On Windows, the "description" is a vendor description,
+ * and the friendly name isn't returned by WinPcap.
+ * Fetch it ourselves.
+ */
+
+ /*
+ * Skip over the "\Device\NPF_" prefix in the device name,
+ * if present.
+ */
+ if (strncmp("\\Device\\NPF_", name, 12) == 0)
+ guid_text = name + 12;
+ else
+ guid_text = name;
+
+ /* Now try to parse what remains as a GUID. */
+ if (parse_as_guid(guid_text, &guid)) {
+ /*
+ * Success. Try to get a friendly name using the GUID.
+ * As this is a regular interface, the description is a
+ * vendor description.
+ */
+ if_info->friendly_name = get_interface_friendly_name_from_device_guid(&guid);
+ if_info->vendor_description = g_strdup(description);
+ } else {
+ /*
+ * This is probably not a regular interface; we only
+ * support NT 5 (W2K) and later, so all regular interfaces
+ * should have GUIDs at the end of the name. Therefore,
+ * the description, if supplied, is a friendly name
+ * provided by WinPcap, and there is no vendor
+ * description.
+ */
+ if_info->friendly_name = g_strdup(description);
+ if_info->vendor_description = NULL;
+ }
+#else
+ /*
+ * On UN*X, if there is a description, it's a friendly
+ * name, and there is no vendor description.
+ *
+ * Try the platform's way of getting a friendly name and
+ * interface type first.
+ *
+ * If that fails, then, for a loopback interface, give it the
+ * friendly name "Loopback" and, for VMware interfaces,
+ * give them the type IF_VIRTUAL.
+ */
+ add_unix_interface_ifinfo(if_info, name, description);
+ if (if_info->type == IF_WIRED) {
+ /*
+ * This is the default interface type.
+ *
+ * Bridge, NAT, or host-only interfaces on VMWare hosts
+ * have the name vmnet[0-9]+. Guests might use a native
+ * (LANCE or E1000) driver or the vmxnet driver. Check
+ * the name.
+ */
+ if (g_ascii_strncasecmp(name, "vmnet", 5) == 0)
+ if_info->type = IF_VIRTUAL;
+ else if (g_ascii_strncasecmp(name, "vmxnet", 6) == 0)
+ if_info->type = IF_VIRTUAL;
+ }
+ if (if_info->friendly_name == NULL) {
+ /*
+ * We couldn't get interface information using platform-
+ * dependent calls.
+ *
+ * If this is a loopback interface, give it a
+ * "friendly name" of "Loopback".
+ */
+ if (loopback)
+ if_info->friendly_name = g_strdup("Loopback");
+ }
+ if_info->vendor_description = NULL;
+#endif
+ if_info->loopback = loopback;
+ if_info->addrs = NULL;
+ return if_info;
+}
+
+void
+if_info_add_address(if_info_t *if_info, struct sockaddr *addr)
+{
+ if_addr_t *if_addr;
+ struct sockaddr_in *ai;
+#ifdef INET6
+ struct sockaddr_in6 *ai6;
+#endif
+
+ switch (addr->sa_family) {
+
+ case AF_INET:
+ ai = (struct sockaddr_in *)(void *)addr;
+ if_addr = (if_addr_t *)g_malloc(sizeof(*if_addr));
+ if_addr->ifat_type = IF_AT_IPv4;
+ if_addr->addr.ip4_addr =
+ *((guint32 *)&(ai->sin_addr.s_addr));
+ if_info->addrs = g_slist_append(if_info->addrs, if_addr);
+ break;
+
+#ifdef INET6
+ case AF_INET6:
+ ai6 = (struct sockaddr_in6 *)(void *)addr;
+ if_addr = (if_addr_t *)g_malloc(sizeof(*if_addr));
+ if_addr->ifat_type = IF_AT_IPv6;
+ memcpy((void *)&if_addr->addr.ip6_addr,
+ (void *)&ai6->sin6_addr.s6_addr,
+ sizeof if_addr->addr.ip6_addr);
+ if_info->addrs = g_slist_append(if_info->addrs, if_addr);
+ break;
+#endif
+ }
+}
+
+#ifdef HAVE_PCAP_FINDALLDEVS
+/*
+ * Get all IP address information for the given interface.
+ */
+static void
+if_info_ip(if_info_t *if_info, pcap_if_t *d)
+{
+ pcap_addr_t *a;
+
+ /* All addresses */
+ for (a = d->addresses; a != NULL; a = a->next) {
+ if (a->addr != NULL)
+ if_info_add_address(if_info, a->addr);
+ }
+}
+
+#ifdef HAVE_PCAP_REMOTE
+GList *
+get_interface_list_findalldevs_ex(const char *source,
+ struct pcap_rmtauth *auth,
+ int *err, char **err_str)
+{
+ GList *il = NULL;
+ pcap_if_t *alldevs, *dev;
+ if_info_t *if_info;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ if (pcap_findalldevs_ex((char *)source, auth, &alldevs, errbuf) == -1) {
+ *err = CANT_GET_INTERFACE_LIST;
+ if (err_str != NULL)
+ *err_str = cant_get_if_list_error_message(errbuf);
+ return NULL;
+ }
+
+ if (alldevs == NULL) {
+ /*
+ * No interfaces found.
+ */
+ *err = NO_INTERFACES_FOUND;
+ if (err_str != NULL)
+ *err_str = NULL;
+ return NULL;
+ }
+
+ for (dev = alldevs; dev != NULL; dev = dev->next) {
+ if_info = if_info_new(dev->name, dev->description,
+ (dev->flags & PCAP_IF_LOOPBACK) ? TRUE : FALSE);
+ il = g_list_append(il, if_info);
+ if_info_ip(if_info, dev);
+ }
+ pcap_freealldevs(alldevs);
+
+ return il;
+}
+#endif
+
+GList *
+get_interface_list_findalldevs(int *err, char **err_str)
+{
+ GList *il = NULL;
+ pcap_if_t *alldevs, *dev;
+ if_info_t *if_info;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ if (pcap_findalldevs(&alldevs, errbuf) == -1) {
+ *err = CANT_GET_INTERFACE_LIST;
+ if (err_str != NULL)
+ *err_str = cant_get_if_list_error_message(errbuf);
+ return NULL;
+ }
+
+ if (alldevs == NULL) {
+ /*
+ * No interfaces found.
+ */
+ *err = NO_INTERFACES_FOUND;
+ if (err_str != NULL)
+ *err_str = NULL;
+ return NULL;
+ }
+
+ for (dev = alldevs; dev != NULL; dev = dev->next) {
+ if_info = if_info_new(dev->name, dev->description,
+ (dev->flags & PCAP_IF_LOOPBACK) ? TRUE : FALSE);
+ il = g_list_append(il, if_info);
+ if_info_ip(if_info, dev);
+ }
+ pcap_freealldevs(alldevs);
+
+ return il;
+}
+#endif /* HAVE_PCAP_FINDALLDEVS */
+
+static void
+free_if_info_addr_cb(gpointer addr, gpointer user_data _U_)
+{
+ g_free(addr);
+}
+
+static void
+free_if_cb(gpointer data, gpointer user_data _U_)
+{
+ if_info_t *if_info = (if_info_t *)data;
+
+ g_free(if_info->name);
+ g_free(if_info->friendly_name);
+ g_free(if_info->vendor_description);
+
+ g_slist_foreach(if_info->addrs, free_if_info_addr_cb, NULL);
+ g_slist_free(if_info->addrs);
+ g_free(if_info);
+}
+
+void
+free_interface_list(GList *if_list)
+{
+ g_list_foreach(if_list, free_if_cb, NULL);
+ g_list_free(if_list);
+}
+
+#if !defined(HAVE_PCAP_DATALINK_NAME_TO_VAL) || !defined(HAVE_PCAP_DATALINK_VAL_TO_NAME) || !defined(HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION)
+struct dlt_choice {
+ const char *name;
+ const char *description;
+ int dlt;
+};
+
+#define DLT_CHOICE(code, description) { #code, description, code }
+#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 }
+
+static struct dlt_choice dlt_choices[] = {
+ DLT_CHOICE(DLT_NULL, "BSD loopback"),
+ DLT_CHOICE(DLT_EN10MB, "Ethernet"),
+ DLT_CHOICE(DLT_IEEE802, "Token ring"),
+ DLT_CHOICE(DLT_ARCNET, "ARCNET"),
+ DLT_CHOICE(DLT_SLIP, "SLIP"),
+ DLT_CHOICE(DLT_PPP, "PPP"),
+ DLT_CHOICE(DLT_FDDI, "FDDI"),
+ DLT_CHOICE(DLT_ATM_RFC1483, "RFC 1483 IP-over-ATM"),
+ DLT_CHOICE(DLT_RAW, "Raw IP"),
+ DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS SLIP"),
+ DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS PPP"),
+ DLT_CHOICE(DLT_ATM_CLIP, "Linux Classical IP-over-ATM"),
+ DLT_CHOICE(DLT_PPP_SERIAL, "PPP over serial"),
+ DLT_CHOICE(DLT_PPP_ETHER, "PPPoE"),
+ DLT_CHOICE(DLT_C_HDLC, "Cisco HDLC"),
+ DLT_CHOICE(DLT_IEEE802_11, "802.11"),
+ DLT_CHOICE(DLT_FRELAY, "Frame Relay"),
+ DLT_CHOICE(DLT_LOOP, "OpenBSD loopback"),
+ DLT_CHOICE(DLT_ENC, "OpenBSD encapsulated IP"),
+ DLT_CHOICE(DLT_LINUX_SLL, "Linux cooked"),
+ DLT_CHOICE(DLT_LTALK, "Localtalk"),
+ DLT_CHOICE(DLT_PFLOG, "OpenBSD pflog file"),
+ DLT_CHOICE(DLT_PRISM_HEADER, "802.11 plus Prism header"),
+ DLT_CHOICE(DLT_IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"),
+ DLT_CHOICE(DLT_SUNATM, "Sun raw ATM"),
+ DLT_CHOICE(DLT_IEEE802_11_RADIO, "802.11 plus BSD radio information header"),
+ DLT_CHOICE(DLT_APPLE_IP_OVER_IEEE1394, "Apple IP-over-IEEE 1394"),
+ DLT_CHOICE(DLT_ARCNET_LINUX, "Linux ARCNET"),
+ DLT_CHOICE(DLT_LINUX_IRDA, "Linux IrDA"),
+ DLT_CHOICE(DLT_IEEE802_11_RADIO_AVS, "802.11 plus AVS radio information header"),
+ DLT_CHOICE_SENTINEL
+};
+
+#if !defined(HAVE_PCAP_DATALINK_NAME_TO_VAL)
+static int
+pcap_datalink_name_to_val(const char *name)
+{
+ int i;
+
+ for (i = 0; dlt_choices[i].name != NULL; i++) {
+ if (g_ascii_strcasecmp(dlt_choices[i].name + sizeof("DLT_") - 1,
+ name) == 0)
+ return (dlt_choices[i].dlt);
+ }
+ return (-1);
+}
+#endif /* defined(HAVE_PCAP_DATALINK_NAME_TO_VAL) */
+
+#if !defined(HAVE_PCAP_DATALINK_VAL_TO_NAME)
+static const char *
+pcap_datalink_val_to_name(int dlt)
+{
+ int i;
+
+ for (i = 0; dlt_choices[i].name != NULL; i++) {
+ if (dlt_choices[i].dlt == dlt)
+ return (dlt_choices[i].name + sizeof("DLT_") - 1);
+ }
+ return (NULL);
+}
+#endif /* defined(HAVE_PCAP_DATALINK_VAL_TO_NAME) */
+
+#if !defined(HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION)
+const char *
+pcap_datalink_val_to_description(int dlt)
+{
+ int i;
+
+ for (i = 0; dlt_choices[i].name != NULL; i++) {
+ if (dlt_choices[i].dlt == dlt)
+ return (dlt_choices[i].description);
+ }
+ return (NULL);
+}
+#endif /* defined(HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION) */
+
+#endif /* !defined(HAVE_PCAP_DATALINK_VAL_TO_NAME) || !defined(HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION) */
+
+static void
+free_linktype_cb(gpointer data, gpointer user_data _U_)
+{
+ data_link_info_t *linktype_info = (data_link_info_t *)data;
+
+ g_free(linktype_info->name);
+ g_free(linktype_info->description);
+}
+
+void
+free_if_capabilities(if_capabilities_t *caps)
+{
+ g_list_foreach(caps->data_link_types, free_linktype_cb, NULL);
+ g_list_free(caps->data_link_types);
+ g_free(caps);
+}
+
+const char *
+linktype_val_to_name(int dlt)
+{
+ return pcap_datalink_val_to_name(dlt);
+}
+
+int linktype_name_to_val(const char *linktype)
+{
+ return pcap_datalink_name_to_val(linktype);
+}
+
+#endif /* HAVE_LIBPCAP */
diff --git a/caputils/capture-pcap-util.h b/caputils/capture-pcap-util.h
new file mode 100644
index 0000000000..617bcc82e5
--- /dev/null
+++ b/caputils/capture-pcap-util.h
@@ -0,0 +1,74 @@
+/* capture-pcap-util.h
+ * Utility definitions for packet capture
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __CAPTURE_PCAP_UTIL_H__
+#define __CAPTURE_PCAP_UTIL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef HAVE_LIBPCAP
+
+#include <pcap.h>
+
+/*
+ * A snapshot length of 0 is useless - and libpcap/WinPcap don't guarantee
+ * that a snapshot length of 0 will work, and, on some platforms, it won't
+ * (with BPF, for example, the kernel is told the snapshot length via the
+ * return value of the BPF program, and a return value of 0 means "drop
+ * the packet"), so the minimum packet size is 1 byte.
+ */
+#define MIN_PACKET_SIZE 1 /* minimum amount of packet data we can read */
+
+GList *get_interface_list(int *err, char **err_str);
+#ifdef HAVE_PCAP_REMOTE
+GList *get_remote_interface_list(const char *hostname, const char *port,
+ int auth_type, const char *username,
+ const char *passwd, int *err, char **err_str);
+#endif
+
+const char *linktype_val_to_name(int dlt);
+int linktype_name_to_val(const char *linktype);
+
+#endif /* HAVE_LIBPCAP */
+
+/*
+ * Get the versions of capture libraries with which we were compiled,
+ * and append them to a GString.
+ */
+extern void get_compiled_caplibs_version(GString *str);
+
+/*
+ * Append to a GString an indication of the version of capture libraries
+ * with which we're running, or an indication that we're not running
+ * with capture libraries, if we were compiled with WinPcap but
+ * WinPcap wasn't loaded, or nothing, if we weren't compiled with
+ * libpcap/WinPcap.
+ */
+extern void get_runtime_caplibs_version(GString *str);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CAPTURE_PCAP_UTIL_H__ */
diff --git a/caputils/capture-wpcap.c b/caputils/capture-wpcap.c
new file mode 100644
index 0000000000..f4f9d61c25
--- /dev/null
+++ b/caputils/capture-wpcap.c
@@ -0,0 +1,990 @@
+/* capture-wpcap.c
+ * WinPcap-specific interfaces for capturing. We load WinPcap at run
+ * time, so that we only need one Wireshark binary and one TShark binary
+ * for Windows, regardless of whether WinPcap is installed or not.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <glib.h>
+#include <gmodule.h>
+
+#include <epan/strutil.h>
+
+#include "caputils/capture_ifinfo.h"
+#include "caputils/capture-pcap-util.h"
+#include "caputils/capture-pcap-util-int.h"
+#include "caputils/capture-wpcap.h"
+
+#include <wsutil/file_util.h>
+
+/* XXX - yes, I know, I should move cppmagic.h to a generic location. */
+#include "tools/lemon/cppmagic.h"
+
+#define MAX_WIN_IF_NAME_LEN 511
+
+
+gboolean has_wpcap = FALSE;
+
+#ifdef HAVE_LIBPCAP
+
+/*
+ * XXX - should we require at least WinPcap 3.1 both for building an
+ * for using Wireshark?
+ */
+
+static char* (*p_pcap_lookupdev) (char *);
+static void (*p_pcap_close) (pcap_t *);
+static int (*p_pcap_stats) (pcap_t *, struct pcap_stat *);
+static int (*p_pcap_dispatch) (pcap_t *, int, pcap_handler, guchar *);
+static int (*p_pcap_snapshot) (pcap_t *);
+static int (*p_pcap_datalink) (pcap_t *);
+static int (*p_pcap_setfilter) (pcap_t *, struct bpf_program *);
+static char* (*p_pcap_geterr) (pcap_t *);
+static int (*p_pcap_compile) (pcap_t *, struct bpf_program *, const char *, int,
+ bpf_u_int32);
+static int (*p_pcap_compile_nopcap) (int, int, struct bpf_program *, const char *, int,
+ bpf_u_int32);
+static int (*p_pcap_lookupnet) (const char *, bpf_u_int32 *, bpf_u_int32 *,
+ char *);
+static pcap_t* (*p_pcap_open_live) (const char *, int, int, int, char *);
+static int (*p_pcap_loop) (pcap_t *, int, pcap_handler, guchar *);
+#ifdef HAVE_PCAP_OPEN_DEAD
+static pcap_t* (*p_pcap_open_dead) (int, int);
+#endif
+static void (*p_pcap_freecode) (struct bpf_program *);
+#ifdef HAVE_PCAP_FINDALLDEVS
+static int (*p_pcap_findalldevs) (pcap_if_t **, char *);
+static void (*p_pcap_freealldevs) (pcap_if_t *);
+#endif
+#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
+static int (*p_pcap_datalink_name_to_val) (const char *);
+#endif
+#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
+static const char *(*p_pcap_datalink_val_to_name) (int);
+#endif
+#ifdef HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION
+static const char *(*p_pcap_datalink_val_to_description) (int);
+#endif
+#ifdef HAVE_PCAP_BREAKLOOP
+static void (*p_pcap_breakloop) (pcap_t *);
+#endif
+static const char *(*p_pcap_lib_version) (void);
+static int (*p_pcap_setbuff) (pcap_t *, int dim);
+static int (*p_pcap_next_ex) (pcap_t *, struct pcap_pkthdr **pkt_header, const u_char **pkt_data);
+#ifdef HAVE_PCAP_REMOTE
+static pcap_t* (*p_pcap_open) (const char *, int, int, int,
+ struct pcap_rmtauth *, char *);
+static int (*p_pcap_findalldevs_ex) (char *, struct pcap_rmtauth *,
+ pcap_if_t **, char *);
+static int (*p_pcap_createsrcstr) (char *, int, const char *, const char *,
+ const char *, char *);
+#endif
+#ifdef HAVE_PCAP_SETSAMPLING
+static struct pcap_samp* (*p_pcap_setsampling)(pcap_t *);
+#endif
+
+#ifdef HAVE_PCAP_LIST_DATALINKS
+static int (*p_pcap_list_datalinks)(pcap_t *, int **);
+#endif
+
+#ifdef HAVE_PCAP_SET_DATALINK
+static int (*p_pcap_set_datalink)(pcap_t *, int);
+#endif
+
+#ifdef HAVE_PCAP_FREE_DATALINKS
+static int (*p_pcap_free_datalinks)(int *);
+#endif
+
+#ifdef HAVE_BPF_IMAGE
+static char *(*p_bpf_image) (const struct bpf_insn *, int);
+#endif
+
+typedef struct {
+ const char *name;
+ gpointer *ptr;
+ gboolean optional;
+} symbol_table_t;
+
+#define SYM(x, y) { G_STRINGIFY(x) , (gpointer) &CONCAT(p_,x), y }
+
+void
+load_wpcap(void)
+{
+
+ /* These are the symbols I need or want from Wpcap */
+ static const symbol_table_t symbols[] = {
+ SYM(pcap_lookupdev, FALSE),
+ SYM(pcap_close, FALSE),
+ SYM(pcap_stats, FALSE),
+ SYM(pcap_dispatch, FALSE),
+ SYM(pcap_snapshot, FALSE),
+ SYM(pcap_datalink, FALSE),
+ SYM(pcap_setfilter, FALSE),
+ SYM(pcap_geterr, FALSE),
+ SYM(pcap_compile, FALSE),
+ SYM(pcap_compile_nopcap, FALSE),
+ SYM(pcap_lookupnet, FALSE),
+#ifdef HAVE_PCAP_REMOTE
+ SYM(pcap_open, FALSE),
+ SYM(pcap_findalldevs_ex, FALSE),
+ SYM(pcap_createsrcstr, FALSE),
+#endif
+ SYM(pcap_open_live, FALSE),
+#ifdef HAVE_PCAP_OPEN_DEAD
+ SYM(pcap_open_dead, FALSE),
+#endif
+#ifdef HAVE_PCAP_SETSAMPLING
+ SYM(pcap_setsampling, TRUE),
+#endif
+ SYM(pcap_loop, FALSE),
+ SYM(pcap_freecode, TRUE),
+#ifdef HAVE_PCAP_FINDALLDEVS
+ SYM(pcap_findalldevs, TRUE),
+ SYM(pcap_freealldevs, TRUE),
+#endif
+#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
+ SYM(pcap_datalink_name_to_val, TRUE),
+#endif
+#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
+ SYM(pcap_datalink_val_to_name, TRUE),
+#endif
+#ifdef HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION
+ SYM(pcap_datalink_val_to_description, TRUE),
+#endif
+#ifdef HAVE_PCAP_BREAKLOOP
+ /*
+ * We don't try to work around the lack of this at
+ * run time; it's present in WinPcap 3.1, which is
+ * the version we build with and ship with.
+ */
+ SYM(pcap_breakloop, FALSE),
+#endif
+ SYM(pcap_lib_version, TRUE),
+ SYM(pcap_setbuff, TRUE),
+ SYM(pcap_next_ex, TRUE),
+#ifdef HAVE_PCAP_LIST_DATALINKS
+ SYM(pcap_list_datalinks, FALSE),
+#endif
+#ifdef HAVE_PCAP_SET_DATALINK
+ SYM(pcap_set_datalink, FALSE),
+#endif
+#ifdef HAVE_PCAP_FREE_DATALINKS
+ SYM(pcap_free_datalinks, TRUE),
+#endif
+#ifdef HAVE_BPF_IMAGE
+ SYM(bpf_image, FALSE),
+#endif
+ { NULL, NULL, FALSE }
+ };
+
+ GModule *wh; /* wpcap handle */
+ const symbol_table_t *sym;
+
+ wh = ws_module_open("wpcap.dll", 0);
+
+ if (!wh) {
+ return;
+ }
+
+ sym = symbols;
+ while (sym->name) {
+ if (!g_module_symbol(wh, sym->name, sym->ptr)) {
+ if (sym->optional) {
+ /*
+ * We don't care if it's missing; we just
+ * don't use it.
+ */
+ *sym->ptr = NULL;
+ } else {
+ /*
+ * We require this symbol.
+ */
+ return;
+ }
+ }
+ sym++;
+ }
+
+
+ has_wpcap = TRUE;
+}
+
+/*
+ * The official list of WinPcap mirrors is at
+ * http://www.winpcap.org/misc/mirrors.htm
+ */
+char *
+cant_load_winpcap_err(const char *app_name)
+{
+ return g_strdup_printf(
+"Unable to load WinPcap (wpcap.dll); %s will not be able to capture\n"
+"packets.\n"
+"\n"
+"In order to capture packets, WinPcap must be installed; see\n"
+"\n"
+" http://www.winpcap.org/\n"
+"\n"
+"or the mirror at\n"
+"\n"
+" http://www.mirrors.wiretapped.net/security/packet-capture/winpcap/\n"
+"\n"
+"or the mirror at\n"
+"\n"
+" http://winpcap.cs.pu.edu.tw/\n"
+"\n"
+"for a downloadable version of WinPcap and for instructions on how to install\n"
+"WinPcap.",
+ app_name);
+}
+
+char*
+pcap_lookupdev (char *a)
+{
+ if (!has_wpcap) {
+ return NULL;
+ }
+ return p_pcap_lookupdev(a);
+}
+
+void
+pcap_close(pcap_t *a)
+{
+ g_assert(has_wpcap);
+ p_pcap_close(a);
+}
+
+int
+pcap_stats(pcap_t *a, struct pcap_stat *b)
+{
+ g_assert(has_wpcap);
+ return p_pcap_stats(a, b);
+}
+
+int
+pcap_dispatch(pcap_t *a, int b, pcap_handler c, guchar *d)
+{
+ g_assert(has_wpcap);
+ return p_pcap_dispatch(a, b, c, d);
+}
+
+int
+pcap_snapshot(pcap_t *a)
+{
+ g_assert(has_wpcap);
+ return p_pcap_snapshot(a);
+}
+
+int
+pcap_datalink(pcap_t *a)
+{
+ g_assert(has_wpcap);
+ return p_pcap_datalink(a);
+}
+
+#ifdef HAVE_PCAP_SET_DATALINK
+int
+pcap_set_datalink(pcap_t *p, int dlt)
+{
+ g_assert(has_wpcap);
+ return p_pcap_set_datalink(p, dlt);
+}
+#endif
+
+int
+pcap_setfilter(pcap_t *a, struct bpf_program *b)
+{
+ g_assert(has_wpcap);
+ return p_pcap_setfilter(a, b);
+}
+
+char*
+pcap_geterr(pcap_t *a)
+{
+ g_assert(has_wpcap);
+ return p_pcap_geterr(a);
+}
+
+int
+pcap_compile(pcap_t *a, struct bpf_program *b, const char *c, int d,
+ bpf_u_int32 e)
+{
+ g_assert(has_wpcap);
+ return p_pcap_compile(a, b, c, d, e);
+}
+
+int
+pcap_compile_nopcap(int a, int b, struct bpf_program *c, const char *d, int e,
+ bpf_u_int32 f)
+{
+ g_assert(has_wpcap);
+ return p_pcap_compile_nopcap(a, b, c, d, e, f);
+}
+
+int
+pcap_lookupnet(const char *a, bpf_u_int32 *b, bpf_u_int32 *c, char *d)
+{
+ g_assert(has_wpcap);
+ return p_pcap_lookupnet(a, b, c, d);
+}
+
+pcap_t*
+pcap_open_live(const char *a, int b, int c, int d, char *e)
+{
+ if (!has_wpcap) {
+ g_snprintf(e, PCAP_ERRBUF_SIZE,
+ "unable to load WinPcap (wpcap.dll); can't open %s to capture",
+ a);
+ return NULL;
+ }
+ return p_pcap_open_live(a, b, c, d, e);
+}
+
+#ifdef HAVE_PCAP_OPEN_DEAD
+pcap_t*
+pcap_open_dead(int a, int b)
+{
+ if (!has_wpcap) {
+ return NULL;
+ }
+ return p_pcap_open_dead(a, b);
+}
+#endif
+
+#ifdef HAVE_BPF_IMAGE
+char *
+bpf_image(const struct bpf_insn *a, int b)
+{
+ if (!has_wpcap) {
+ return NULL;
+ }
+ return p_bpf_image(a, b);
+}
+#endif
+
+#ifdef HAVE_PCAP_REMOTE
+pcap_t*
+pcap_open(const char *a, int b, int c, int d, struct pcap_rmtauth *e, char *f)
+{
+ if (!has_wpcap) {
+ g_snprintf(f, PCAP_ERRBUF_SIZE,
+ "unable to load WinPcap (wpcap.dll); can't open %s to capture",
+ a);
+ return NULL;
+ }
+ return p_pcap_open(a, b, c, d, e, f);
+}
+
+int
+pcap_findalldevs_ex(char *a, struct pcap_rmtauth *b, pcap_if_t **c, char *d)
+{
+ g_assert(has_wpcap);
+ return p_pcap_findalldevs_ex(a, b, c, d);
+}
+
+int
+pcap_createsrcstr(char *a, int b, const char *c, const char *d, const char *e,
+ char *f)
+{
+ g_assert(has_wpcap);
+ return p_pcap_createsrcstr(a, b, c, d, e, f);
+}
+#endif
+
+#ifdef HAVE_PCAP_SETSAMPLING
+struct pcap_samp *
+pcap_setsampling(pcap_t *a)
+{
+ g_assert(has_wpcap);
+ if (p_pcap_setsampling != NULL) {
+ return p_pcap_setsampling(a);
+ }
+ return NULL;
+}
+#endif
+
+int
+pcap_loop(pcap_t *a, int b, pcap_handler c, guchar *d)
+{
+ g_assert(has_wpcap);
+ return p_pcap_loop(a, b, c, d);
+}
+
+void
+pcap_freecode(struct bpf_program *a)
+{
+ g_assert(has_wpcap);
+ if(p_pcap_freecode) {
+ p_pcap_freecode(a);
+ }
+}
+
+#ifdef HAVE_PCAP_FINDALLDEVS
+int
+pcap_findalldevs(pcap_if_t **a, char *b)
+{
+ g_assert(has_wpcap && p_pcap_findalldevs != NULL);
+ return p_pcap_findalldevs(a, b);
+}
+
+void
+pcap_freealldevs(pcap_if_t *a)
+{
+ g_assert(has_wpcap && p_pcap_freealldevs != NULL);
+ p_pcap_freealldevs(a);
+}
+#endif
+
+#if defined(HAVE_PCAP_DATALINK_NAME_TO_VAL) || defined(HAVE_PCAP_DATALINK_VAL_TO_NAME) || defined(HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION)
+/*
+ * Table of DLT_ types, names, and descriptions, for use if the version
+ * of WinPcap we have installed lacks "pcap_datalink_name_to_val()"
+ * or "pcap_datalink_val_to_name()".
+ */
+struct dlt_choice {
+ const char *name;
+ const char *description;
+ int dlt;
+};
+
+#define DLT_CHOICE(code, description) { #code, description, code }
+#define DLT_CHOICE_SENTINEL { NULL, NULL, 0 }
+
+static struct dlt_choice dlt_choices[] = {
+ DLT_CHOICE(DLT_NULL, "BSD loopback"),
+ DLT_CHOICE(DLT_EN10MB, "Ethernet"),
+ DLT_CHOICE(DLT_IEEE802, "Token ring"),
+ DLT_CHOICE(DLT_ARCNET, "ARCNET"),
+ DLT_CHOICE(DLT_SLIP, "SLIP"),
+ DLT_CHOICE(DLT_PPP, "PPP"),
+ DLT_CHOICE(DLT_FDDI, "FDDI"),
+ DLT_CHOICE(DLT_ATM_RFC1483, "RFC 1483 IP-over-ATM"),
+ DLT_CHOICE(DLT_RAW, "Raw IP"),
+#ifdef DLT_SLIP_BSDOS
+ DLT_CHOICE(DLT_SLIP_BSDOS, "BSD/OS SLIP"),
+#endif
+#ifdef DLT_PPP_BSDOS
+ DLT_CHOICE(DLT_PPP_BSDOS, "BSD/OS PPP"),
+#endif
+#ifdef DLT_ATM_CLIP
+ DLT_CHOICE(DLT_ATM_CLIP, "Linux Classical IP-over-ATM"),
+#endif
+#ifdef DLT_PPP_SERIAL
+ DLT_CHOICE(DLT_PPP_SERIAL, "PPP over serial"),
+#endif
+#ifdef DLT_PPP_ETHER
+ DLT_CHOICE(DLT_PPP_ETHER, "PPPoE"),
+#endif
+#ifdef DLT_C_HDLC
+ DLT_CHOICE(DLT_C_HDLC, "Cisco HDLC"),
+#endif
+#ifdef DLT_IEEE802_11
+ DLT_CHOICE(DLT_IEEE802_11, "802.11"),
+#endif
+#ifdef DLT_FRELAY
+ DLT_CHOICE(DLT_FRELAY, "Frame Relay"),
+#endif
+#ifdef DLT_LOOP
+ DLT_CHOICE(DLT_LOOP, "OpenBSD loopback"),
+#endif
+#ifdef DLT_ENC
+ DLT_CHOICE(DLT_ENC, "OpenBSD encapsulated IP"),
+#endif
+#ifdef DLT_LINUX_SLL
+ DLT_CHOICE(DLT_LINUX_SLL, "Linux cooked"),
+#endif
+#ifdef DLT_LTALK
+ DLT_CHOICE(DLT_LTALK, "Localtalk"),
+#endif
+#ifdef DLT_PFLOG
+ DLT_CHOICE(DLT_PFLOG, "OpenBSD pflog file"),
+#endif
+#ifdef DLT_PRISM_HEADER
+ DLT_CHOICE(DLT_PRISM_HEADER, "802.11 plus Prism header"),
+#endif
+#ifdef DLT_IP_OVER_FC
+ DLT_CHOICE(DLT_IP_OVER_FC, "RFC 2625 IP-over-Fibre Channel"),
+#endif
+#ifdef DLT_SUNATM
+ DLT_CHOICE(DLT_SUNATM, "Sun raw ATM"),
+#endif
+#ifdef DLT_IEEE802_11_RADIO
+ DLT_CHOICE(DLT_IEEE802_11_RADIO, "802.11 plus radio information header"),
+#endif
+#ifdef DLT_ARCNET_LINUX
+ DLT_CHOICE(DLT_ARCNET_LINUX, "Linux ARCNET"),
+#endif
+#ifdef DLT_LINUX_IRDA
+ DLT_CHOICE(DLT_LINUX_IRDA, "Linux IrDA"),
+#endif
+#ifdef DLT_LINUX_LAPD
+ DLT_CHOICE(DLT_LINUX_LAPD, "Linux vISDN LAPD"),
+#endif
+#ifdef DLT_LANE8023
+ DLT_CHOICE(DLT_LANE8023, "Linux 802.3 LANE"),
+#endif
+#ifdef DLT_CIP
+ DLT_CHOICE(DLT_CIP, "Linux Classical IP-over-ATM"),
+#endif
+#ifdef DLT_HDLC
+ DLT_CHOICE(DLT_HDLC, "Cisco HDLC"),
+#endif
+#ifdef DLT_PPI
+ DLT_CHOICE(DLT_PPI, "Per-Packet Information"),
+#endif
+ DLT_CHOICE_SENTINEL
+};
+#endif /* defined(HAVE_PCAP_DATALINK_NAME_TO_VAL) || defined(HAVE_PCAP_DATALINK_VAL_TO_NAME) || defined(HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION */
+
+#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
+int
+pcap_datalink_name_to_val(const char *name)
+{
+ int i;
+
+ g_assert(has_wpcap);
+
+ if (p_pcap_datalink_name_to_val != NULL)
+ return p_pcap_datalink_name_to_val(name);
+ else {
+ /*
+ * We don't have it in WinPcap; do it ourselves.
+ */
+ for (i = 0; dlt_choices[i].name != NULL; i++) {
+ if (g_ascii_strcasecmp(dlt_choices[i].name + sizeof("DLT_") - 1,
+ name) == 0)
+ return dlt_choices[i].dlt;
+ }
+ return -1;
+ }
+}
+#endif
+
+#ifdef HAVE_PCAP_LIST_DATALINKS
+int
+pcap_list_datalinks(pcap_t *p, int **ddlt)
+{
+ g_assert(has_wpcap);
+ return p_pcap_list_datalinks(p, ddlt);
+}
+#endif
+
+#ifdef HAVE_PCAP_FREE_DATALINKS
+void
+pcap_free_datalinks(int *ddlt)
+{
+ g_assert(has_wpcap);
+
+ /*
+ * If we don't have pcap_free_datalinks() in WinPcap,
+ * we don't free the memory - we can't use free(), as
+ * we might not have been built with the same version
+ * of the C runtime library as WinPcap was, and, if we're
+ * not, free() isn't guaranteed to work on something
+ * allocated by WinPcap.
+ */
+ if (p_pcap_free_datalinks != NULL)
+ p_pcap_free_datalinks(ddlt);
+}
+#endif
+
+#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
+const char *
+pcap_datalink_val_to_name(int dlt)
+{
+ int i;
+
+ g_assert(has_wpcap);
+
+ if (p_pcap_datalink_val_to_name != NULL)
+ return p_pcap_datalink_val_to_name(dlt);
+ else {
+ /*
+ * We don't have it in WinPcap; do it ourselves.
+ */
+ for (i = 0; dlt_choices[i].name != NULL; i++) {
+ if (dlt_choices[i].dlt == dlt)
+ return dlt_choices[i].name + sizeof("DLT_") - 1;
+ }
+ return NULL;
+ }
+}
+#endif
+
+#ifdef HAVE_PCAP_DATALINK_VAL_TO_DESCRIPTION
+const char *
+pcap_datalink_val_to_description(int dlt)
+{
+ int i;
+
+ g_assert(has_wpcap);
+
+ if (p_pcap_datalink_val_to_description != NULL)
+ return p_pcap_datalink_val_to_description(dlt);
+ else {
+ /*
+ * We don't have it in WinPcap; do it ourselves.
+ */
+ for (i = 0; dlt_choices[i].name != NULL; i++) {
+ if (dlt_choices[i].dlt == dlt)
+ return (dlt_choices[i].description);
+ }
+ return NULL;
+ }
+}
+#endif
+
+#ifdef HAVE_PCAP_BREAKLOOP
+void pcap_breakloop(pcap_t *a)
+{
+ p_pcap_breakloop(a);
+}
+#endif
+
+/* setbuff is win32 specific! */
+int pcap_setbuff(pcap_t *a, int b)
+{
+ g_assert(has_wpcap);
+ return p_pcap_setbuff(a, b);
+}
+
+/* pcap_next_ex is available since libpcap 0.8 / WinPcap 3.0! */
+/* (if you get a declaration warning here, try to update to at least WinPcap 3.1b4 develpack) */
+int pcap_next_ex (pcap_t *a, struct pcap_pkthdr **b, const u_char **c)
+{
+ g_assert(has_wpcap);
+ return p_pcap_next_ex(a, b, c);
+}
+
+#ifdef HAVE_PCAP_REMOTE
+GList *
+get_remote_interface_list(const char *hostname, const char *port,
+ int auth_type, const char *username,
+ const char *passwd, int *err, char **err_str)
+{
+ struct pcap_rmtauth auth;
+ char source[PCAP_BUF_SIZE];
+ char errbuf[PCAP_ERRBUF_SIZE];
+ GList *result;
+
+ if (pcap_createsrcstr(source, PCAP_SRC_IFREMOTE, hostname, port,
+ NULL, errbuf) == -1) {
+ *err = CANT_GET_INTERFACE_LIST;
+ if (err_str != NULL)
+ *err_str = cant_get_if_list_error_message(errbuf);
+ return NULL;
+ }
+
+ auth.type = auth_type;
+ auth.username = g_strdup(username);
+ auth.password = g_strdup(passwd);
+
+ result = get_interface_list_findalldevs_ex(source, &auth, err, err_str);
+ g_free(auth.username);
+ g_free(auth.password);
+
+ return result;
+}
+#endif
+
+/*
+ * This will use "pcap_findalldevs()" if we have it, otherwise it'll
+ * fall back on "pcap_lookupdev()".
+ */
+GList *
+get_interface_list(int *err, char **err_str)
+{
+ GList *il = NULL;
+ wchar_t *names;
+ char *win95names;
+ char ascii_name[MAX_WIN_IF_NAME_LEN + 1];
+ char ascii_desc[MAX_WIN_IF_NAME_LEN + 1];
+ int i, j;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ if (!has_wpcap) {
+ /*
+ * We don't have WinPcap, so we can't get a list of
+ * interfaces.
+ */
+ *err = DONT_HAVE_PCAP;
+ *err_str = cant_load_winpcap_err("you");
+ return NULL;
+ }
+
+#ifdef HAVE_PCAP_FINDALLDEVS
+ if (p_pcap_findalldevs != NULL)
+ return get_interface_list_findalldevs(err, err_str);
+#endif
+
+ /*
+ * In WinPcap, pcap_lookupdev is implemented by calling
+ * PacketGetAdapterNames. According to the documentation
+ * I could find:
+ *
+ * http://www.winpcap.org/docs/man/html/Packet32_8c.html#a43
+ *
+ * this means that:
+ *
+ * On Windows OT (95, 98, Me), pcap_lookupdev returns a sequence
+ * of bytes consisting of:
+ *
+ * a sequence of null-terminated ASCII strings (i.e., each
+ * one is terminated by a single 0 byte), giving the names
+ * of the interfaces;
+ *
+ * an empty ASCII string (i.e., a single 0 byte);
+ *
+ * a sequence of null-terminated ASCII strings, giving the
+ * descriptions of the interfaces;
+ *
+ * an empty ASCII string.
+ *
+ * On Windows NT (NT 4.0, W2K, WXP, W2K3, etc.), pcap_lookupdev
+ * returns a sequence of bytes consisting of:
+ *
+ * a sequence of null-terminated double-byte Unicode strings
+ * (i.e., each one consits of a sequence of double-byte
+ * characters, terminated by a double-byte 0), giving the
+ * names of the interfaces;
+ *
+ * an empty Unicode string (i.e., a double 0 byte);
+ *
+ * a sequence of null-terminated ASCII strings, giving the
+ * descriptions of the interfaces;
+ *
+ * an empty ASCII string.
+ *
+ * The Nth string in the first sequence is the name of the Nth
+ * adapter; the Nth string in the second sequence is the
+ * description of the Nth adapter.
+ */
+
+ names = (wchar_t *)pcap_lookupdev(errbuf);
+ i = 0;
+
+ if (names) {
+ char* desc = 0;
+ int desc_pos = 0;
+
+ if (names[0]<256) {
+ /*
+ * If names[0] is less than 256 it means the first
+ * byte is 0. This implies that we are using Unicode
+ * characters.
+ */
+ while (*(names+desc_pos) || *(names+desc_pos-1))
+ desc_pos++;
+ desc_pos++; /* Step over the extra '\0' */
+ desc = (char*)(names + desc_pos); /* cast *after* addition */
+
+ while (names[i] != 0) {
+ /*
+ * Copy the Unicode description to an ASCII
+ * string.
+ */
+ j = 0;
+ while (*desc != 0) {
+ if (j < MAX_WIN_IF_NAME_LEN)
+ ascii_desc[j++] = *desc;
+ desc++;
+ }
+ ascii_desc[j] = '\0';
+ desc++;
+
+ /*
+ * Copy the Unicode name to an ASCII string.
+ */
+ j = 0;
+ while (names[i] != 0) {
+ if (j < MAX_WIN_IF_NAME_LEN)
+ ascii_name[j++] = (char) names[i++];
+ }
+ ascii_name[j] = '\0';
+ i++;
+ il = g_list_append(il,
+ if_info_new(ascii_name, ascii_desc, FALSE));
+ }
+ } else {
+ /*
+ * Otherwise we are in Windows 95/98 and using ASCII
+ * (8-bit) characters.
+ */
+ win95names=(char *)names;
+ while (*(win95names+desc_pos) || *(win95names+desc_pos-1))
+ desc_pos++;
+ desc_pos++; /* Step over the extra '\0' */
+ desc = win95names + desc_pos;
+
+ while (win95names[i] != '\0') {
+ /*
+ * "&win95names[i]" points to the current
+ * interface name, and "desc" points to
+ * that interface's description.
+ */
+ il = g_list_append(il,
+ if_info_new(&win95names[i], desc, FALSE));
+
+ /*
+ * Skip to the next description.
+ */
+ while (*desc != 0)
+ desc++;
+ desc++;
+
+ /*
+ * Skip to the next name.
+ */
+ while (win95names[i] != 0)
+ i++;
+ i++;
+ }
+ }
+ }
+
+ if (il == NULL) {
+ /*
+ * No interfaces found.
+ */
+ *err = NO_INTERFACES_FOUND;
+ if (err_str != NULL)
+ *err_str = NULL;
+ }
+
+ return il;
+}
+
+/*
+ * Get an error message string for a CANT_GET_INTERFACE_LIST error from
+ * "get_interface_list()".
+ */
+gchar *
+cant_get_if_list_error_message(const char *err_str)
+{
+ /*
+ * If the error message includes "Not enough storage is available
+ * to process this command" or "The operation completed successfully",
+ * suggest that they install a WinPcap version later than 3.0.
+ */
+ if (strstr(err_str, "Not enough storage is available to process this command") != NULL ||
+ strstr(err_str, "The operation completed successfully") != NULL) {
+ return g_strdup_printf("Can't get list of interfaces: %s\n"
+"This might be a problem with WinPcap 3.0; you should try updating to\n"
+"a later version of WinPcap - see the WinPcap site at www.winpcap.org",
+ err_str);
+ }
+ return g_strdup_printf("Can't get list of interfaces: %s", err_str);
+}
+
+/*
+ * Append the version of WinPcap with which we were compiled to a GString.
+ */
+void
+get_compiled_pcap_version(GString *str)
+{
+ g_string_append(str, "with WinPcap (" G_STRINGIFY(WINPCAP_VERSION) ")");
+}
+
+/*
+ * Append the version of WinPcap with which we we're running to a GString.
+ */
+void
+get_runtime_pcap_version(GString *str)
+{
+ /*
+ * On Windows, we might have been compiled with WinPcap but
+ * might not have it loaded; indicate whether we have it or
+ * not and, if we have it and we have "pcap_lib_version()",
+ * what version we have.
+ */
+ GModule *handle; /* handle returned by ws_module_open */
+ static gchar *packetVer;
+ gchar *blankp;
+
+ if (has_wpcap) {
+ g_string_append_printf(str, "with ");
+ if (p_pcap_lib_version != NULL)
+ g_string_append_printf(str, p_pcap_lib_version());
+ else {
+ /*
+ * An alternative method of obtaining the version
+ * number, by using the PacketLibraryVersion
+ * string from packet.dll.
+ *
+ * Unfortunately, in WinPcap 3.0, it returns
+ * "3.0 alpha3", even in the final version of
+ * WinPcap 3.0, so if there's a blank in the
+ * string, we strip it and everything after
+ * it from the string, so we don't misleadingly
+ * report that 3.0 alpha3 is being used when
+ * the final version is being used.
+ */
+ if (packetVer == NULL) {
+ packetVer = "version unknown";
+ handle = ws_module_open("packet.dll", 0);
+ if (handle != NULL) {
+ if (g_module_symbol(handle,
+ "PacketLibraryVersion",
+ (gpointer*)&packetVer)) {
+ packetVer = g_strdup(packetVer);
+ blankp = strchr(packetVer, ' ');
+ if (blankp != NULL)
+ *blankp = '\0';
+ } else {
+ packetVer = "version unknown";
+ }
+ g_module_close(handle);
+ }
+ }
+ g_string_append_printf(str, "WinPcap (%s)", packetVer);
+ }
+ } else
+ g_string_append(str, "without WinPcap");
+}
+
+#else /* HAVE_LIBPCAP */
+
+void
+load_wpcap(void)
+{
+ return;
+}
+
+/*
+ * Append an indication that we were not compiled with WinPcap
+ * to a GString.
+ */
+void
+get_compiled_pcap_version(GString *str)
+{
+ g_string_append(str, "without WinPcap");
+}
+
+/*
+ * Don't append anything, as we weren't even compiled to use WinPcap.
+ */
+void
+get_runtime_pcap_version(GString *str _U_)
+{
+}
+
+#endif /* HAVE_LIBPCAP */
diff --git a/caputils/capture-wpcap.h b/caputils/capture-wpcap.h
new file mode 100644
index 0000000000..5e6b10c3ca
--- /dev/null
+++ b/caputils/capture-wpcap.h
@@ -0,0 +1,42 @@
+/* capture-wpcap.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef CAPTURE_WPCAP_H
+#define CAPTURE_WPCAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern gboolean has_wpcap;
+
+
+extern void load_wpcap(void);
+
+/* error message, if WinPcap couldn't be loaded */
+/* will use g_strdup, don't forget to g_free the returned string! */
+extern char *cant_load_winpcap_err(const char *app_name);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAPTURE_WPCAP_H */
diff --git a/caputils/capture_ifinfo.h b/caputils/capture_ifinfo.h
new file mode 100644
index 0000000000..f70bdf4ba5
--- /dev/null
+++ b/caputils/capture_ifinfo.h
@@ -0,0 +1,121 @@
+/* capture_ifinfo.h
+ * Definitions for routines to get information about capture interfaces
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __CAPTURE_IFINFO_H__
+#define __CAPTURE_IFINFO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum {
+ IF_WIRED,
+ IF_AIRPCAP,
+ IF_PIPE,
+ IF_STDIN,
+ IF_BLUETOOTH,
+ IF_WIRELESS,
+ IF_DIALUP,
+ IF_USB,
+ IF_VIRTUAL
+} interface_type;
+
+/*
+ * The list of interfaces returned by "get_interface_list()" is
+ * a list of these structures.
+ */
+typedef struct {
+ char *name; /* e.g. "eth0" */
+ char *friendly_name; /* from OS, e.g. "Local Area Connection", or
+ NULL if not available */
+ char *vendor_description;
+ /* vendor description from pcap_findalldevs(),
+ e.g. "Realtek PCIe GBE Family Controller",
+ or NULL if not available */
+ GSList *addrs; /* containing address values of if_addr_t */
+ interface_type type; /* type of interface */
+ gboolean loopback; /* TRUE if loopback, FALSE otherwise */
+} if_info_t;
+
+/*
+ * An address in the "addrs" list.
+ */
+typedef enum {
+ IF_AT_IPv4,
+ IF_AT_IPv6
+} if_address_type;
+
+typedef struct {
+ if_address_type ifat_type;
+ union {
+ guint32 ip4_addr; /* 4 byte IP V4 address, or */
+ guint8 ip6_addr[16];/* 16 byte IP V6 address */
+ } addr;
+} if_addr_t;
+
+/**
+ * Fetch the interface list from a child process.
+ */
+extern GList *capture_interface_list(int *err, char **err_str, void (*update_cb)(void));
+
+/* Error values from "get_interface_list()/capture_interface_list()". */
+#define CANT_GET_INTERFACE_LIST 1 /* error getting list */
+#define NO_INTERFACES_FOUND 2 /* list is empty */
+#define DONT_HAVE_PCAP 3 /* couldn't load WinPcap */
+
+void free_interface_list(GList *if_list);
+
+/*
+ * "get_if_capabilities()" and "capture_if_capabilities()" return a pointer
+ * to an allocated instance of this structure. "free_if_capabilities()"
+ * frees the returned instance.
+ */
+typedef struct {
+ gboolean can_set_rfmon; /* TRUE if can be put into monitor mode */
+ GList *data_link_types; /* GList of data_link_info_t's */
+} if_capabilities_t;
+
+/*
+ * Information about data link types.
+ */
+typedef struct {
+ int dlt; /* e.g. DLT_EN10MB (which is 1) */
+ char *name; /* e.g. "EN10MB" or "DLT 1" */
+ char *description; /* descriptive name from wiretap e.g. "Ethernet", NULL if unknown */
+} data_link_info_t;
+
+/**
+ * Fetch the linktype list for the specified interface from a child process.
+ */
+extern if_capabilities_t *
+capture_get_if_capabilities(const char *devname, gboolean monitor_mode,
+ char **err_str, void (*update_cb)(void));
+
+void free_if_capabilities(if_capabilities_t *caps);
+
+void add_interface_to_remote_list(if_info_t *if_info);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CAPTURE_IFINFO_H__ */
diff --git a/caputils/capture_win_ifnames.c b/caputils/capture_win_ifnames.c
new file mode 100644
index 0000000000..b18250f57d
--- /dev/null
+++ b/caputils/capture_win_ifnames.c
@@ -0,0 +1,369 @@
+/* capture_win_ifnames.c
+* Routines supporting the use of Windows friendly interface names within Wireshark
+* Copyright 2011-2012, Mike Garratt <wireshark@evn.co.nz>
+*
+* Wireshark - Network traffic analyzer
+* By Gerald Combs <gerald@wireshark.org>
+* Copyright 1998 Gerald Combs
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "config.h"
+
+#ifdef _WIN32
+
+#include <winsock2.h>
+#include <windows.h>
+#include <iphlpapi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <wtap.h>
+#include <libpcap.h>
+#include <glib.h>
+
+#include <ntddndis.h>
+
+#ifndef NDIS_IF_MAX_STRING_SIZE
+#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE /* =256 in <ifdef.h> */
+#endif
+
+#ifndef NETIO_STATUS
+#define NETIO_STATUS DWORD
+#endif
+
+#include "log.h"
+
+#include <capchild/capture_ifinfo.h>
+#include "caputils/capture_win_ifnames.h"
+#include "wsutil/file_util.h"
+
+static int gethexdigit(const char *p)
+{
+ if(*p >= '0' && *p <= '9'){
+ return *p - '0';
+ }else if(*p >= 'A' && *p <= 'F'){
+ return *p - 'A' + 0xA;
+ }else if(*p >= 'a' && *p <= 'f'){
+ return *p - 'a' + 0xa;
+ }else{
+ return -1; /* Not a hex digit */
+ }
+}
+
+static gboolean get8hexdigits(const char *p, DWORD *d)
+{
+ int digit;
+ DWORD val;
+ int i;
+
+ val = 0;
+ for(i = 0; i < 8; i++){
+ digit = gethexdigit(p++);
+ if(digit == -1){
+ return FALSE; /* Not a hex digit */
+ }
+ val = (val << 4) | digit;
+ }
+ *d = val;
+ return TRUE;
+}
+
+static gboolean get4hexdigits(const char *p, WORD *w)
+{
+ int digit;
+ WORD val;
+ int i;
+
+ val = 0;
+ for(i = 0; i < 4; i++){
+ digit = gethexdigit(p++);
+ if(digit == -1){
+ return FALSE; /* Not a hex digit */
+ }
+ val = (val << 4) | digit;
+ }
+ *w = val;
+ return TRUE;
+}
+
+/*
+ * If a string is a GUID in {}, fill in a GUID structure with the GUID
+ * value and return TRUE; otherwise, if the string is not a valid GUID
+ * in {}, return FALSE.
+ */
+gboolean
+parse_as_guid(const char *guid_text, GUID *guid)
+{
+ int i;
+ int digit1, digit2;
+
+ if(*guid_text != '{'){
+ return FALSE; /* Nope, not enclosed in {} */
+ }
+ guid_text++;
+ /* There must be 8 hex digits; if so, they go into guid->Data1 */
+ if(!get8hexdigits(guid_text, &guid->Data1)){
+ return FALSE; /* nope, not 8 hex digits */
+ }
+ guid_text += 8;
+ /* Now there must be a hyphen */
+ if(*guid_text != '-'){
+ return FALSE; /* Nope */
+ }
+ guid_text++;
+ /* There must be 4 hex digits; if so, they go into guid->Data2 */
+ if(!get4hexdigits(guid_text, &guid->Data2)){
+ return FALSE; /* nope, not 4 hex digits */
+ }
+ guid_text += 4;
+ /* Now there must be a hyphen */
+ if(*guid_text != '-'){
+ return FALSE; /* Nope */
+ }
+ guid_text++;
+ /* There must be 4 hex digits; if so, they go into guid->Data3 */
+ if(!get4hexdigits(guid_text, &guid->Data3)){
+ return FALSE; /* nope, not 4 hex digits */
+ }
+ guid_text += 4;
+ /* Now there must be a hyphen */
+ if(*guid_text != '-'){
+ return FALSE; /* Nope */
+ }
+ guid_text++;
+ /*
+ * There must be 4 hex digits; if so, they go into the first 2 bytes
+ * of guid->Data4.
+ */
+ for(i = 0; i < 2; i++){
+ digit1 = gethexdigit(guid_text);
+ if(digit1 == -1){
+ return FALSE; /* Not a hex digit */
+ }
+ guid_text++;
+ digit2 = gethexdigit(guid_text);
+ if(digit2 == -1){
+ return FALSE; /* Not a hex digit */
+ }
+ guid_text++;
+ guid->Data4[i] = (digit1 << 4)|(digit2);
+ }
+ /* Now there must be a hyphen */
+ if(*guid_text != '-'){
+ return FALSE; /* Nope */
+ }
+ guid_text++;
+ /*
+ * There must be 12 hex digits; if so,t hey go into the next 6 bytes
+ * of guid->Data4.
+ */
+ for(i = 0; i < 6; i++){
+ digit1 = gethexdigit(guid_text);
+ if(digit1 == -1){
+ return FALSE; /* Not a hex digit */
+ }
+ guid_text++;
+ digit2 = gethexdigit(guid_text);
+ if(digit2 == -1){
+ return FALSE; /* Not a hex digit */
+ }
+ guid_text++;
+ guid->Data4[i+2] = (digit1 << 4)|(digit2);
+ }
+ /* Now there must be a closing } */
+ if(*guid_text != '}'){
+ return FALSE; /* Nope */
+ }
+ guid_text++;
+ /* And that must be the end of the string */
+ if(*guid_text != '\0'){
+ return FALSE; /* Nope */
+ }
+ return TRUE;
+}
+
+/**********************************************************************************/
+gboolean IsWindowsVistaOrLater()
+{
+#if (_MSC_VER >= 1800)
+ /*
+ * On VS2103, GetVersionEx is deprecated. Microsoft recommend to
+ * use VerifyVersionInfo instead
+ */
+ OSVERSIONINFOEX osvi;
+ DWORDLONG dwlConditionMask = 0;
+ int op = VER_GREATER_EQUAL;
+
+ SecureZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ osvi.dwMajorVersion = 6;
+ VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op);
+ return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask);
+#else
+ OSVERSIONINFO osvi;
+
+ SecureZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ if(GetVersionEx(&osvi)){
+ return osvi.dwMajorVersion >= 6;
+ }
+ return FALSE;
+#endif
+}
+
+/**********************************************************************************/
+/* Get the friendly name for the given GUID */
+char *
+get_interface_friendly_name_from_device_guid(__in GUID *guid)
+{
+ HMODULE hIPHlpApi;
+ HRESULT status;
+ WCHAR wName[NDIS_IF_MAX_STRING_SIZE + 1];
+ HRESULT hr;
+ gboolean fallbackToUnpublishedApi=TRUE;
+ gboolean haveInterfaceFriendlyName=FALSE;
+ int size;
+ char *name;
+
+ /* Load the ip helper api DLL */
+ hIPHlpApi = LoadLibrary(TEXT("iphlpapi.dll"));
+ if (hIPHlpApi == NULL) {
+ /* Load failed - DLL should always be available in XP+*/
+ return NULL;
+ }
+
+ /* Need to convert an Interface GUID to the interface friendly name (e.g. "Local Area Connection")
+ * The functions required to do this all reside within iphlpapi.dll
+ * - The preferred approach is to use published API functions (Available since Windows Vista)
+ * - We do however fallback to trying undocumented API if the published API is not available (Windows XP/2k3 scenario)
+ */
+
+ if(IsWindowsVistaOrLater()){
+ /* Published API function prototypes (for Windows Vista/Windows Server 2008+) */
+ typedef NETIO_STATUS (WINAPI *ProcAddr_CIG2L) (__in CONST GUID *InterfaceGuid, __out PNET_LUID InterfaceLuid);
+ typedef NETIO_STATUS (WINAPI *ProcAddr_CIL2A) ( __in CONST NET_LUID *InterfaceLuid,__out_ecount(Length) PWSTR InterfaceAlias, __in SIZE_T Length);
+
+ /* Attempt to do the conversion using Published API functions */
+ ProcAddr_CIG2L proc_ConvertInterfaceGuidToLuid=(ProcAddr_CIG2L) GetProcAddress(hIPHlpApi, "ConvertInterfaceGuidToLuid");
+ if(proc_ConvertInterfaceGuidToLuid!=NULL){
+ ProcAddr_CIL2A Proc_ConvertInterfaceLuidToAlias=(ProcAddr_CIL2A) GetProcAddress(hIPHlpApi, "ConvertInterfaceLuidToAlias");
+ if(Proc_ConvertInterfaceLuidToAlias!=NULL){
+ /* we have our functions ready to go, attempt to convert interface guid->luid->friendlyname */
+ NET_LUID InterfaceLuid;
+ hr = proc_ConvertInterfaceGuidToLuid(guid, &InterfaceLuid);
+ if(hr==NO_ERROR){
+ /* guid->luid success */
+ hr = Proc_ConvertInterfaceLuidToAlias(&InterfaceLuid, wName, NDIS_IF_MAX_STRING_SIZE+1);
+
+ if(hr==NO_ERROR){
+ /* luid->friendly name success */
+ haveInterfaceFriendlyName=TRUE; /* success */
+ }else{
+ /* luid->friendly name failed */
+ fallbackToUnpublishedApi=FALSE;
+ }
+ }else{
+ fallbackToUnpublishedApi=FALSE;
+ }
+
+ }
+ }
+ }
+
+
+ if(fallbackToUnpublishedApi && !haveInterfaceFriendlyName){
+ /* Didn't manage to get the friendly name using published api functions
+ * (most likely cause wireshark is running on Windows XP/Server 2003)
+ * Retry using nhGetInterfaceNameFromGuid (an older unpublished API function) */
+ typedef HRESULT (WINAPI *ProcAddr_nhGINFG) (__in GUID *InterfaceGuid, __out PCWSTR InterfaceAlias, __inout DWORD *LengthAddress, wchar_t *a4, wchar_t *a5);
+
+ ProcAddr_nhGINFG Proc_nhGetInterfaceNameFromGuid = NULL;
+ Proc_nhGetInterfaceNameFromGuid = (ProcAddr_nhGINFG) GetProcAddress(hIPHlpApi, "NhGetInterfaceNameFromGuid");
+ if (Proc_nhGetInterfaceNameFromGuid!= NULL) {
+ wchar_t *p4=NULL, *p5=NULL;
+ DWORD NameSize;
+
+ /* testing of nhGetInterfaceNameFromGuid indicates the unpublished API function expects the 3rd parameter
+ * to be the available space in bytes (as compared to wchar's) available in the second parameter buffer
+ * to receive the friendly name (in unicode format) including the space for the nul termination.*/
+ NameSize = sizeof(wName);
+
+ /* do the guid->friendlyname lookup */
+ status = Proc_nhGetInterfaceNameFromGuid(guid, wName, &NameSize, p4, p5);
+
+ if(status==0){
+ haveInterfaceFriendlyName=TRUE; /* success */
+ }
+ }
+ }
+
+ /* we have finished with iphlpapi.dll - release it */
+ FreeLibrary(hIPHlpApi);
+
+ if(!haveInterfaceFriendlyName){
+ /* failed to get the friendly name, nothing further to do */
+ return NULL;
+ }
+
+ /* Get the required buffer size, and then convert the string
+ * from UTF-16 to UTF-8. */
+ size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, NULL, 0, NULL, NULL);
+ name=(char *) g_malloc(size);
+ if (name == NULL){
+ return NULL;
+ }
+ size=WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, size, NULL, NULL);
+ if(size==0){
+ /* bytes written == 0, indicating some form of error*/
+ g_free(name);
+ return NULL;
+ }
+ return name;
+}
+
+/*
+ * Given an interface name, try to extract the GUID from it and parse it.
+ * If that fails, return NULL; if that succeeds, attempt to get the
+ * friendly name for the interface in question. If that fails, return
+ * NULL, otherwise return the friendly name, allocated with g_malloc()
+ * (so that it must be freed with g_free()).
+ */
+char *
+get_windows_interface_friendly_name(const char *interface_devicename)
+{
+ const char* guid_text;
+ GUID guid;
+
+ /* Extract the guid text from the interface device name */
+ if(strncmp("\\Device\\NPF_", interface_devicename, 12)==0){
+ guid_text=interface_devicename+12; /* skip over the '\Device\NPF_' prefix, assume the rest is the guid text */
+ }else{
+ guid_text=interface_devicename;
+ }
+
+ if (!parse_as_guid(guid_text, &guid)){
+ return NULL; /* not a GUID, so no friendly name */
+ }
+
+ /* guid okay, get the interface friendly name associated with the guid */
+ return get_interface_friendly_name_from_device_guid(&guid);
+}
+
+/**************************************************************************************/
+#endif
+
diff --git a/caputils/capture_win_ifnames.h b/caputils/capture_win_ifnames.h
new file mode 100644
index 0000000000..528c73de14
--- /dev/null
+++ b/caputils/capture_win_ifnames.h
@@ -0,0 +1,46 @@
+/* capture_win_ifnames.h
+ * Routines supporting the use of Windows friendly interface names within Wireshark
+ * Copyright 2011-2012, Mike Garratt <wireshark@evn.co.nz>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef CAPTURE_WIN_IFNAMES_H
+#define CAPTURE_WIN_IFNAMES_H
+
+/*
+ * If a string is a GUID in {}, fill in a GUID structure with the GUID
+ * value and return TRUE; otherwise, if the string is not a valid GUID
+ * in {}, return FALSE.
+ */
+extern gboolean parse_as_guid(const char *guid_text, GUID *guid);
+
+/* Get the friendly name for the given GUID */
+extern char *get_interface_friendly_name_from_device_guid(GUID *guid);
+
+/*
+ * Given an interface name, try to extract the GUID from it and parse it.
+ * If that fails, return NULL; if that succeeds, attempt to get the
+ * friendly name for the interface in question. If that fails, return
+ * NULL, otherwise return the friendly name, allocated with g_malloc()
+ * (so that it must be freed with g_free()).
+ */
+extern char *get_windows_interface_friendly_name(const char *interface_devicename);
+
+#endif
diff --git a/caputils/capture_wpcap_packet.c b/caputils/capture_wpcap_packet.c
new file mode 100644
index 0000000000..5b3ffc479d
--- /dev/null
+++ b/caputils/capture_wpcap_packet.c
@@ -0,0 +1,331 @@
+/* capture_wpcap_packet.c
+ * WinPcap-specific interfaces for low-level information (packet.dll).
+ * We load WinPcap at run
+ * time, so that we only need one Wireshark binary and one TShark binary
+ * for Windows, regardless of whether WinPcap is installed or not.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#if defined HAVE_LIBPCAP && defined _WIN32
+
+#include <glib.h>
+#include <gmodule.h>
+
+#include <pcap.h>
+
+/* XXX - yes, I know, I should move cppmagic.h to a generic location. */
+#include "tools/lemon/cppmagic.h"
+
+#include <epan/value_string.h>
+
+#include <winsock2.h> /* Needed here to force a definition of WINVER */
+ /* for some (all ?) Microsoft compilers newer than vc6. */
+ /* (If windows.h were used instead, there might be */
+ /* issues re winsock.h included before winsock2.h ) */
+#include <windowsx.h>
+#include <Ntddndis.h>
+
+#include "caputils/capture_wpcap_packet.h"
+#include <wsutil/file_util.h>
+
+/* packet32.h requires sockaddr_storage
+ * whether sockaddr_storage is defined or not depends on the Platform SDK
+ * version installed. The only one not defining it is the SDK that comes
+ * with MSVC 6.0 (WINVER 0x0400).
+ *
+ * copied from RFC2553 (and slightly modified because of datatypes) ...
+ * XXX - defined more than once, move this to a header file */
+#ifndef WINVER
+#error WINVER not defined ....
+#endif
+#if (WINVER <= 0x0400) && defined(_MSC_VER)
+typedef unsigned short eth_sa_family_t;
+
+/*
+ * Desired design of maximum size and alignment
+ */
+#define ETH_SS_MAXSIZE 128 /* Implementation specific max size */
+#define ETH_SS_ALIGNSIZE (sizeof (gint64 /*int64_t*/))
+ /* Implementation specific desired alignment */
+/*
+ * Definitions used for sockaddr_storage structure paddings design.
+ */
+#define ETH_SS_PAD1SIZE (ETH_SS_ALIGNSIZE - sizeof (eth_sa_family_t))
+#define ETH_SS_PAD2SIZE (ETH_SS_MAXSIZE - (sizeof (eth_sa_family_t) + \
+ ETH_SS_PAD1SIZE + ETH_SS_ALIGNSIZE))
+
+struct sockaddr_storage {
+ eth_sa_family_t __ss_family; /* address family */
+ /* Following fields are implementation specific */
+ char __ss_pad1[ETH_SS_PAD1SIZE];
+ /* 6 byte pad, this is to make implementation */
+ /* specific pad up to alignment field that */
+ /* follows explicit in the data structure */
+ gint64 /*int64_t*/ __ss_align; /* field to force desired structure */
+ /* storage alignment */
+ char __ss_pad2[ETH_SS_PAD2SIZE];
+ /* 112 byte pad to achieve desired size, */
+ /* _SS_MAXSIZE value minus size of ss_family */
+ /* __ss_pad1, __ss_align fields is 112 */
+};
+/* ... copied from RFC2553 */
+#endif /* WINVER */
+
+#include <Packet32.h>
+
+gboolean has_wpacket = FALSE;
+
+
+/* This module will use the PacketRequest function in packet.dll (coming with WinPcap) to "directly" access
+ * the Win32 NDIS network driver(s) and ask for various values (status, statistics, ...).
+ *
+ * Unfortunately, the definitions required for this are not available through the usual windows header files,
+ * but require the Windows "Device Driver Kit" which is not available for free :-(
+ *
+ * Fortunately, the definitions needed to access the various NDIS values are available from various OSS projects:
+ * - WinPcap in Ntddndis.h
+ * - Ndiswrapper in driver/ndis.h and driver/iw_ndis.h
+ * - cygwin (MingW?) in usr/include/w32api/ddk/ndis.h and ntddndis.h
+ * - FreeBSD (netperf)
+ */
+
+/* The MSDN description of the NDIS driver API is available at:
+/* MSDN Home > MSDN Library > Win32 and COM Development > Driver Development Kit > Network Devices and Protocols > Reference */
+/* "NDIS Objects" */
+/* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/network/hh/network/21oidovw_d55042e5-0b8a-4439-8ef2-be7331e98464.xml.asp */
+
+/* Some more interesting links:
+ * http://sourceforge.net/projects/ndiswrapper/
+ * http://www.osronline.com/lists_archive/windbg/thread521.html
+ * http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ndis.h?view=markup
+ * http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/ntddndis.h?view=markup
+ */
+
+
+
+/******************************************************************************************************************************/
+/* stuff to load WinPcap's packet.dll and the functions required from it */
+
+static PCHAR (*p_PacketGetVersion) (void);
+static LPADAPTER (*p_PacketOpenAdapter) (char *adaptername);
+static void (*p_PacketCloseAdapter) (LPADAPTER);
+static int (*p_PacketRequest) (LPADAPTER, int, void *);
+
+typedef struct {
+ const char *name;
+ gpointer *ptr;
+ gboolean optional;
+} symbol_table_t;
+
+#define SYM(x, y) { G_STRINGIFY(x) , (gpointer) &CONCAT(p_,x), y }
+
+void
+wpcap_packet_load(void)
+{
+
+ /* These are the symbols I need or want from packet.dll */
+ static const symbol_table_t symbols[] = {
+ SYM(PacketGetVersion, FALSE),
+ SYM(PacketOpenAdapter, FALSE),
+ SYM(PacketCloseAdapter, FALSE),
+ SYM(PacketRequest, FALSE),
+ { NULL, NULL, FALSE }
+ };
+
+ GModule *wh; /* wpcap handle */
+ const symbol_table_t *sym;
+
+ wh = ws_module_open("packet.dll", 0);
+
+ if (!wh) {
+ return;
+ }
+
+ sym = symbols;
+ while (sym->name) {
+ if (!g_module_symbol(wh, sym->name, sym->ptr)) {
+ if (sym->optional) {
+ /*
+ * We don't care if it's missing; we just
+ * don't use it.
+ */
+ *sym->ptr = NULL;
+ } else {
+ /*
+ * We require this symbol.
+ */
+ return;
+ }
+ }
+ sym++;
+ }
+
+ has_wpacket = TRUE;
+}
+
+
+
+/******************************************************************************************************************************/
+/* functions to access the NDIS driver values */
+
+
+/* get dll version */
+char *
+wpcap_packet_get_version(void)
+{
+ if(!has_wpacket) {
+ return NULL;
+ }
+ return p_PacketGetVersion();
+}
+
+
+/* open the interface */
+void *
+wpcap_packet_open(char *if_name)
+{
+ LPADAPTER adapter;
+
+ g_assert(has_wpacket);
+ adapter = p_PacketOpenAdapter(if_name);
+
+ return adapter;
+}
+
+
+/* close the interface */
+void
+wpcap_packet_close(void *adapter)
+{
+
+ g_assert(has_wpacket);
+ p_PacketCloseAdapter(adapter);
+}
+
+
+/* do a packet request call */
+int
+wpcap_packet_request(void *adapter, ULONG Oid, int set, char *value, unsigned int *length)
+{
+ BOOLEAN Status;
+ ULONG IoCtlBufferLength=(sizeof(PACKET_OID_DATA) + (*length) - 1);
+ PPACKET_OID_DATA OidData;
+
+
+ g_assert(has_wpacket);
+
+ if(p_PacketRequest == NULL) {
+ g_warning("packet_request not available\n");
+ return 0;
+ }
+
+ /* get a buffer suitable for PacketRequest() */
+ OidData=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,IoCtlBufferLength);
+ if (OidData == NULL) {
+ g_warning("GlobalAllocPtr failed for %u\n", IoCtlBufferLength);
+ return 0;
+ }
+
+ OidData->Oid = Oid;
+ OidData->Length = *length;
+ memcpy(OidData->Data, value, *length);
+
+ Status = p_PacketRequest(adapter, set, OidData);
+
+ if(Status) {
+ if(OidData->Length <= *length) {
+ /* copy value from driver */
+ memcpy(value, OidData->Data, OidData->Length);
+ *length = OidData->Length;
+ } else {
+ /* the driver returned a value that is longer than expected (and longer than the given buffer) */
+ g_warning("returned oid too long, Oid: 0x%x OidLen:%u MaxLen:%u", Oid, OidData->Length, *length);
+ Status = FALSE;
+ }
+ }
+
+ GlobalFreePtr (OidData);
+
+ if(Status) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/* get an UINT value using the packet request call */
+int
+wpcap_packet_request_uint(void *adapter, ULONG Oid, UINT *value)
+{
+ BOOLEAN Status;
+ int length = sizeof(UINT);
+
+
+ Status = wpcap_packet_request(adapter, Oid, FALSE /* !set */, (char *) value, &length);
+ if(Status && length == sizeof(UINT)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/* get an ULONG value using the NDIS packet request call */
+int
+wpcap_packet_request_ulong(void *adapter, ULONG Oid, ULONG *value)
+{
+ BOOLEAN Status;
+ int length = sizeof(ULONG);
+
+
+ Status = wpcap_packet_request(adapter, Oid, FALSE /* !set */, (char *) value, &length);
+ if(Status && length == sizeof(ULONG)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+#else /* HAVE_LIBPCAP && _WIN32 */
+
+void
+wpcap_packet_load(void)
+{
+ return;
+}
+
+#endif /* HAVE_LIBPCAP */
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * ex: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/caputils/capture_wpcap_packet.h b/caputils/capture_wpcap_packet.h
new file mode 100644
index 0000000000..f043d89e92
--- /dev/null
+++ b/caputils/capture_wpcap_packet.h
@@ -0,0 +1,51 @@
+/* capture_wpcap_packet.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef CAPTURE_WPCAP_PACKET_H
+#define CAPTURE_WPCAP_PACKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern void wpcap_packet_load(void);
+
+/* get the packet.dll version info */
+extern char *wpcap_packet_get_version(void);
+
+/* open the interface */
+extern void * wpcap_packet_open(char *if_name);
+
+/* close the interface */
+extern void wpcap_packet_close(void * adapter);
+
+extern int wpcap_packet_request(void *a, ULONG Oid, int set, char *value, unsigned int *length);
+
+extern int wpcap_packet_request_uint(void *a, ULONG Oid, UINT *value);
+
+extern int wpcap_packet_request_ulong(void *a, ULONG Oid, ULONG *value);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAPTURE_WPCAP_PACKET_H */
diff --git a/caputils/doxygen.cfg.in b/caputils/doxygen.cfg.in
new file mode 100644
index 0000000000..cae55f4037
--- /dev/null
+++ b/caputils/doxygen.cfg.in
@@ -0,0 +1,81 @@
+# @configure_input@
+
+@INCLUDE = ../doxygen_global.cfg
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "Wireshark Capture Utilities Library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ../wsar_html
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = caputils
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES = ../doxygen-core.tag=..
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE = doxygen-caputils.tag
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE = wireshark-caputils.chm
diff --git a/caputils/ws80211_utils.c b/caputils/ws80211_utils.c
new file mode 100644
index 0000000000..21f8a8a673
--- /dev/null
+++ b/caputils/ws80211_utils.c
@@ -0,0 +1,748 @@
+/*
+ * ws80211 utilities
+ * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
+
+Parts of this file was copied from iw:
+
+Copyright (c) 2007, 2008 Johannes Berg
+Copyright (c) 2007 Andy Lutomirski
+Copyright (c) 2007 Mike Kershaw
+Copyright (c) 2008-2009 Luis R. Rodriguez
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "ws80211_utils.h"
+
+#if defined(HAVE_LIBNL) && defined(HAVE_NL80211)
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#include <linux/nl80211.h>
+
+/* libnl 1.x compatibility code */
+#ifdef HAVE_LIBNL1
+#define nl_sock nl_handle
+static inline struct nl_handle *nl_socket_alloc(void)
+{
+ return nl_handle_alloc();
+}
+
+static inline void nl_socket_free(struct nl_sock *h)
+{
+ nl_handle_destroy(h);
+}
+#endif /* HAVE_LIBNL1 */
+
+struct nl80211_state {
+ struct nl_sock *nl_sock;
+ int nl80211_id;
+};
+
+static struct nl80211_state nl_state;
+
+int ws80211_init(void)
+{
+ int err;
+
+ struct nl80211_state *state = &nl_state;
+
+ state->nl_sock = nl_socket_alloc();
+ if (!state->nl_sock) {
+ fprintf(stderr, "Failed to allocate netlink socket.\n");
+ return -ENOMEM;
+ }
+
+ if (genl_connect(state->nl_sock)) {
+ fprintf(stderr, "Failed to connect to generic netlink.\n");
+ err = -ENOLINK;
+ goto out_handle_destroy;
+ }
+
+ state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
+ if (state->nl80211_id < 0) {
+ fprintf(stderr, "nl80211 not found.\n");
+ err = -ENOENT;
+ goto out_handle_destroy;
+ }
+
+ return 0;
+
+ out_handle_destroy:
+ nl_socket_free(state->nl_sock);
+ state->nl_sock = 0;
+ return err;
+}
+
+static int error_handler(struct sockaddr_nl *nla _U_, struct nlmsgerr *err,
+ void *arg)
+{
+ int *ret = (int *)arg;
+ *ret = err->error;
+ return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg _U_, void *arg)
+{
+ int *ret = (int *)arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+static int ack_handler(struct nl_msg *msg _U_, void *arg)
+{
+ int *ret = (int *)arg;
+ *ret = 0;
+ return NL_STOP;
+}
+
+static int nl80211_do_cmd(struct nl_msg *msg, struct nl_cb *cb)
+{
+ volatile int err;
+
+ if (!nl_state.nl_sock)
+ return -ENOLINK;
+
+ err = nl_send_auto_complete(nl_state.nl_sock, msg);
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, (void *)&err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, (void *)&err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, (void *)&err);
+
+ while (err > 0)
+ nl_recvmsgs(nl_state.nl_sock, cb);
+ out:
+ nl_cb_put(cb);
+
+ return err;
+}
+
+struct nliface_cookie
+{
+ char *ifname;
+ GArray *interfaces;
+};
+
+/*
+ * And now for a steaming heap of suck.
+ *
+ * The nla_for_each_nested() macro defined by at least some versions of the
+ * Linux kernel's headers doesn't do the casting required when compiling
+ * with a C++ compiler or with -Wc++-compat, so we get warnings, and those
+ * warnings are fatal when we compile this file.
+ *
+ * So we replace it with our own version, which does the requisite cast.
+ */
+
+/**
+ * nla_for_each_nested - iterate over nested attributes
+ * @pos: loop counter, set to current attribute
+ * @nla: attribute containing the nested attributes
+ * @rem: initialized to len, holds bytes currently remaining in stream
+ */
+#undef nla_for_each_nested
+#define nla_for_each_nested(pos, nla, rem) \
+ nla_for_each_attr(pos, (struct nlattr *)nla_data(nla), nla_len(nla), rem)
+
+static int get_phys_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
+
+ struct nliface_cookie *cookie = (struct nliface_cookie *)arg;
+
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ {NLA_UNSPEC, 0, 0}, /* __NL80211_FREQUENCY_ATTR_INVALID */
+ {NLA_U32, 0, 0}, /* NL80211_FREQUENCY_ATTR_FREQ */
+ {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_DISABLED */
+ {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_PASSIVE_SCAN */
+ {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_NO_IBSS */
+ {NLA_FLAG, 0, 0}, /* NL80211_FREQUENCY_ATTR_RADAR */
+ {NLA_U32, 0, 0} /* NL80211_FREQUENCY_ATTR_MAX_TX_POWER */
+ };
+
+ struct nlattr *nl_band;
+ struct nlattr *nl_freq;
+ struct nlattr *nl_mode;
+ int bandidx = 1;
+ int rem_band, rem_freq, rem_mode;
+ struct ws80211_interface *iface;
+ int cap_monitor = 0;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
+
+ if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) {
+ nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) {
+ if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
+ cap_monitor = 1;
+ }
+ }
+ if (!cap_monitor)
+ return NL_SKIP;
+
+ iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
+ if (!iface)
+ return NL_SKIP;
+
+ iface->frequencies = g_array_new(FALSE, FALSE, sizeof(int));
+ iface->channel_types = 1 << WS80211_CHAN_NO_HT;
+
+ if (tb_msg[NL80211_ATTR_WIPHY_NAME]) {
+ iface->ifname = g_strdup_printf("%s.mon",
+ nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
+ }
+
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+ bandidx++;
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX,
+ (struct nlattr *)nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+#ifdef NL80211_BAND_ATTR_HT_CAPA
+ if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
+ gboolean ht40;
+ iface->channel_types |= 1 << WS80211_CHAN_HT20;
+ ht40 = !!(nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]) & 0x02);
+ if (ht40) {
+ iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
+ iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
+ }
+ }
+#endif /* NL80211_BAND_ATTR_HT_CAPA */
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ uint32_t freq;
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ (struct nlattr *)nla_data(nl_freq),
+ nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ continue;
+
+ freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ g_array_append_val(iface->frequencies, freq);
+ }
+ }
+
+ /* Can frequency be set? Only newer versions of cfg80211 supports this */
+#ifdef HAVE_NL80211_CMD_SET_CHANNEL
+ if (tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) {
+ int cmd;
+ struct nlattr *nl_cmd;
+ nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], cmd) {
+ if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
+ iface->can_set_freq = TRUE;
+ }
+ }
+#else
+ iface->can_set_freq = TRUE;
+#endif
+ g_array_append_val(cookie->interfaces, iface);
+
+ return NL_SKIP;
+}
+
+
+static int ws80211_get_phys(GArray *interfaces)
+{
+ struct nliface_cookie cookie;
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+ msg = nlmsg_alloc();
+ if (!msg) {
+ fprintf(stderr, "failed to allocate netlink message\n");
+ return 2;
+ }
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+
+ cookie.interfaces = interfaces;
+
+ genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
+ NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
+
+ return nl80211_do_cmd(msg, cb);
+
+}
+
+static int get_freq_wext(const char *ifname)
+{
+ int fd;
+ int ret = -1;
+ /* Ugly hack to avoid including wireless.h */
+ struct {
+ char name1[IFNAMSIZ];
+ __s32 m;
+ __s16 e;
+ __u8 i;
+ __u8 flags;
+ } wrq;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd == -1)
+ return -1;
+
+ g_strlcpy(wrq.name1, ifname, IFNAMSIZ);
+ /* SIOCGIWFREQ */
+ if (ioctl(fd, 0x8B05, &wrq) == 0) {
+ if (wrq.e == 6)
+ ret = wrq.m;
+ }
+ close(fd);
+ return ret;
+}
+
+struct __iface_info
+{
+ struct ws80211_iface_info *pub;
+ int type;
+ int phyidx;
+};
+
+static int get_iface_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct __iface_info *iface_info = (struct __iface_info *)arg;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb_msg[NL80211_ATTR_IFTYPE]) {
+ iface_info->type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]);
+ }
+ if (tb_msg[NL80211_ATTR_WIPHY]) {
+ iface_info->phyidx = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
+ }
+
+ if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) {
+ iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
+ iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
+
+ if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ switch (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+
+ case NL80211_CHAN_NO_HT:
+ iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
+ break;
+
+ case NL80211_CHAN_HT20:
+ iface_info->pub->current_chan_type = WS80211_CHAN_HT20;
+ break;
+
+ case NL80211_CHAN_HT40MINUS:
+ iface_info->pub->current_chan_type = WS80211_CHAN_HT40MINUS;
+ break;
+
+ case NL80211_CHAN_HT40PLUS:
+ iface_info->pub->current_chan_type = WS80211_CHAN_HT40PLUS;
+ break;
+ }
+ }
+
+ }
+ return NL_SKIP;
+}
+
+
+static int __ws80211_get_iface_info(const char *name, struct __iface_info *iface_info)
+{
+ int devidx;
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+ msg = nlmsg_alloc();
+ if (!msg) {
+ fprintf(stderr, "failed to allocate netlink message\n");
+ return 2;
+ }
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+
+ devidx = if_nametoindex(name);
+
+ genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
+ 0, NL80211_CMD_GET_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_info_handler, iface_info);
+
+ if (nl80211_do_cmd(msg, cb))
+ return -1;
+
+ /* Old kernels cant get the current freq via netlink. Try WEXT too :( */
+ if (iface_info->pub->current_freq == -1)
+ iface_info->pub->current_freq = get_freq_wext(name);
+ return 0;
+
+nla_put_failure:
+ fprintf(stderr, "building message failed\n");
+ return -1;
+}
+
+int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
+{
+ struct __iface_info __iface_info;
+
+ memset(iface_info, 0, sizeof(*iface_info));
+ __iface_info.pub = iface_info;
+ __iface_info.type = -1;
+ __iface_info.phyidx= -1;
+ __iface_info.pub->current_freq = -1;
+ __iface_info.pub->current_chan_type = WS80211_CHAN_NO_HT;
+
+ return __ws80211_get_iface_info(name, &__iface_info);
+}
+
+static int ws80211_populate_devices(GArray *interfaces)
+{
+ FILE *fh;
+ char line[200];
+ char *t;
+ gchar *t2;
+ char *ret;
+ int i;
+ unsigned int j;
+
+ struct ws80211_iface_info pub = {-1, WS80211_CHAN_NO_HT};
+ struct __iface_info iface_info;
+ struct ws80211_interface *iface;
+
+ /* Get a list of phy's that can handle monitor mode */
+ ws80211_get_phys(interfaces);
+
+ fh = g_fopen("/proc/net/dev", "r");
+ if(!fh) {
+ fprintf(stderr, "Cannot open /proc/net/dev");
+ return -ENOENT;
+ }
+
+ /* Skip the first two lines */
+ for (i = 0; i < 2; i++) {
+ ret = fgets(line, sizeof(line), fh);
+ if (ret == NULL) {
+ fprintf(stderr, "Error parsing /proc/net/dev");
+ fclose(fh);
+ return -1;
+ }
+ }
+
+ /* Update names of user created monitor interfaces */
+ while(fgets(line, sizeof(line), fh)) {
+ t = index(line, ':');
+ if (!t)
+ continue;
+ *t = 0;
+ t = line;
+ while (*t && *t == ' ')
+ t++;
+ memset(&iface_info, 0, sizeof(iface_info));
+ iface_info.pub = &pub;
+ __ws80211_get_iface_info(t, &iface_info);
+
+ if (iface_info.type == NL80211_IFTYPE_MONITOR) {
+ for (j = 0; j < interfaces->len; j++) {
+ iface = g_array_index(interfaces, struct ws80211_interface *, j);
+ t2 = g_strdup_printf("phy%d.mon", iface_info.phyidx);
+ if (t2) {
+ if (!strcmp(t2, iface->ifname)) {
+ g_free(iface->ifname);
+ iface->ifname = g_strdup(t);
+ }
+ g_free(t2);
+ }
+ }
+ }
+ }
+ fclose(fh);
+ return 0;
+}
+
+static int ws80211_iface_up(const char *ifname)
+{
+ int sock;
+ struct ifreq ifreq;
+
+ sock = socket(AF_PACKET, SOCK_RAW, 0);
+ if (sock == -1)
+ return -1;
+
+ g_strlcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
+
+ if (ioctl(sock, SIOCGIFFLAGS, &ifreq))
+ goto out_err;
+
+ ifreq.ifr_flags |= IFF_UP;
+
+ if (ioctl(sock, SIOCSIFFLAGS, &ifreq))
+ goto out_err;
+
+ close(sock);
+ return 0;
+
+out_err:
+ close(sock);
+ return -1;
+}
+
+static int ws80211_create_on_demand_interface(const char *name)
+{
+ int devidx, phyidx, err;
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+
+ devidx = if_nametoindex(name);
+ if (devidx)
+ return ws80211_iface_up(name);
+
+ if (sscanf(name, "phy%d.mon", &phyidx) != 1)
+ return -EINVAL;
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+ msg = nlmsg_alloc();
+ if (!msg) {
+ fprintf(stderr, "failed to allocate netlink message\n");
+ return 2;
+ }
+
+ genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
+ 0, NL80211_CMD_NEW_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phyidx);
+
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
+
+ err = nl80211_do_cmd(msg, cb);
+ if (err)
+ return err;
+ return ws80211_iface_up(name);
+
+nla_put_failure:
+ fprintf(stderr, "building message failed\n");
+ return 2;
+}
+
+int ws80211_set_freq(const char *name, int freq, int chan_type)
+{
+ int devidx, err;
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+
+ err = ws80211_create_on_demand_interface(name);
+ if (err)
+ return err;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ fprintf(stderr, "failed to allocate netlink message\n");
+ return 2;
+ }
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+
+ devidx = if_nametoindex(name);
+
+#ifdef HAVE_NL80211_CMD_SET_CHANNEL
+ genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
+ 0, NL80211_CMD_SET_CHANNEL, 0);
+#else
+ genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0,
+ 0, NL80211_CMD_SET_WIPHY, 0);
+#endif
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+
+ switch (chan_type) {
+
+#ifdef NL80211_BAND_ATTR_HT_CAPA
+ case WS80211_CHAN_NO_HT:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
+ break;
+
+ case WS80211_CHAN_HT20:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
+ break;
+
+ case WS80211_CHAN_HT40MINUS:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
+ break;
+
+ case WS80211_CHAN_HT40PLUS:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
+ break;
+#endif
+
+ default:
+ break;
+ }
+ err = nl80211_do_cmd(msg, cb);
+ return err;
+
+nla_put_failure:
+ fprintf(stderr, "building message failed\n");
+ return 2;
+
+}
+
+void ws80211_free_interfaces(GArray *interfaces)
+{
+ struct ws80211_interface *iface;
+
+ if (!interfaces)
+ return;
+
+ while (interfaces->len) {
+ iface = g_array_index(interfaces, struct ws80211_interface *, 0);
+ g_array_remove_index(interfaces, 0);
+ g_array_free(iface->frequencies, TRUE);
+ g_free(iface->ifname);
+ g_free(iface);
+ }
+ g_array_free(interfaces, TRUE);
+}
+
+GArray* ws80211_find_interfaces(void)
+{
+ GArray *interfaces;
+
+ if (!nl_state.nl_sock)
+ return NULL;
+
+ interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
+ if (!interfaces)
+ return NULL;
+
+ if (ws80211_populate_devices(interfaces)) {
+ ws80211_free_interfaces(interfaces);
+ return NULL;
+ }
+ return interfaces;
+}
+
+int ws80211_frequency_to_channel(int freq)
+{
+ if (freq == 2484)
+ return 14;
+
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+
+ return freq / 5 - 1000;
+}
+
+int
+ws80211_str_to_chan_type(const gchar *s)
+{
+ int ret = -1;
+ if (!s)
+ return -1;
+
+ if (!strcmp(s, CHAN_NO_HT))
+ ret = WS80211_CHAN_NO_HT;
+ if (!strcmp(s, CHAN_HT20))
+ ret = WS80211_CHAN_HT20;
+ if (!strcmp(s, CHAN_HT40MINUS))
+ ret = WS80211_CHAN_HT40MINUS;
+ if (!strcmp(s, CHAN_HT40PLUS))
+ ret = WS80211_CHAN_HT40PLUS;
+ return ret;
+}
+
+const gchar
+*ws80211_chan_type_to_str(int type)
+{
+ switch (type) {
+ case WS80211_CHAN_NO_HT:
+ return CHAN_NO_HT;
+ case WS80211_CHAN_HT20:
+ return CHAN_HT20;
+ case WS80211_CHAN_HT40MINUS:
+ return CHAN_HT40MINUS;
+ case WS80211_CHAN_HT40PLUS:
+ return CHAN_HT40PLUS;
+ }
+ return NULL;
+}
+
+#else /* HAVE_LIBNL */
+int ws80211_init(void)
+{
+ return -1;
+}
+
+GArray* ws80211_find_interfaces(void)
+{
+ return NULL;
+}
+
+int ws80211_get_iface_info(const char *name _U_, struct ws80211_iface_info *iface_info _U_)
+{
+ return -1;
+}
+
+void ws80211_free_interfaces(GArray *interfaces _U_)
+{
+}
+
+int ws80211_frequency_to_channel(int freq _U_)
+{
+ return -1;
+}
+
+int ws80211_set_freq(const char *name _U_, int freq _U_, int chan_type _U_)
+{
+ return -1;
+}
+
+int ws80211_str_to_chan_type(const gchar *s _U_)
+{
+ return -1;
+}
+
+const gchar *ws80211_chan_type_to_str(int type _U_)
+{
+ return NULL;
+}
+#endif /* HAVE_LIBNL && HAVE_NL80211 */
diff --git a/caputils/ws80211_utils.h b/caputils/ws80211_utils.h
new file mode 100644
index 0000000000..2a6e04f629
--- /dev/null
+++ b/caputils/ws80211_utils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __WS80211_UTILS_H__
+#define __WS80211_UTILS_H__
+
+enum ws80211_channel_type {
+ WS80211_CHAN_NO_HT,
+ WS80211_CHAN_HT20,
+ WS80211_CHAN_HT40MINUS,
+ WS80211_CHAN_HT40PLUS
+};
+
+#define CHAN_NO_HT "NOHT"
+#define CHAN_HT20 "HT20"
+#define CHAN_HT40MINUS "HT40-"
+#define CHAN_HT40PLUS "HT40+"
+
+struct ws80211_interface
+{
+ char *ifname;
+ gboolean can_set_freq;
+ GArray *frequencies;
+ int channel_types; /* Union for all bands */
+};
+
+struct ws80211_iface_info {
+ int current_freq;
+ enum ws80211_channel_type current_chan_type;
+};
+
+
+int ws80211_init(void);
+GArray* ws80211_find_interfaces(void);
+int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info);
+void ws80211_free_interfaces(GArray *interfaces);
+int ws80211_frequency_to_channel(int freq);
+int ws80211_set_freq(const char *name, int freq, int chan_type);
+int ws80211_str_to_chan_type(const gchar *s);
+const gchar *ws80211_chan_type_to_str(int type);
+
+#endif /* __WS80211_UTILS_H__ */