aboutsummaryrefslogtreecommitdiffstats
path: root/capture
diff options
context:
space:
mode:
authorJoão Valverde <joao.valverde@tecnico.ulisboa.pt>2021-03-24 22:09:19 +0000
committerJoão Valverde <joao.valverde@tecnico.ulisboa.pt>2021-03-29 06:08:02 +0100
commit7fee50274f36a5feba113aa9ad3e72ca37bf1466 (patch)
tree485b040aa4b6f00d9043c379db8fecdea4661f1b /capture
parent2ba52cdc0e4216dafdfc32498fc0210c99449ec9 (diff)
Merge the caputils/ and capchild/ directories
The distinction between the different kinds of capture utility may not warrant a special subfolfer for each, and sometimes the distinction is not be clear or some functions could stradle multiple "categories" (like capture_ifinfo.[ch]). Simplify by having only a generic 'capture' subfolder. The separate CMake libraries are kept as a way to reuse object code efficiently.
Diffstat (limited to 'capture')
-rw-r--r--capture/.editorconfig21
-rw-r--r--capture/CMakeLists.txt124
-rw-r--r--capture/airpcap.h905
-rw-r--r--capture/airpcap_loader.c1230
-rw-r--r--capture/airpcap_loader.h407
-rw-r--r--capture/capture-pcap-util-int.h61
-rw-r--r--capture/capture-pcap-util-unix.c202
-rw-r--r--capture/capture-pcap-util.c1626
-rw-r--r--capture/capture-pcap-util.h93
-rw-r--r--capture/capture-wpcap.c915
-rw-r--r--capture/capture-wpcap.h32
-rw-r--r--capture/capture_ifinfo.c373
-rw-r--r--capture/capture_ifinfo.h138
-rw-r--r--capture/capture_session.h135
-rw-r--r--capture/capture_sync.c2100
-rw-r--r--capture/capture_sync.h112
-rw-r--r--capture/capture_win_ifnames.c271
-rw-r--r--capture/capture_win_ifnames.h34
-rw-r--r--capture/iface_monitor.c398
-rw-r--r--capture/iface_monitor.h71
-rw-r--r--capture/ws80211_utils.c1275
-rw-r--r--capture/ws80211_utils.h134
22 files changed, 10657 insertions, 0 deletions
diff --git a/capture/.editorconfig b/capture/.editorconfig
new file mode 100644
index 0000000000..9411ef0157
--- /dev/null
+++ b/capture/.editorconfig
@@ -0,0 +1,21 @@
+#
+# Editor configuration
+#
+# https://editorconfig.org
+#
+
+[capture-pcap-util-unix.[ch]]
+indent_style = tab
+indent_size = tab
+
+[capture-pcap-util.[ch]]
+indent_style = tab
+indent_size = tab
+
+[capture-wpcap.[ch]]
+indent_style = tab
+indent_size = tab
+
+[ws80211_utils.[ch]]
+indent_style = tab
+indent_size = tab
diff --git a/capture/CMakeLists.txt b/capture/CMakeLists.txt
new file mode 100644
index 0000000000..57a94d78c7
--- /dev/null
+++ b/capture/CMakeLists.txt
@@ -0,0 +1,124 @@
+# CMakeLists.txt
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# Copyright 1998 Gerald Combs
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+
+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
+ )
+endif()
+
+set(CAPUTILS_SRC
+ ${PLATFORM_CAPUTILS_SRC}
+ capture-pcap-util.c
+ iface_monitor.c
+ ws80211_utils.c
+)
+
+if (AIRPCAP_FOUND)
+ set(CAPUTILS_SRC
+ ${CAPUTILS_SRC}
+ airpcap_loader.c
+ )
+endif()
+
+set_source_files_properties(
+ ${CAPUTILS_SRC}
+ PROPERTIES
+ COMPILE_FLAGS "${WERROR_COMMON_FLAGS}"
+)
+
+
+add_library(caputils STATIC
+ ${CAPUTILS_SRC}
+)
+
+target_link_libraries(caputils
+ PUBLIC
+ wsutil
+ $<$<BOOL:${PCAP_FOUND}>:pcap::pcap>
+ PRIVATE
+ ${NL_LIBRARIES}
+)
+
+target_include_directories(caputils SYSTEM
+ PRIVATE
+ ${NL_INCLUDE_DIRS}
+)
+
+if(WIN32)
+ target_link_libraries(caputils PRIVATE "iphlpapi.lib")
+endif(WIN32)
+
+set_target_properties(caputils PROPERTIES
+ LINK_FLAGS "${WS_LINK_FLAGS}"
+ FOLDER "Libs")
+
+set(CAPCHILD_SRC
+ capture_ifinfo.c
+ capture_sync.c
+)
+
+set_source_files_properties(
+ ${CAPCHILD_SRC}
+ PROPERTIES
+ COMPILE_FLAGS "${WERROR_COMMON_FLAGS}"
+)
+
+file(GLOB CAPCHILD_HEADERS capture_session.h)
+
+add_library(capchild STATIC
+ ${CAPCHILD_SRC}
+)
+
+target_link_libraries(capchild
+ PRIVATE
+ wsutil
+ $<$<BOOL:${PCAP_FOUND}>:pcap::pcap>
+)
+
+set_target_properties(capchild PROPERTIES
+ LINK_FLAGS "${WS_LINK_FLAGS}"
+ FOLDER "Libs")
+
+CHECKAPI(
+ NAME
+ caputils-base
+ SWITCHES
+ SOURCES
+ ${CAPUTILS_SRC}
+)
+CHECKAPI(
+ NAME
+ caputils-todo
+ SWITCHES
+ -M
+ SOURCES
+ ${CAPUTILS_SRC}
+)
+
+#
+# Editor modelines - https://www.wireshark.org/tools/modelines.html
+#
+# Local variables:
+# c-basic-offset: 8
+# tab-width: 8
+# indent-tabs-mode: t
+# End:
+#
+# vi: set shiftwidth=8 tabstop=8 noexpandtab:
+# :indentSize=8:tabSize=8:noTabs=false:
+#
diff --git a/capture/airpcap.h b/capture/airpcap.h
new file mode 100644
index 0000000000..9ca0688834
--- /dev/null
+++ b/capture/airpcap.h
@@ -0,0 +1,905 @@
+/*
+ * Copyright (c) 2006-2007 CACE Technologies, Davis (California)
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_)
+#define AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_
+
+#ifdef _MSC_VER
+/* This stops VS2005 ranting against stdio. */
+#pragma warning( disable : 4996)
+#endif
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ \mainpage AirPcap interface documentation
+
+ \section Introduction
+
+ This document describes the data structures and the functions exported by the CACE Technologies AirPcap library.
+ The AirPcap library provides low-level access to the AirPcap driver including advanced capabilities such as channel setting,
+ link type control and WEP configuration.<br>
+ This manual includes the following sections:
+
+ \note throughout this documentation, \e device refers to a physical USB AirPcap device, while \e adapter is an open API
+ instance. Most of the AirPcap API operations are adapter-specific but some of them, like setting the channel, are
+ per-device and will be reflected on all the open adapters. These functions will have "Device" in their name, e.g.
+ AirpcapSetDeviceChannel().
+
+ \b Sections:
+
+ - \ref airpcapfuncs
+ - \ref airpcapdefs
+ - \ref radiotap
+*/
+
+/** @defgroup airpcapdefs AirPcap definitions and data structures
+ * @{
+ */
+
+/*!
+ \brief This string is the fixed prefix in the airpcap adapter name.
+ It can be used to parse the name field in an AirpcapDeviceDescription structure.
+*/
+#define AIRPCAP_DEVICE_NAME_PREFIX "\\\\.\\airpcap"
+
+/*!
+ \brief This string is the scanf modifier to extract the adapter number from an adapter name.
+ It can be used to parse the name field in an AirpcapDeviceDescription structure with scanf.
+*/
+#define AIRPCAP_DEVICE_NUMBER_EXTRACT_STRING "\\\\.\\airpcap%u"
+
+#define AIRPCAP_DEVICE_ANY_EXTRACT_STRING "\\\\.\\airpcap_any"
+
+/*!
+ \brief Entry in the list returned by \ref AirpcapGetDeviceList();
+*/
+typedef struct _AirpcapDeviceDescription
+{
+ struct _AirpcapDeviceDescription *next; /* < Next element in the list */
+ gchar * Name; /* < Device name */
+ gchar * Description; /* < Device description */
+} AirpcapDeviceDescription, *PAirpcapDeviceDescription;
+
+#define MAX_ENCRYPTION_KEYS 64
+
+#define WEP_KEY_MAX_SIZE 32 /* < Maximum size of a WEP key, in bytes. This is the size of an entry in the
+ < AirpcapWepKeysCollection structure. */
+
+#ifdef _WIN32
+#ifndef __MINGW32__
+#pragma pack(push)
+#pragma pack(1)
+#endif
+#endif
+
+#define AIRPCAP_KEYTYPE_WEP 0 /* < Key type: WEP. The key can have an arbitrary length smaller than 32 bytes. */
+#define AIRPCAP_KEYTYPE_TKIP 1 /* < Key type: TKIP (WPA). NOT SUPPORTED YET. */
+#define AIRPCAP_KEYTYPE_CCMP 2 /* < Key type: CCMP (WPA2). NOT SUPPORTED YET. */
+
+/*!
+ \brief WEP key container
+*/
+typedef struct _AirpcapKey
+{
+ guint KeyType; /* < Type of key, can be on of: \ref AIRPCAP_KEYTYPE_WEP, \ref AIRPCAP_KEYTYPE_TKIP, \ref AIRPCAP_KEYTYPE_CCMP. Only AIRPCAP_KEYTYPE_WEP is supported by the driver at the moment. */
+ guint KeyLen; /* < Length of the key, in bytes */
+ guint8 KeyData[WEP_KEY_MAX_SIZE]; /* < Key Data */
+}
+#ifdef __MINGW32__
+__attribute__((__packed__))
+#endif
+AirpcapKey, *PAirpcapKey;
+
+/*!
+ \brief frequency Band.
+ 802.11 adapters can support different frequency bands, the most important of which are: 2.4GHz (802.11b/g/n)
+ and 5GHz (802.11a/n).
+*/
+typedef enum _AirpcapChannelBand
+{
+ AIRPCAP_CB_AUTO = 1, /* < Automatically pick the best frequency band */
+ AIRPCAP_CB_2_4_GHZ = 2, /* < 2.4 GHz frequency band */
+ AIRPCAP_CB_4_GHZ = 4, /* < 4 GHz frequency band */
+ AIRPCAP_CB_5_GHZ = 5 /* < 5 GHz frequency band */
+}AirpcapChannelBand, *PAirpcapChannelBand;
+
+/*!
+ \brief Type of frame validation the adapter performs.
+ An adapter can be instructed to accept different kind of frames: correct frames only, frames with wrong Frame Check Sequence (FCS) only, all frames.
+*/
+typedef enum _AirpcapValidationType
+{
+ AIRPCAP_VT_ACCEPT_EVERYTHING = 1, /* < Accept all the frames the device captures */
+ AIRPCAP_VT_ACCEPT_CORRECT_FRAMES = 2, /* < Accept correct frames only, i.e. frames with correct Frame Check Sequence (FCS). */
+ AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES = 3, /* < Accept corrupt frames only, i.e. frames with wrong Frame Check Sequence (FCS). */
+ AIRPCAP_VT_UNKNOWN = 4 /* < Unknown validation type. You should see it only in case of error. */
+}AirpcapValidationType, *PAirpcapValidationType;
+
+/*!
+ \brief Type of decryption the adapter performs.
+ An adapter can be instructed to turn decryption (based on the device-configured keys configured
+ with \ref AirpcapSetDeviceKeys()) on or off.
+*/
+typedef enum _AirpcapDecryptionState
+{
+ AIRPCAP_DECRYPTION_ON = 1, /* < This adapter performs decryption */
+ AIRPCAP_DECRYPTION_OFF = 2 /* < This adapter does not perform decryption */
+}AirpcapDecryptionState, *PAirpcapDecryptionState;
+
+
+/*!
+ \brief Storage for a MAC address
+*/
+typedef struct _AirpcapMacAddress
+{
+ guint8 Address[6]; /* < MAC address bytes */
+}
+#ifdef __MINGW32__
+__attribute__((__packed__))
+#endif
+AirpcapMacAddress, *PAirpcapMacAddress;
+
+/*!
+ \brief This structure is used to store a collection of WEP keys.
+ Note that the definition of the structure has one key in it
+ (so that this code can be compiled by compilers that don't
+ support zero-length arrays), so be careful to allocate a buffer
+ with the size of the set of keys, as per the following example:
+
+ \code
+ PAirpcapKeysCollection KeysCollection;
+ guint KeysCollectionSize;
+
+ KeysCollectionSize = AirpcapKeysCollectionSize(NumKeys);
+
+ KeysCollection = (PAirpcapKeysCollection)malloc(KeysCollectionSize);
+ if(!KeysCollection)
+ {
+ Error
+ }
+ \endcode
+*/
+typedef struct _AirpcapKeysCollection
+{
+ guint nKeys; /* < Number of keys in the collection */
+ AirpcapKey Keys[1]; /* < Array of nKeys keys. */
+} AirpcapKeysCollection, *PAirpcapKeysCollection;
+
+#define AirpcapKeysCollectionSize(nKeys) \
+ ((sizeof(AirpcapKeysCollection) - sizeof(AirpcapKey)) + ((nKeys) * sizeof(AirpcapKey)))
+#define AirpcapKeysCollectionSizeToKeyCount(size) \
+ (guint)(((size) - AirpcapKeysCollectionSize(0))/sizeof(AirpcapKey))
+
+/*!
+ \brief Packet header.
+
+ This structure defines the BPF that precedes every packet delivered to the application.
+*/
+typedef struct _AirpcapBpfHeader
+{
+ guint TsSec; /* < Timestamp associated with the captured packet. SECONDS. */
+ guint TsUsec; /* < Timestamp associated with the captured packet. MICROSECONDS. */
+ guint Caplen; /* < Length of captured portion. The captured portion <b>can be different</b> from the original packet, because it is possible (with a proper filter) to instruct the driver to capture only a portion of the packets. */
+ guint Originallen; /* < Original length of packet */
+ guint16 Hdrlen; /* < Length of bpf header (this struct plus alignment padding). In some cases, a padding could be added between the end of this structure and the packet data for performance reasons. This field can be used to retrieve the actual data of the packet. */
+}
+#ifdef __MINGW32__
+__attribute__((__packed__))
+#endif
+AirpcapBpfHeader, *PAirpcapBpfHeader;
+
+/* Helper macros to extract packets coming from the driver. Rounds up to the next even multiple of AIRPCAP_ALIGNMENT. */
+#define AIRPCAP_ALIGNMENT sizeof(int)
+#define AIRPCAP_WORDALIGN(x) (((x)+(AIRPCAP_ALIGNMENT-1))&~(AIRPCAP_ALIGNMENT-1))
+
+#ifdef _WIN32
+#ifndef __MINGW32__
+#pragma pack(pop)
+#endif
+#endif
+
+#define AIRPCAP_ERRBUF_SIZE 512 /* < Size of the error buffer, in bytes */
+
+#ifndef __AIRPCAP_DRIVER__
+
+/*!
+ \brief Link type.
+ AirPcap supports two kind of 802.11 linktypes: plain 802.11 and radiotap.
+*/
+#undef _AirpcapLinkType
+typedef enum _AirpcapLinkType
+{
+ AIRPCAP_LT_802_11 = 1, /* < plain 802.11 linktype. Every packet in the buffer contains the raw 802.11 frame, including MAC FCS. */
+ AIRPCAP_LT_802_11_PLUS_RADIO = 2, /* < 802.11 plus radiotap linktype. Every packet in the buffer contains a radiotap header followed by the 802.11 frame. MAC FCS is included. */
+ AIRPCAP_LT_UNKNOWN = 3, /* < Unknown linktype. You should see it only in case of error. */
+ AIRPCAP_LT_802_11_PLUS_PPI = 4 /* < 802.11 plus PPI header linktype. Every packet in the buffer contains a PPI header followed by the 802.11 frame. MAC FCS is included. */
+}AirpcapLinkType, *PAirpcapLinkType;
+
+#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_)
+#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_
+/*!
+ \brief Adapter handle.
+*/
+typedef struct _AirpcapHandle AirpcapHandle, *PAirpcapHandle;
+#endif
+
+/*!
+ \brief Capture statistics.
+ Returned by \ref AirpcapGetStats();
+*/
+typedef struct _AirpcapStats
+{
+ guint Recvs; /* < Number of packets that the driver received by the adapter */
+ /* < from the beginning of the current capture. This value includes the packets */
+ /* < dropped because of buffer full. */
+ guint Drops; /* < number of packets that the driver dropped from the beginning of a capture. */
+ /* < A packet is lost when the the buffer of the driver is full. */
+ guint IfDrops; /* < Packets dropped by the card before going to the USB bus. */
+ /* < Not supported at the moment. */
+ guint Capt; /* < number of packets that pass the BPF filter, find place in the kernel buffer and */
+ /* < therefore reach the application. */
+}AirpcapStats, *PAirpcapStats;
+
+/*!
+ \brief Channel information.
+ Used by \ref AirpcapSetDeviceChannelEx(), \ref AirpcapGetDeviceChannelEx(), \ref AirpcapGetDeviceSupportedChannels()
+*/
+typedef struct _AirpcapChannelInfo
+{
+ guint Frequency; /* < Channel frequency, in MHz. */
+ /*!
+ \brief 802.11n specific. Offset of the extension channel in case of 40MHz channels.
+
+ Possible values are -1, 0 +1:
+ - -1 means that the extension channel should be below the control channel (e.g. Control = 5 and Extension = 1)
+ - 0 means that no extension channel should be used (20MHz channels or legacy mode)
+ - +1 means that the extension channel should be above the control channel (e.g. Control = 1 and Extension = 5)
+
+ In case of 802.11a/b/g channels (802.11n legacy mode), this field should be set to 0.
+ */
+ gint8 ExtChannel;
+ guint8 Reserved[3]; /* < Reserved. It should be set to {0,0,0}. */
+}
+ AirpcapChannelInfo, *PAirpcapChannelInfo;
+
+
+/*@}*/
+
+/** @defgroup airpcapfuncs AirPcap functions
+ * @{
+ */
+
+/*!
+ \brief Return a string with the API version
+ \param VersionMajor Pointer to a variable that will be filled with the major version number.
+ \param VersionMinor Pointer to a variable that will be filled with the minor version number.
+ \param VersionRev Pointer to a variable that will be filled with the revision number.
+ \param VersionBuild Pointer to a variable that will be filled with the build number.
+*/
+void AirpcapGetVersion(guint * VersionMajor, guint * VersionMinor, guint * VersionRev, guint * VersionBuild);
+
+/*!
+ \brief Return the last error related to the specified handle
+ \param AdapterHandle Handle to an open adapter.
+ \return The string with the last error.
+*/
+gchar * AirpcapGetLastError(PAirpcapHandle AdapterHandle);
+
+/*!
+ \brief Return the list of available devices
+ \param PPAllDevs Address to a caller allocated pointer. On success this pointer will receive the head of a list of available devices.
+ \param Ebuf String that will contain error information if FALSE is returned. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes.
+ \return TRUE on success. FALSE is returned on failure, in which case Ebuf is filled in with an appropriate error message.
+
+ Here's a snippet of code that shows how to use AirpcapGetDeviceList():
+
+ \code
+ gchar Ebuf[AIRPCAP_ERRBUF_SIZE];
+ AirpcapDeviceDescription *Desc, *tDesc;
+
+ if(AirpcapGetDeviceList(&Desc, Ebuf) == -1)
+ {
+ printf("Unable to get the list of devices: %s\n", Ebuf);
+ return -1;
+ }
+
+ for(tDesc = Desc; tDesc; tDesc = tDesc->next)
+ {
+ printf("%u) %s (%s)\n",
+ ++i,
+ tDesc->Name,
+ tDesc->Description);
+ }
+
+ AirpcapFreeDeviceList(Desc);
+ \endcode
+*/
+gboolean AirpcapGetDeviceList(PAirpcapDeviceDescription *PPAllDevs, gchar * Ebuf);
+
+/*!
+ \brief Free a list of devices returned by AirpcapGetDeviceList()
+ \param PAllDevs Head of the list of devices returned by \ref AirpcapGetDeviceList().
+*/
+void AirpcapFreeDeviceList(PAirpcapDeviceDescription PAllDevs);
+
+/*!
+ \brief Open an adapter
+ \param DeviceName Name of the device to open. Use \ref AirpcapGetDeviceList() to get the list of devices.
+ \param Ebuf String that will contain error information in case of failure. The size of the string must be AIRPCAP_ERRBUF_SIZE bytes.
+ \return A PAirpcapHandle handle on success. NULL is returned on failure, in which case Ebuf is filled in with an appropriate error message.
+*/
+PAirpcapHandle AirpcapOpen(gchar * DeviceName, gchar * Ebuf);
+
+/*!
+ \brief Close an adapter
+ \param AdapterHandle Handle to the adapter to close.
+*/
+void AirpcapClose(PAirpcapHandle AdapterHandle);
+
+/*!
+ \brief Sets the monitor mode for the specified adapter
+ \param AdapterHandle Handle to the adapter.
+ \param MonitorModeEnabled If TRUE, the adapter will be put in monitor mode. If FALSE, the adapter will be configured
+ for normal operation.
+ \return TRUE on success.
+
+ When monitor mode is on, the adapter captures all the packets transmitted on the channel. This includes:
+
+ - unicast packets
+ - multicast packets
+ - broadcast packets
+ - control and management packets
+
+ When monitor mode is off, the adapter has a filter on unicast packets to capture only the packets whose MAC
+ destination address equals to the adapter's address. This means the following frames will be received:
+
+ - unicast packets with the address of the adapter
+ - multicast packets
+ - broadcast packets
+ - beacons and probe requests
+
+ The main reason to turn monitor mode off is that, when not in monitor mode, the adapter will acknowledge the
+ data frames sent to its address. This is useful when the adapter needs to interact with other devices on the
+ 802.11 network, because handling the ACKs in software is too slow.
+
+ \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode
+ configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it
+ every time you open the adapter.
+*/
+gboolean AirpcapSetMonitorMode(PAirpcapHandle AdapterHandle, gboolean MonitorModeEnabled);
+
+/*!
+ \brief Returns TRUE if the specified adapter is in monitor mode.
+ \param AdapterHandle Handle to the adapter.
+ \param PMonitorModeEnabled User-provided variable that will be set to true if the adapter is in monitor mode.
+ \return TRUE if the operation is successful. FALSE otherwise.
+
+ \note When an adapter is plugged into the system, it's always configured with monitor mode ON. The monitor mode
+ configuration is not stored persistently, so if you want to turn monitor mode off, you will need to do it
+ every time you open the adapter.
+*/
+gboolean AirpcapGetMonitorMode(PAirpcapHandle AdapterHandle, gboolean * PMonitorModeEnabled);
+
+/*!
+ \brief Set the link type of an adapter
+ \param AdapterHandle Handle to the adapter.
+ \param NewLinkType the "link type", i.e. the format of the frames that will be received from the adapter.
+ \return TRUE on success.
+
+ the "link type" determines how the driver will encode the packets captured from the network.
+ Aircap supports two link types:
+ - AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any
+ power information. Look at the Capture_no_radio example application in the developer's pack
+ for a reference on how to decode 802.11 frames with this link type.
+ - AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header
+ that contains power and channel information. More information about the radiotap header can be found in the
+ radiotap section. Moreover, the "Capture_radio" example application in
+ the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers.
+ - AIRPCAP_LT_802_11_PLUS_PPI, to capture 802.11 frames (including control frames) with a Per Packet Information (PPI)
+ header that contains per-packet meta information like channel and power information. More details on the PPI header can
+ be found in the PPI online documentation (TODO).
+*/
+gboolean AirpcapSetLinkType(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType);
+
+/*!
+ \brief Get the link type of the specified adapter
+ \param AdapterHandle Handle to the adapter.
+ \param PLinkType Pointer to a caller allocated AirpcapLinkType variable that will contain the link type of the adapter.
+ \return TRUE on success.
+
+ the "link type" determines how the driver will encode the packets captured from the network.
+ Aircap supports two link types:
+ - AIRPCAP_LT_802_11, to capture 802.11 frames (including control frames) without any
+ power information. Look at the Capture_no_radio example application in the developer's pack
+ for a reference on how to decode 802.11 frames with this link type.
+ - AIRPCAP_LT_802_11_PLUS_RADIO, to capture 802.11 frames (including control frames) with a radiotap header
+ that contains power and channel information. More information about the radiotap header can be found int the
+ radiotap section. Moreover, the "Capture_radio" example application in
+ the developer's pack can be used as a reference on how to decode 802.11 frames with radiotap headers.
+*/
+gboolean AirpcapGetLinkType(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType);
+
+/*!
+ \brief Configures the adapter on whether to include the MAC Frame Check Sequence in the captured packets.
+ \param AdapterHandle Handle to the adapter.
+ \param IsFcsPresent TRUE if the packets should include the FCS. FALSE otherwise
+ \return TRUE on success.
+
+ In the default configuration, the adapter includes the FCS in the captured packets. The MAC Frame Check Sequence
+ is 4 bytes and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO
+ link types.
+ When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header
+ that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present
+ when FCS inclusion is off.
+*/
+gboolean AirpcapSetFcsPresence(PAirpcapHandle AdapterHandle, gboolean IsFcsPresent);
+
+/*!
+ \brief Returns TRUE if the specified adapter includes the MAC Frame Check Sequence in the captured packets
+ \param AdapterHandle Handle to the adapter.
+ \param PIsFcsPresent User-provided variable that will be set to true if the adapter is including the FCS.
+ \return TRUE if the operation is successful. FALSE otherwise.
+
+ In the default configuration, the adapter has FCS inclusion turned on. The MAC Frame Check Sequence is 4 bytes
+ and is located at the end of the 802.11 packet, with both AIRPCAP_LT_802_11 and AIRPCAP_LT_802_11_PLUS_RADIO
+ link types.
+ When the FCS inclusion is turned on, and if the link type is AIRPCAP_LT_802_11_PLUS_RADIO, the radiotap header
+ that precedes each frame has two additional fields at the end: Padding and FCS. These two fields are not present
+ when FCS inclusion is off.
+*/
+gboolean AirpcapGetFcsPresence(PAirpcapHandle AdapterHandle, gboolean * PIsFcsPresent);
+
+/*!
+ \brief Configures the adapter to accept or drop frames with an incorrect Frame Check sequence (FCS).
+ \param AdapterHandle Handle to the adapter.
+ \param ValidationType The type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details.
+ \return TRUE on success.
+
+ \note By default, the driver is configured in AIRPCAP_VT_ACCEPT_EVERYTHING mode.
+*/
+gboolean AirpcapSetFcsValidation(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType);
+
+/*!
+ \brief Checks if the specified adapter is configured to capture frames with incorrect an incorrect Frame Check Sequence (FCS).
+ \param AdapterHandle Handle to the adapter.
+ \param ValidationType Pointer to a user supplied variable that will contain the type of validation the driver will perform. See the documentation of \ref AirpcapValidationType for details.
+ \return TRUE if the operation is successful. FALSE otherwise.
+
+ \note By default, the driver is configured in AIRPCAP_VT_ACCEPT_EVERYTHING mode.
+*/
+gboolean AirpcapGetFcsValidation(PAirpcapHandle AdapterHandle, PAirpcapValidationType ValidationType);
+
+/*!
+ \brief Set the list of decryption keys that the driver is going to use with the specified device.
+ \param AdapterHandle Handle an open adapter instance.
+ \param KeysCollection Pointer to a PAirpcapKeysCollection structure that contains the keys to be set in the driver.
+ \return TRUE if the operation is successful. FALSE otherwise.
+
+ The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the
+ keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames
+ to the application.
+
+ This function allows to set the <b>adapter-specific</b> set of keys. These keys will be used by the specified adapter only,
+ and will not be used by other airpcap devices besides the specified one.
+
+ At this time, the only supported decryption method is WEP.
+
+ The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is
+ correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance.
+
+ \note: when you change the set of keys from an open capture instance, the change will be
+ immediately reflected on all the other capture instances.
+*/
+gboolean AirpcapSetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection);
+
+/*!
+ \brief Returns the list of decryption keys in the driver that are currently associated with the specified device
+ \param AdapterHandle Handle to an open adapter instance.
+ \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys.
+ \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes.
+ \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes.
+ \return TRUE if the operation is successful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero.
+ If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the
+ needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and
+ KeysCollectionSize will be zero.
+
+ This function returns the <b>adapter-specific</b> set of keys. These keys are used by the specified adapter only,
+ and not by other airpcap devices besides the specified one.
+
+ The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the
+ keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames
+ to the application.
+ The driver supports, for every device, multiple keys at the same time.
+
+ The configured decryption keys are device-specific, therefore AirpcapGetDeviceKeys() will return a different set of keys
+ when called on different devices.
+
+ At this time, the only supported decryption method is WEP.
+*/
+gboolean AirpcapGetDeviceKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, guint * PKeysCollectionSize);
+
+/*!
+ \brief Set the global list of decryption keys that the driver is going to use with all the devices.
+ \param AdapterHandle Handle an open adapter instance.
+ \param KeysCollection Pointer to a PAirpcapKeysCollection structure that contains the keys to be set in the driver.
+ \return TRUE if the operation is successful. FALSE otherwise.
+
+ The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the
+ keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames
+ to the application.
+
+ This function allows to set the <b>global driver</b> set of keys. These keys will be used by all the adapters plugged in
+ the machine.
+
+ At this time, the only supported decryption method is WEP.
+
+ The keys are applied to the packets in the same order they appear in the KeysCollection structure until the packet is
+ correctly decrypted, therefore putting frequently used keys at the beginning of the structure improves performance.
+
+ \note: when you change the set of keys from an open capture instance, the change will be
+ immediately reflected on all the other capture instances.
+*/
+gboolean AirpcapSetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection);
+
+/*!
+ \brief Returns the global list of decryption keys in the driver that are associated with all the devices.
+ \param AdapterHandle Handle to an open adapter instance.
+ \param KeysCollection User-allocated PAirpcapKeysCollection structure that will be filled with the keys.
+ \param PKeysCollectionSize \b IN: pointer to a user-allocated variable that contains the length of the KeysCollection structure, in bytes.
+ \b OUT: amount of data moved by the driver in the buffer pointed by KeysBuffer, in bytes.
+ \return TRUE if the operation is successful. If an error occurs, the return value is FALSE and KeysCollectionSize is zero.
+ If the provided buffer is too small to contain the keys, the return value is FALSE and KeysCollectionSize contains the
+ needed KeysCollection length, in bytes. If the device doesn't have any decryption key configured, the return value is TRUE, and
+ KeysCollectionSize will be zero.
+
+ This function returns the <b>global driver</b> set of keys. These keys will be used by all the adapters plugged in
+ the machine.
+
+ The AirPcap driver is able to use a set of decryption keys to decrypt the traffic transmitted on a specific SSID. If one of the
+ keys corresponds to the one the frame has been encrypted with, the driver will perform decryption and return the cleartext frames
+ to the application.
+
+ At this time, the only supported decryption method is WEP.
+*/
+gboolean AirpcapGetDriverKeys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, guint * PKeysCollectionSize);
+
+/*!
+ \brief Turns on or off the decryption of the incoming frames with the <b>adapter-specific</b> keys.
+ \param AdapterHandle Handle to the adapter.
+ \param Enable Either AIRPCAP_DECRYPTION_ON or AIRPCAP_DECRYPTION_OFF
+ \return TRUE on success.
+
+ The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function.
+ \note By default, the driver is configured with AIRPCAP_DECRYPTION_ON.
+*/
+gboolean AirpcapSetDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable);
+
+/*!
+ \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the <b>adapter-specific</b> keys.
+ \param AdapterHandle Handle to the adapter.
+ \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref _AirpcapDecryptionState for details.
+ \return TRUE if the operation is successful. FALSE otherwise.
+
+ The adapter-specific decryption keys can be configured with the \ref AirpcapSetDeviceKeys() function.
+ \note By default, the driver is configured with AIRPCAP_DECRYPTION_ON.
+*/
+gboolean AirpcapGetDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable);
+
+/*!
+ \brief Turns on or off the decryption of the incoming frames with the <b>global driver</b> set of keys.
+ \param AdapterHandle Handle to the adapter.
+ \param Enable Either AIRPCAP_DECRYPTION_ON or AIRPCAP_DECRYPTION_OFF
+ \return TRUE on success.
+
+ The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function.
+ \note By default, the driver is configured with AIRPCAP_DECRYPTION_ON.
+*/
+gboolean AirpcapSetDriverDecryptionState(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable);
+
+/*!
+ \brief Tells if this open instance is configured to perform the decryption of the incoming frames with the <b>global driver</b> set of keys.
+ \param AdapterHandle Handle to the adapter.
+ \param PEnable Pointer to a user supplied variable that will contain the decryption configuration. See \ref _AirpcapDecryptionState for details.
+ \return TRUE if the operation is successful. FALSE otherwise.
+
+ The global decryption keys can be configured with the \ref AirpcapSetDriverKeys() function.
+ \note By default, the driver is configured with AIRPCAP_DECRYPTION_ON.
+*/
+gboolean AirpcapGetDriverDecryptionState(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable);
+
+/*!
+ \brief Set the radio channel of a device
+ \param AdapterHandle Handle to the adapter.
+ \param Channel the new channel to set.
+ \return TRUE on success.
+
+ The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6.
+
+ \note this is a device-related function: when you change the channel from an open capture instance, the change will be
+ immediately reflected on all the other capture instances.
+*/
+gboolean AirpcapSetDeviceChannel(PAirpcapHandle AdapterHandle, guint Channel);
+
+/*!
+ \brief Get the radio channel of a device
+ \param AdapterHandle Handle to the adapter.
+ \param PChannel Pointer to a user-supplied variable into which the function will copy the currently configured radio channel.
+ \return TRUE on success.
+
+ The list of available channels can be retrieved with \ref AirpcapGetDeviceSupportedChannels(). The default channel setting is 6.
+
+ \note this is a device-related function: when you change the channel from an open capture instance, the change will be
+ immediately reflected on all the other capture instances.
+*/
+gboolean AirpcapGetDeviceChannel(PAirpcapHandle AdapterHandle, guint * PChannel);
+
+/*!
+ \brief Set the size of the kernel packet buffer for this adapter
+ \param AdapterHandle Handle to the adapter.
+ \param BufferSize New size, in bytes.
+ \return TRUE on success.
+
+ Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte.
+ This function can be used to change the size of this buffer, and can be called at any time.
+ A bigger kernel buffer size decreases the risk of dropping packets during network bursts or when the
+ application is busy, at the cost of higher kernel memory usage.
+
+ \note don't use this function unless you know what you are doing. Due to caching issues and bigger non-paged
+ memory consumption, bigger buffer sizes can decrease the capture performance instead of improving it.
+*/
+gboolean AirpcapSetKernelBuffer(PAirpcapHandle AdapterHandle, guint BufferSize);
+
+/*!
+ \brief Get the size of the kernel packet buffer for this adapter
+ \param AdapterHandle Handle to the adapter.
+ \param PSizeBytes User-allocated variable that will be filled with the size of the kernel buffer.
+ \return TRUE on success.
+
+ Every AirPcap open instance has an associated kernel buffer, whose default size is 1 Mbyte.
+ This function can be used to get the size of this buffer.
+*/
+gboolean AirpcapGetKernelBufferSize(PAirpcapHandle AdapterHandle, guint * PSizeBytes);
+
+/*!
+ \brief Saves the configuration of the specified adapter in the registry, so that it becomes the default for this adapter.
+ \param AdapterHandle Handle to the adapter.
+ \return TRUE on success. FALSE on failure.
+
+ Almost all the AirPcap calls that modify the configuration (\ref AirpcapSetLinkType(), \ref AirpcapSetFcsPresence(),
+ \ref AirpcapSetFcsValidation(), \ref AirpcapSetKernelBuffer(), \ref AirpcapSetMinToCopy())
+ affect only the referenced AirPcap open instance. This means that if you do another \ref AirpcapOpen() on the same
+ adapter, the configuration changes will not be remembered, and the new adapter handle will have default configuration
+ settings.
+
+ Exceptions to this rule are the \ref AirpcapSetDeviceChannel() and \ref AirpcapSetDeviceKeys() functions: a channel change is
+ reflected on all the open instances, and remembered until the next call to \ref AirpcapSetDeviceChannel(), until the adapter
+ is unplugged, or until the machine is powered off. Same thing for the configuration of the WEP keys.
+
+ AirpcapStoreCurConfigAsAdapterDefault() stores the configuration of the give open instance as the default for the adapter:
+ all the instances opened in the future will have the same configuration that this adapter currently has.
+ The configuration is stored in the registry, therefore it is remembered even when the adapter is unplugged or the
+ machine is turned off. However, an adapter doesn't bring its configuration with it from machine to machine.
+
+ the configuration information saved in the registry includes the following parameters:
+ - channel
+ - kernel buffer size
+ - mintocopy
+ - link type
+ - CRC presence
+ - Encryption keys
+ - Encryption Enabled/Disabled state
+
+ The configuration is adapter-specific. This means that changing the configuration of an adapter
+ doesn't modify the one of the other adapters that are currently used or that will be used in the future.
+
+ \note AirpcapStoreCurConfigAsAdapterDefault() must have exclusive access to the adapter -- it
+ will fail if more than one AirPcap handle is opened at the same time for this adapter.
+ AirpcapStoreCurConfigAsAdapterDefault() needs administrator privileges. It will fail if the calling user
+ is not a local machine administrator.
+*/
+gboolean AirpcapStoreCurConfigAsAdapterDefault(PAirpcapHandle AdapterHandle);
+
+/*!
+ \brief Set the BPF kernel filter for an adapter
+ \param AdapterHandle Handle to the adapter.
+ \param Instructions pointer to the first BPF instruction in the array. Corresponds to the bf_insns
+ in a bpf_program structure (see the WinPcap documentation at https://www.winpcap.org/devel.htm).
+ \param Len Number of instructions in the array pointed by the previous field. Corresponds to the bf_len in
+ a a bpf_program structure (see the WinPcap documentation at https://www.winpcap.org/devel.htm).
+ \return TRUE on success.
+
+ The AirPcap driver is able to perform kernel-level filtering using the standard BPF pseudo-machine format. You can read
+ the WinPcap documentation at https://www.winpcap.org/devel.htm for more details on the BPF filtering mechanism.
+
+ A filter can be automatically created by using the pcap_compile() function of the WinPcap API. This function
+ converts a human readable text expression with the tcpdump/libpcap syntax into a BPF program.
+ If your program doesn't link wpcap, but you need to generate the code for a particular filter, you can run WinDump
+ with the -d or -dd or -ddd flags to obtain the pseudocode.
+
+*/
+gboolean AirpcapSetFilter(PAirpcapHandle AdapterHandle, void * Instructions, guint Len);
+
+/*!
+ \brief Return the MAC address of an adapter.
+ \param AdapterHandle Handle to the adapter.
+ \param PMacAddress Pointer to a user allocated MAC address.
+ The size of this buffer needs to be at least 6 bytes.
+ \return TRUE on success.
+*/
+gboolean AirpcapGetMacAddress(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress);
+
+/*!
+ \brief Set the mintocopy parameter for an open adapter
+ \param AdapterHandle Handle to the adapter.
+ \param MinToCopy is the mintocopy size in bytes.
+ \return TRUE on success.
+
+ When the number of bytes in the kernel buffer changes from less than mintocopy bytes to greater than or equal to mintocopy bytes,
+ the read event is signalled (see \ref AirpcapGetReadEvent()). A high value for mintocopy results in poor responsiveness since the
+ driver may signal the application "long" after the arrival of the packet. And a high value results in low CPU loading
+ by minimizing the number of user/kernel context switches.
+ A low MinToCopy results in good responsiveness since the driver will signal the application close to the arrival time of
+ the packet. This has higher CPU loading over the first approach.
+*/
+gboolean AirpcapSetMinToCopy(PAirpcapHandle AdapterHandle, guint MinToCopy);
+
+/*!
+ \brief Gets an event that is signaled when that is signalled when packets are available in the kernel buffer (see \ref AirpcapSetMinToCopy()).
+ \param AdapterHandle Handle to the adapter.
+ \param PReadEvent Pointer to a user-supplied handle that in which the read event will be copied.
+ \return TRUE on success.
+
+ \note the event is signalled when at least mintocopy bytes are present in the kernel buffer (see \ref AirpcapSetMinToCopy()).
+ This event can be used by WaitForSingleObject() and WaitForMultipleObjects() to create blocking behavior when reading
+ packets from one or more adapters (see \ref AirpcapRead()).
+*/
+gboolean AirpcapGetReadEvent(PAirpcapHandle AdapterHandle, void *** PReadEvent);
+
+/*!
+ \brief Fills a user-provided buffer with zero or more packets that have been captured on the referenced adapter.
+ \param AdapterHandle Handle to the adapter.
+ \param Buffer pointer to the buffer that will be filled with captured packets.
+ \param BufSize size of the input buffer that will contain the packets, in bytes.
+ \param PReceievedBytes Pointer to a user supplied variable that will receive the number of bytes copied by AirpcapRead.
+ Can be smaller than BufSize.
+ \return TRUE on success.
+
+ 802.11 frames are returned by the driver in buffers. Every 802.11 frame in the buffer is preceded by a \ref AirpcapBpfHeader structure.
+ The suggested way to use an AirPcap adapter is through the pcap API exported by wpcap.dll. If this is not
+ possible, the Capture_radio and Capture_no_radio examples in the AirPcap developer's pack show how to properly decode the
+ packets in the read buffer returned by AirpcapRead().
+
+ \note this function is NOT blocking. Blocking behavior can be obtained using the event returned
+ by \ref AirpcapGetReadEvent(). See also \ref AirpcapSetMinToCopy().
+*/
+gboolean AirpcapRead(PAirpcapHandle AdapterHandle, guint8 * Buffer, guint BufSize, guint * PReceievedBytes);
+
+/*!
+ \brief Transmits a packet.
+ \param AdapterHandle Handle to the adapter.
+ \param TxPacket Pointer to a buffer that contains the packet to be transmitted.
+ \param PacketLen Length of the buffer pointed by the TxPacket argument, in bytes.
+ \return TRUE on success.
+
+ The packet will be transmitted on the channel the device is currently set. To change the device adapter, use the
+ \ref AirpcapSetDeviceChannel() function.
+
+ If the linktype of the adapter is AIRPCAP_LT_802_11, the buffer pointed by TxPacket should contain just the 802.11
+ packet, without additional information. The packet will be transmitted at 1Mbps.
+
+ If the linktype of the adapter is AIRPCAP_LT_802_11_PLUS_RADIO, the buffer pointed by TxPacket should contain a radiotap
+ header followed by the 802.11 packet. AirpcapWrite will use the rate information in the radiotap header when
+ transmitting the packet.
+*/
+gboolean AirpcapWrite(PAirpcapHandle AdapterHandle, gchar * TxPacket, guint32 PacketLen);
+
+/*!
+ \brief Get per-adapter WinPcap-compatible capture statistics.
+ \param AdapterHandle Handle to the adapter.
+ \param PStats pointer to a user-allocated AirpcapStats structure that will be filled with statistical information.
+ \return TRUE on success.
+*/
+gboolean AirpcapGetStats(PAirpcapHandle AdapterHandle, PAirpcapStats PStats);
+
+/*!
+ \brief Get the number of LEDs the referenced adapter has available.
+ \param AdapterHandle Handle to the adapter.
+ \param NumberOfLeds Number of LEDs available on this adapter.
+ \return TRUE on success.
+*/
+gboolean AirpcapGetLedsNumber(PAirpcapHandle AdapterHandle, guint * NumberOfLeds);
+
+/*!
+ \brief Turn on one of the adapter's LEDs.
+ \param AdapterHandle Handle to the adapter.
+ \param LedNumber zero-based identifier of the LED to turn on.
+ \return TRUE on success.
+*/
+gboolean AirpcapTurnLedOn(PAirpcapHandle AdapterHandle, guint LedNumber);
+
+/*!
+ \brief Turn off one of the adapter's LEDs.
+ \param AdapterHandle Handle to the adapter.
+ \param LedNumber zero-based identifier of the LED to turn off.
+ \return TRUE on success.
+*/
+gboolean AirpcapTurnLedOff(PAirpcapHandle AdapterHandle, guint LedNumber);
+
+/*!
+ \brief Set the channel of a device through its radio frequency. In case of 802.11n enabled devices, it sets the extension channel, if used.
+ \param AdapterHandle Handle to the adapter.
+ \param ChannelInfo The new channel information to set.
+ \return TRUE on success.
+
+ \note this is a device-related function: when you change the channel from an open capture instance, the change will be
+ immediately reflected on all the other capture instances.
+*/
+gboolean AirpcapSetDeviceChannelEx(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo);
+
+/*!
+ \brief Get the channel of a device through its radiofrequency. In case of 802.11n enabled devices, it gets the extension channel, if in use.
+ \param AdapterHandle Handle to the adapter.
+ \param PChannelInfo Pointer to a user-supplied variable into which the function will copy the currently configured channel information.
+ \return TRUE on success.
+
+ \note this is a device-related function: when you change the channel from an open capture instance, the change will be
+ immediately reflected on all the other capture instances.
+*/
+gboolean AirpcapGetDeviceChannelEx(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo);
+
+/*!
+ \brief Get the list of supported channels for a given device. In case of a 802.11n capable device, information related to supported extension channels is also reported.
+
+ Every control channel is listed multiple times, one for each different supported extension channel. For example channel 6 (2437MHz) is usually listed three times:
+ - <b>Frequency 2437 Extension +1</b>. Control channel is 6, extension channel is 10.
+ - <b>Frequency 2437 Extension 0</b>. Control channel is 6, no extension channel is used (20MHz channel and legacy mode).
+ - <b>Frequency 2437 Extension -1</b>. Control channel is 6, extension channel is 2.
+ \param AdapterHandle Handle to the adapter.
+ \param ppChannelInfo Pointer to a user-supplied variable that will point to an array of supported channel. Such list must not be freed by the caller
+ \param pNumChannelInfo Number of channels returned in the array.
+ \return TRUE on success.
+
+ \note The supported channels are not listed in any specific order.
+*/
+gboolean AirpcapGetDeviceSupportedChannels(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo *ppChannelInfo, guint * pNumChannelInfo);
+
+/*!
+ \brief Converts a given frequency to the corresponding channel.
+
+ \param Frequency Frequency of the channel, in MHz.
+ \param PChannel Pointer to a user-supplied variable that will contain the channel number on success.
+ \param PBand Pointer to a user-supplied variable that will contain the band (a or b/g) of the given channel.
+ \return TRUE on success, i.e. the frequency corresponds to a valid a or b/g channel.
+*/
+gboolean AirpcapConvertFrequencyToChannel(guint Frequency, guint * PChannel, PAirpcapChannelBand PBand);
+
+/*!
+ \brief Converts a given channel to the corresponding frequency.
+
+ \param Channel Channel number to be converted.
+ \param PFrequency Pointer to a user-supplied variable that will contain the channel frequency in MHz on success.
+ \return TRUE on success, i.e. the given channel number exists.
+*/
+gboolean AirpcapConvertChannelToFrequency(guint Channel, guint * PFrequency);
+
+
+/*@}*/
+
+#endif /* __AIRPCAP_DRIVER__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(AIRPCAP_H__EAE405F5_0171_9592_B3C2_C19EC426AD34__INCLUDED_) */
diff --git a/capture/airpcap_loader.c b/capture/airpcap_loader.c
new file mode 100644
index 0000000000..4e83953fdb
--- /dev/null
+++ b/capture/airpcap_loader.c
@@ -0,0 +1,1230 @@
+/* airpcap_loader.c
+ *
+ * Giorgio Tino <giorgio.tino@cacetech.com>
+ * Copyright (c) CACE Technologies, LLC 2006
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2000 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <glib.h>
+
+#include <epan/crypt/dot11decrypt_ws.h>
+#include <epan/strutil.h>
+#include <wsutil/file_util.h>
+#include <wsutil/802_11-utils.h>
+
+#include <capture/airpcap.h>
+#include <capture/airpcap_loader.h>
+
+
+/*
+ * Set to TRUE if the DLL was successfully loaded AND all functions
+ * are present.
+ */
+static gboolean AirpcapLoaded = FALSE;
+
+#ifdef _WIN32
+/*
+ * We load dynamically the dag library in order link it only when
+ * it's present on the system
+ */
+static void * AirpcapLib = NULL;
+
+static AirpcapGetLastErrorHandler g_PAirpcapGetLastError;
+static AirpcapSetKernelBufferHandler g_PAirpcapSetKernelBuffer;
+static AirpcapSetFilterHandler g_PAirpcapSetFilter;
+static AirpcapGetMacAddressHandler g_PAirpcapGetMacAddress;
+static AirpcapSetMinToCopyHandler g_PAirpcapSetMinToCopy;
+static AirpcapGetReadEventHandler g_PAirpcapGetReadEvent;
+static AirpcapReadHandler g_PAirpcapRead;
+static AirpcapGetStatsHandler g_PAirpcapGetStats;
+#endif
+
+static int AirpcapVersion = 3;
+
+static AirpcapGetDeviceListHandler g_PAirpcapGetDeviceList;
+static AirpcapFreeDeviceListHandler g_PAirpcapFreeDeviceList;
+static AirpcapOpenHandler g_PAirpcapOpen;
+static AirpcapCloseHandler g_PAirpcapClose;
+static AirpcapGetLinkTypeHandler g_PAirpcapGetLinkType;
+static AirpcapSetLinkTypeHandler g_PAirpcapSetLinkType;
+static AirpcapTurnLedOnHandler g_PAirpcapTurnLedOn;
+static AirpcapTurnLedOffHandler g_PAirpcapTurnLedOff;
+static AirpcapGetDeviceChannelHandler g_PAirpcapGetDeviceChannel;
+static AirpcapSetDeviceChannelHandler g_PAirpcapSetDeviceChannel;
+static AirpcapGetFcsPresenceHandler g_PAirpcapGetFcsPresence;
+static AirpcapSetFcsPresenceHandler g_PAirpcapSetFcsPresence;
+static AirpcapGetFcsValidationHandler g_PAirpcapGetFcsValidation;
+static AirpcapSetFcsValidationHandler g_PAirpcapSetFcsValidation;
+static AirpcapGetDeviceKeysHandler g_PAirpcapGetDeviceKeys;
+static AirpcapSetDeviceKeysHandler g_PAirpcapSetDeviceKeys;
+static AirpcapGetDriverKeysHandler g_PAirpcapGetDriverKeys;
+static AirpcapSetDriverKeysHandler g_PAirpcapSetDriverKeys;
+static AirpcapGetDecryptionStateHandler g_PAirpcapGetDecryptionState;
+static AirpcapSetDecryptionStateHandler g_PAirpcapSetDecryptionState;
+static AirpcapGetDriverDecryptionStateHandler g_PAirpcapGetDriverDecryptionState;
+static AirpcapSetDriverDecryptionStateHandler g_PAirpcapSetDriverDecryptionState;
+static AirpcapStoreCurConfigAsAdapterDefaultHandler g_PAirpcapStoreCurConfigAsAdapterDefault;
+static AirpcapGetVersionHandler g_PAirpcapGetVersion;
+static AirpcapSetDeviceChannelExHandler g_PAirpcapSetDeviceChannelEx;
+static AirpcapGetDeviceChannelExHandler g_PAirpcapGetDeviceChannelEx;
+static AirpcapGetDeviceSupportedChannelsHandler g_PAirpcapGetDeviceSupportedChannels;
+
+/* Airpcap interface list */
+GList *g_airpcap_if_list = NULL;
+
+/* Airpcap current selected interface */
+airpcap_if_info_t *airpcap_if_selected = NULL;
+
+/* Airpcap current active interface */
+airpcap_if_info_t *airpcap_if_active = NULL;
+
+Dot11Channel *pSupportedChannels;
+guint numSupportedChannels;
+
+static AirpcapChannelInfo LegacyChannels[] =
+{
+ {2412, 0, {0,0,0}},
+ {2417, 0, {0,0,0}},
+ {2422, 0, {0,0,0}},
+ {2427, 0, {0,0,0}},
+ {2432, 0, {0,0,0}},
+ {2437, 0, {0,0,0}},
+ {2442, 0, {0,0,0}},
+ {2447, 0, {0,0,0}},
+ {2452, 0, {0,0,0}},
+ {2457, 0, {0,0,0}},
+ {2462, 0, {0,0,0}},
+ {2467, 0, {0,0,0}},
+ {2472, 0, {0,0,0}},
+ {2484, 0, {0,0,0}},
+};
+
+static guint num_legacy_channels = 14;
+
+/*
+ * Get an error message string for a CANT_GET_INTERFACE_LIST error from
+ * "get_airpcap_interface_list()".
+ */
+static gchar *
+cant_get_airpcap_if_list_error_message(const char *err_str)
+{
+ return g_strdup_printf("Can't get list of Wireless interfaces: %s", err_str);
+}
+
+/*
+ * Airpcap wrapper, used to store the current settings for the selected adapter
+ */
+gboolean
+airpcap_if_store_cur_config_as_adapter_default(PAirpcapHandle ah)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapStoreCurConfigAsAdapterDefault(ah);
+}
+
+/*
+ * Airpcap wrapper, used to open an airpcap adapter
+ */
+PAirpcapHandle
+airpcap_if_open(gchar * name, gchar * err)
+{
+ if (!AirpcapLoaded) return NULL;
+ if (name == NULL) return NULL;
+ return g_PAirpcapOpen(name,err);
+}
+
+/*
+ * Airpcap wrapper, used to close an airpcap adapter
+ */
+void
+airpcap_if_close(PAirpcapHandle handle)
+{
+ if (!AirpcapLoaded) return;
+ g_PAirpcapClose(handle);
+}
+
+/*
+ * Retrieve the state of the Airpcap DLL
+ */
+int
+airpcap_get_dll_state(void)
+{
+ return AirpcapVersion;
+}
+
+/*
+ * Airpcap wrapper, used to turn on the led of an airpcap adapter
+ */
+gboolean
+airpcap_if_turn_led_on(PAirpcapHandle AdapterHandle, guint LedNumber)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapTurnLedOn(AdapterHandle,LedNumber);
+}
+
+/*
+ * Airpcap wrapper, used to turn off the led of an airpcap adapter
+ */
+gboolean
+airpcap_if_turn_led_off(PAirpcapHandle AdapterHandle, guint LedNumber)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapTurnLedOff(AdapterHandle,LedNumber);
+}
+
+/*
+ * Airpcap wrapper, used to get the channel of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_device_channel(PAirpcapHandle ah, guint * ch)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapGetDeviceChannel(ah,ch);
+}
+
+/*
+ * Airpcap wrapper, used to get the supported channels of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_device_supported_channels(PAirpcapHandle ah, AirpcapChannelInfo **cInfo, guint * nInfo)
+{
+ if (!AirpcapLoaded) return FALSE;
+ if (airpcap_get_dll_state() == AIRPCAP_DLL_OLD) {
+ *nInfo = num_legacy_channels;
+ *cInfo = (AirpcapChannelInfo*)&LegacyChannels;
+
+ return TRUE;
+ } else if (airpcap_get_dll_state() == AIRPCAP_DLL_OK) {
+ return g_PAirpcapGetDeviceSupportedChannels(ah, cInfo, nInfo);
+ }
+ return FALSE;
+}
+
+/*
+ * Airpcap wrapper, used to get the supported channels of an airpcap adapter
+ */
+Dot11Channel*
+airpcap_if_get_device_supported_channels_array(PAirpcapHandle ah, guint * pNumSupportedChannels)
+{
+ AirpcapChannelInfo *chanInfo;
+ guint numInfo = 0;
+
+ if (!AirpcapLoaded)
+ return NULL;
+ if (airpcap_if_get_device_supported_channels(ah, &chanInfo, &numInfo) == FALSE)
+ return NULL;
+ numSupportedChannels = 0;
+
+ /*
+ * allocate a bigger array
+ */
+ if (numInfo == 0)
+ return NULL;
+
+ pSupportedChannels = (Dot11Channel *)g_malloc(numInfo * (sizeof *pSupportedChannels));
+
+ for (guint i = 0; i < numInfo; i++)
+ {
+ guint supportedChannel = G_MAXUINT;
+
+ /*
+ * search if we have it already
+ */
+ for (guint j = 0; j < numSupportedChannels; j++)
+ {
+ if (pSupportedChannels[j].Frequency == chanInfo[i].Frequency)
+ {
+ supportedChannel = j;
+ break;
+ }
+ }
+
+ if (supportedChannel == G_MAXUINT)
+ {
+ /*
+ * not found, create a new item
+ */
+ pSupportedChannels[numSupportedChannels].Frequency = chanInfo[i].Frequency;
+
+ switch(chanInfo[i].ExtChannel)
+ {
+ case -1:
+ pSupportedChannels[numSupportedChannels].Flags = FLAG_CAN_BE_LOW;
+ break;
+ case +1:
+ pSupportedChannels[numSupportedChannels].Flags = FLAG_CAN_BE_HIGH;
+ break;
+ case 0:
+ default:
+ pSupportedChannels[numSupportedChannels].Flags = 0;
+ }
+
+ /*
+ * Gather channel information
+ */
+
+ pSupportedChannels[numSupportedChannels].Flags |=
+ FREQ_IS_BG(pSupportedChannels[numSupportedChannels].Frequency) ?
+ FLAG_IS_BG_CHANNEL : FLAG_IS_A_CHANNEL;
+ pSupportedChannels[numSupportedChannels].Channel =
+ ieee80211_mhz_to_chan(pSupportedChannels[numSupportedChannels].Frequency);
+ numSupportedChannels++;
+ }
+ else
+ {
+ /*
+ * just update the ext channel flags
+ */
+ switch(chanInfo[i].ExtChannel)
+ {
+ case -1:
+ pSupportedChannels[supportedChannel].Flags |= FLAG_CAN_BE_LOW;
+ break;
+ case +1:
+ pSupportedChannels[supportedChannel].Flags |= FLAG_CAN_BE_HIGH;
+ break;
+ case 0:
+ default:
+ break;
+ }
+ }
+ }
+
+ if (numSupportedChannels < 1)
+ return NULL;
+ /*
+ * Now sort the list by frequency
+ */
+ for (guint i = 0; i < numSupportedChannels - 1; i++)
+ {
+ for (guint j = i + 1; j < numSupportedChannels; j++)
+ {
+ if (pSupportedChannels[i].Frequency > pSupportedChannels[j].Frequency)
+ {
+ Dot11Channel temp = pSupportedChannels[i];
+ pSupportedChannels[i] = pSupportedChannels[j];
+ pSupportedChannels[j] = temp;
+ }
+ }
+ }
+
+ *pNumSupportedChannels = numSupportedChannels;
+ return pSupportedChannels;
+}
+
+/*
+ * Airpcap wrapper, used to set the channel of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_device_channel(PAirpcapHandle ah, guint ch)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapSetDeviceChannel(ah,ch);
+}
+
+/*
+ * Airpcap wrapper, used to set the frequency of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_device_channel_ex(PAirpcapHandle ah, AirpcapChannelInfo ChannelInfo)
+{
+ if (!AirpcapLoaded) return FALSE;
+ if (airpcap_get_dll_state() == AIRPCAP_DLL_OLD){
+ gint channel = 0;
+ channel = ieee80211_mhz_to_chan(ChannelInfo.Frequency);
+
+ if (channel < 0){
+ return FALSE;
+ } else {
+ return airpcap_if_set_device_channel(ah, channel);
+ }
+ } else if (airpcap_get_dll_state() == AIRPCAP_DLL_OK){
+ return g_PAirpcapSetDeviceChannelEx (ah, ChannelInfo);
+ }
+
+ return FALSE;
+}
+
+/*
+ * Airpcap wrapper, used to get the frequency of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_device_channel_ex(PAirpcapHandle ah, PAirpcapChannelInfo pChannelInfo)
+{
+ if (!AirpcapLoaded) return FALSE;
+
+ pChannelInfo->Frequency = 0;
+ pChannelInfo->ExtChannel = 0;
+ pChannelInfo->Reserved[0] = 0;
+ pChannelInfo->Reserved[1] = 0;
+ pChannelInfo->Reserved[2] = 0;
+
+ if (airpcap_get_dll_state() == AIRPCAP_DLL_OLD){
+ guint channel = 0;
+ guint chan_freq = 0;
+
+ if (!airpcap_if_get_device_channel(ah, &channel)) return FALSE;
+
+ chan_freq = ieee80211_chan_to_mhz(channel, TRUE);
+ if (chan_freq == 0) return FALSE;
+ pChannelInfo->Frequency = chan_freq;
+
+ return TRUE;
+ } else if (airpcap_get_dll_state() == AIRPCAP_DLL_OK){
+ return g_PAirpcapGetDeviceChannelEx (ah, pChannelInfo);
+ }
+ return FALSE;
+}
+
+/*
+ * Airpcap wrapper, used to get the link type of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_link_type(PAirpcapHandle ah, PAirpcapLinkType lt)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapGetLinkType(ah,lt);
+}
+
+/*
+ * Airpcap wrapper, used to set the link type of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_link_type(PAirpcapHandle ah, AirpcapLinkType lt)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapSetLinkType(ah,lt);
+}
+
+/*
+ * Airpcap wrapper, used to get the fcs presence of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_fcs_presence(PAirpcapHandle ah, gboolean * fcs)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapGetFcsPresence(ah,fcs);
+}
+
+/*
+ * Airpcap wrapper, used to set the fcs presence of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_fcs_presence(PAirpcapHandle ah, gboolean fcs)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapSetFcsPresence(ah,fcs);
+}
+
+/*
+ * Airpcap wrapper, used to get the decryption enabling of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState PEnable)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapGetDecryptionState(ah,PEnable);
+}
+
+/*
+ * Airpcap wrapper, used to set the decryption enabling of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState Enable)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapSetDecryptionState(ah,Enable);
+}
+
+/*
+ * Airpcap wrapper, used to get the decryption enabling of an airpcap driver
+ */
+gboolean
+airpcap_if_get_driver_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState PEnable)
+{
+ if (!AirpcapLoaded || (g_PAirpcapGetDriverDecryptionState==NULL)) return FALSE;
+ return g_PAirpcapGetDriverDecryptionState(ah,PEnable);
+}
+
+/*
+ * Airpcap wrapper, used to set the decryption enabling of an airpcap driver
+ */
+gboolean
+airpcap_if_set_driver_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState Enable)
+{
+ if (!AirpcapLoaded || (g_PAirpcapSetDriverDecryptionState==NULL)) return FALSE;
+ return g_PAirpcapSetDriverDecryptionState(ah,Enable);
+}
+
+/*
+ * Airpcap wrapper, used to get the fcs validation of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_fcs_validation(PAirpcapHandle ah, PAirpcapValidationType val)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapGetFcsValidation(ah,val);
+}
+
+/*
+ * Airpcap wrapper, used to set the fcs validation of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_fcs_validation(PAirpcapHandle ah, AirpcapValidationType val)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapSetFcsValidation(ah,val);
+}
+
+/*
+ * Airpcap wrapper, used to save the settings for the selected_if
+ */
+gboolean
+airpcap_if_set_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapSetDeviceKeys(AdapterHandle,KeysCollection);
+}
+
+/*
+ * Airpcap wrapper, used to save the settings for the selected_if
+ */
+gboolean
+airpcap_if_get_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, guint * PKeysCollectionSize)
+{
+ if (!AirpcapLoaded) return FALSE;
+ return g_PAirpcapGetDeviceKeys(AdapterHandle,KeysCollection,PKeysCollectionSize);
+}
+
+/*
+ * Airpcap wrapper, used to save the driver's set of keys
+ */
+gboolean
+airpcap_if_set_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection)
+{
+ if (!AirpcapLoaded || (g_PAirpcapSetDriverKeys==NULL)) return FALSE;
+ return g_PAirpcapSetDriverKeys(AdapterHandle,KeysCollection);
+}
+
+/*
+ * Airpcap wrapper, used to load the driver's set of keys
+ */
+gboolean
+airpcap_if_get_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, guint * PKeysCollectionSize)
+{
+ if (!AirpcapLoaded || (g_PAirpcapGetDriverKeys==NULL)) return FALSE;
+ return g_PAirpcapGetDriverKeys(AdapterHandle,KeysCollection,PKeysCollectionSize);
+}
+
+/*
+ * This function will create a new airpcap_if_info_t using a name and a description
+ */
+airpcap_if_info_t *
+airpcap_if_info_new(char *name, char *description)
+{
+ PAirpcapHandle ad;
+ gchar ebuf[AIRPCAP_ERRBUF_SIZE];
+
+ airpcap_if_info_t *if_info = NULL;
+
+ /* Probably I have to switch on the leds!!! */
+ ad = airpcap_if_open(name, ebuf);
+ if (ad)
+ {
+ if_info = g_new0(airpcap_if_info_t, 1);
+ if_info->name = g_strdup(name);
+ if (description == NULL){
+ if_info->description = NULL;
+ }else{
+ if_info->description = g_strdup(description);
+ }
+
+ if_info->ip_addr = NULL;
+ if_info->loopback = FALSE;
+ airpcap_if_get_fcs_validation(ad,&(if_info->CrcValidationOn));
+ airpcap_if_get_fcs_presence(ad,&(if_info->IsFcsPresent));
+ airpcap_if_get_link_type(ad,&(if_info->linkType));
+ airpcap_if_get_device_channel_ex(ad,&(if_info->channelInfo));
+ if_info->pSupportedChannels = airpcap_if_get_device_supported_channels_array(ad, &(if_info->numSupportedChannels));
+ airpcap_if_turn_led_on(ad, 0);
+ airpcap_if_get_decryption_state(ad, &(if_info->DecryptionOn));
+ if_info->led = TRUE;
+ if_info->blinking = FALSE;
+ if_info->saved = TRUE; /* NO NEED TO BE SAVED */
+
+ /* get the keys, if everything is ok, close the adapter */
+ if (airpcap_if_load_keys(ad,if_info))
+ {
+ airpcap_if_close(ad);
+ }
+ }
+ return if_info;
+}
+
+/*
+ * This function will create a new fake drivers' interface, to load global keys...
+ */
+airpcap_if_info_t*
+airpcap_driver_fake_if_info_new(void)
+{
+ PAirpcapHandle ad;
+ gchar ebuf[AIRPCAP_ERRBUF_SIZE];
+
+ airpcap_if_info_t *if_info = NULL;
+ airpcap_if_info_t *fake_if_info = NULL;
+
+ /* Maybe for some reason no airpcap adapter is found */
+ if (g_airpcap_if_list == NULL)
+ return NULL;
+
+ /*
+ * Retrieve the first AirPcap adapter available. If no interface is found,
+ * it is not possible to retrieve the driver's settings, so return NULL.
+ */
+ if_info = (airpcap_if_info_t *)g_list_nth_data(g_airpcap_if_list,0);
+ if (if_info == NULL)
+ return NULL;
+
+ /* Open the 'fake' adapter */
+ ad = airpcap_if_open(if_info->name, ebuf);
+ if (ad)
+ {
+ fake_if_info = g_new0(airpcap_if_info_t, 1);
+ fake_if_info->name = g_strdup(if_info->name);
+ fake_if_info->description = g_strdup(if_info->description);
+ fake_if_info->loopback = FALSE;
+ fake_if_info->ip_addr = NULL;
+ airpcap_if_get_driver_decryption_state(ad, &(fake_if_info->DecryptionOn));
+ airpcap_if_get_fcs_validation(ad,&(fake_if_info->CrcValidationOn));
+ airpcap_if_get_fcs_presence(ad,&(fake_if_info->IsFcsPresent));
+ airpcap_if_get_link_type(ad,&(fake_if_info->linkType));
+ airpcap_if_get_device_channel_ex(ad,&(fake_if_info->channelInfo));
+ airpcap_if_turn_led_on(ad, 0);
+ fake_if_info->led = TRUE;
+ fake_if_info->blinking = FALSE;
+ fake_if_info->saved = TRUE; /* NO NEED TO BE SAVED */
+
+ /* get the keys, if everything is ok, close the adapter */
+ if (airpcap_if_load_driver_keys(ad,fake_if_info))
+ {
+ airpcap_if_close(ad);
+ }
+ }
+
+ return fake_if_info;
+}
+
+#ifdef AIRPCAP_DEBUG
+/*
+ * USED FOR DEBUG ONLY... PRINTS AN AirPcap ADAPTER STRUCTURE in a fancy way.
+ */
+void
+airpcap_if_info_print(airpcap_if_info_t* if_info)
+{
+ guint i;
+ if (if_info == NULL)
+ {
+ g_print("\nWARNING : AirPcap Interface pointer is NULL.\n");
+ return;
+ }
+
+ g_print("\n----------------- AirPcap Interface \n");
+ g_print(" NAME: %s\n",if_info->name);
+ g_print(" DESCRIPTION: %s\n",if_info->description);
+ g_print(" BLINKING: %s\n",if_info->blinking ? "TRUE" : "FALSE");
+ g_print(" channelInfo.Frequency: %u\n",if_info->channelInfo.Frequency);
+ g_print(" channelInfo.ExtChannel: %d\n",if_info->channelInfo.ExtChannel);
+ g_print(" CRCVALIDATION: %s\n",if_info->CrcValidationOn ? "ON" : "OFF");
+ g_print(" DECRYPTION: %s\n",if_info->DecryptionOn ? "ON" : "OFF");
+ g_print(" IP ADDR: %s\n",if_info->ip_addr!=NULL ? "NOT NULL" : "NULL");
+ g_print(" FCSPRESENT: %s\n",if_info->IsFcsPresent ? "TRUE" : "FALSE");
+ g_print(" KEYSCOLLECTION: %s\n",if_info->keysCollection!=NULL ? "NOT NULL" : "NULL");
+ g_print(" KEYSCOLLECTIONSIZE: %u\n",if_info->keysCollectionSize);
+ g_print(" LED: %s\n",if_info->led ? "ON" : "OFF");
+ g_print(" LINKTYPE: %d\n",if_info->linkType);
+ g_print(" LOOPBACK: %s\n",if_info->loopback ? "YES" : "NO");
+ g_print(" (GTK) TAG: %d\n",if_info->tag);
+ g_print("SUPPORTED CHANNELS POINTER: %p\n",if_info->pSupportedChannels);
+ g_print(" NUM SUPPORTED CHANNELS: %u\n",if_info->numSupportedChannels);
+
+ for(i=0; i<(if_info->numSupportedChannels); i++){
+ g_print("\n SUPPORTED CHANNEL #%u\n",i+1);
+ g_print(" CHANNEL: %u\n",if_info->pSupportedChannels[i].Channel);
+ g_print(" FREQUENCY: %u\n",if_info->pSupportedChannels[i].Frequency);
+ g_print(" FLAGS: %u\n",if_info->pSupportedChannels[i].Flags);
+ }
+ g_print("\n\n");
+}
+#endif /* AIRPCAP_DEBUG */
+
+/*
+ * Function used to load the WEP keys for a selected interface
+ */
+gboolean
+airpcap_if_load_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info)
+{
+ if (!if_info) return FALSE;
+
+ if_info->keysCollectionSize = 0;
+ if_info->keysCollection = NULL;
+
+ if (!airpcap_if_get_device_keys(ad, NULL, &(if_info->keysCollectionSize)))
+ {
+ if (if_info->keysCollectionSize == 0)
+ {
+ if_info->keysCollection = NULL;
+ airpcap_if_close(ad);
+ return FALSE;
+ }
+
+ if_info->keysCollection = (PAirpcapKeysCollection)g_malloc(if_info->keysCollectionSize);
+ if (!if_info->keysCollection)
+ {
+ if_info->keysCollectionSize = 0;
+ if_info->keysCollection = NULL;
+ airpcap_if_close(ad);
+ return FALSE;
+ }
+
+ airpcap_if_get_device_keys(ad, if_info->keysCollection, &(if_info->keysCollectionSize));
+ return TRUE;
+ }
+
+ airpcap_if_close(ad);
+ return FALSE;
+}
+
+/*
+ * Function used to load the WEP keys for a selected interface
+ */
+gboolean
+airpcap_if_load_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info)
+{
+ if_info->keysCollectionSize = 0;
+ if_info->keysCollection = NULL;
+
+ if (!airpcap_if_get_driver_keys(ad, NULL, &(if_info->keysCollectionSize)))
+ {
+ if (if_info->keysCollectionSize == 0)
+ {
+ if_info->keysCollection = NULL;
+ airpcap_if_close(ad);
+ return FALSE;
+ }
+
+ if_info->keysCollection = (PAirpcapKeysCollection)g_malloc(if_info->keysCollectionSize);
+ if (!if_info->keysCollection)
+ {
+ if_info->keysCollectionSize = 0;
+ if_info->keysCollection = NULL;
+ airpcap_if_close(ad);
+ return FALSE;
+ }
+
+ airpcap_if_get_driver_keys(ad, if_info->keysCollection, &(if_info->keysCollectionSize));
+ return TRUE;
+ }
+
+ airpcap_if_close(ad);
+ return FALSE;
+}
+
+/*
+ * Function used to save the WEP keys for a selected interface
+ */
+void
+airpcap_if_save_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info)
+{
+ if (!if_info || !AirpcapLoaded) return;
+
+ if (if_info->keysCollection != NULL)
+ g_PAirpcapSetDeviceKeys(ad,if_info->keysCollection);
+}
+
+/*
+ * Function used to save the WEP keys for a selected interface
+ */
+void
+airpcap_if_save_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info)
+{
+ if (if_info->keysCollection != NULL)
+ airpcap_if_set_driver_keys(ad,if_info->keysCollection);
+}
+
+/*
+ * Callback used to free an instance of airpcap_if_info_t
+ */
+static void
+free_airpcap_if_cb(gpointer data, gpointer user_data _U_)
+{
+ airpcap_if_info_t *if_info = (airpcap_if_info_t *)data;
+
+ if (NULL == if_info)
+ return;
+
+ g_free(if_info->name);
+
+ g_free(if_info->description);
+
+ /* XXX - FREE THE WEP KEY LIST HERE!!!*/
+ if (if_info->keysCollection != NULL)
+ {
+ g_free(if_info->keysCollection);
+ if_info->keysCollection = NULL;
+ }
+
+ g_slist_free(if_info->ip_addr);
+
+ g_free(if_info);
+}
+
+/*
+ * Function used to free the airpcap interface list
+ */
+void
+free_airpcap_interface_list(GList *if_list)
+{
+ g_list_foreach(if_list, free_airpcap_if_cb, NULL);
+ g_list_free(if_list);
+}
+
+/*
+ * This function will use the airpcap.dll to find all the airpcap devices.
+ * Will return null if no device is found.
+ */
+GList*
+get_airpcap_interface_list(int *err, char **err_str)
+{
+ GList *il = NULL;
+ airpcap_if_info_t *if_info;
+ int n_adapts;
+ AirpcapDeviceDescription *devsList, *adListEntry;
+ char errbuf[AIRPCAP_ERRBUF_SIZE];
+
+ *err = 0;
+
+ if (!AirpcapLoaded)
+ {
+ *err = AIRPCAP_NOT_LOADED;
+ return il;
+ }
+
+ if (!g_PAirpcapGetDeviceList(&devsList, errbuf))
+ {
+ /* No interfaces, return il = NULL; */
+ *err = CANT_GET_AIRPCAP_INTERFACE_LIST;
+ if (err_str != NULL)
+ *err_str = cant_get_airpcap_if_list_error_message(errbuf);
+ return il;
+ }
+
+ /*
+ * Count the adapters
+ */
+ adListEntry = devsList;
+ n_adapts = 0;
+ while(adListEntry)
+ {
+ n_adapts++;
+ adListEntry = adListEntry->next;
+ }
+
+ if (n_adapts == 0)
+ {
+ /* No interfaces, return il= NULL */
+ g_PAirpcapFreeDeviceList(devsList);
+ *err = NO_AIRPCAP_INTERFACES_FOUND;
+ if (err_str != NULL)
+ *err_str = NULL;
+ return il;
+ }
+
+ /*
+ * Insert the adapters in our list
+ */
+ adListEntry = devsList;
+ while(adListEntry)
+ {
+ if_info = airpcap_if_info_new(adListEntry->Name, adListEntry->Description);
+ if (if_info != NULL){
+ il = g_list_append(il, if_info);
+ }
+
+ adListEntry = adListEntry->next;
+ }
+
+ g_PAirpcapFreeDeviceList(devsList);
+
+ return il;
+}
+
+/*
+ * Used to retrieve the interface given the name
+ * (the name is used in AirpcapOpen)
+ */
+airpcap_if_info_t* get_airpcap_if_from_name(GList* if_list, const gchar* name)
+{
+ GList* curr;
+ airpcap_if_info_t* if_info;
+
+ for (curr = g_list_first(if_list); curr; curr = g_list_next(curr)) {
+ if_info = (airpcap_if_info_t *)curr->data;
+ if (if_info && (g_ascii_strcasecmp(if_info->name, name) == 0)) {
+ return (if_info);
+ }
+ /* Try the name without the "\\.\" prefix. */
+ if (strlen(if_info->name) > 4 && (g_ascii_strcasecmp(if_info->name + 4, name) == 0)) {
+ return (if_info);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Clear keys and decryption status for the specified interface
+ */
+void
+airpcap_if_clear_decryption_settings(airpcap_if_info_t* info_if)
+{
+ if (info_if != NULL)
+ {
+ if (info_if->keysCollection != NULL)
+ {
+ g_free(info_if->keysCollection);
+ info_if->keysCollection = NULL;
+ }
+
+ info_if->keysCollectionSize = 0;
+
+ info_if->DecryptionOn = AIRPCAP_DECRYPTION_OFF;
+ info_if->saved = FALSE;
+ }
+}
+
+/*
+ * Used to retrieve the two chars string from interface
+ */
+gchar*
+airpcap_get_if_string_number(airpcap_if_info_t* if_info)
+{
+ gchar* number;
+ guint n;
+ int a;
+
+ a = sscanf(if_info->name,AIRPCAP_DEVICE_NUMBER_EXTRACT_STRING,&n);
+
+ /* If sscanf() returned 1, it means that has read a number, so interface is not "Any"
+ * Otherwise, check if it is the "Any" adapter...
+ */
+ if (a == 0)
+ {
+ if (g_ascii_strcasecmp(if_info->name,AIRPCAP_DEVICE_ANY_EXTRACT_STRING)!=0)
+ number = g_strdup("??");
+ else
+ number = g_strdup(AIRPCAP_CHANNEL_ANY_NAME);
+ }
+ else
+ {
+ number = g_strdup_printf("%.2u",n);
+ }
+
+ return number;
+}
+
+/*
+ * Used to retrieve the two chars string from interface
+ */
+gchar*
+airpcap_get_if_string_number_from_description(gchar* description)
+{
+ gchar* number;
+ gchar* pointer;
+
+ number = g_new(gchar, 3);
+
+ pointer = g_strrstr(description,"#\0");
+
+ number[0] = *(pointer+1);
+ number[1] = *(pointer+2);
+ number[2] = '\0';
+
+ return number;
+}
+
+/*
+ * Load the configuration for the specified interface
+ */
+void
+airpcap_load_selected_if_configuration(airpcap_if_info_t* if_info)
+{
+ gchar ebuf[AIRPCAP_ERRBUF_SIZE];
+ PAirpcapHandle ad;
+
+ if (if_info != NULL)
+ {
+ ad = airpcap_if_open(if_info->name, ebuf);
+
+ if (ad)
+ {
+ /* Stop blinking (if it was blinking!)*/
+ if (if_info->blinking)
+ {
+ /* Turn on the light (if it was off) */
+ if (!(if_info->led)) airpcap_if_turn_led_on(ad, 0);
+ }
+
+ /* Apply settings... */
+ airpcap_if_get_device_channel_ex(ad,&(if_info->channelInfo));
+ airpcap_if_get_fcs_validation(ad,&(if_info->CrcValidationOn));
+ airpcap_if_get_fcs_presence(ad,&(if_info->IsFcsPresent));
+ airpcap_if_get_link_type(ad,&(if_info->linkType));
+ airpcap_if_get_decryption_state(ad, &(if_info->DecryptionOn));
+ /* get the keys, if everything is ok, close the adapter */
+ if (airpcap_if_load_keys(ad,if_info))
+ airpcap_if_close(ad);
+
+ if_info->saved = TRUE;
+ }
+#if 0
+ else
+ {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, " Error in opening adapter for %s",if_info->description);
+ }
+#endif
+ }
+}
+
+/*
+ * Save the configuration for the specified interface
+ */
+void
+airpcap_save_selected_if_configuration(airpcap_if_info_t* if_info)
+{
+ gchar ebuf[AIRPCAP_ERRBUF_SIZE];
+ PAirpcapHandle ad;
+
+ if (if_info != NULL)
+ {
+ ad = airpcap_if_open(if_info->name, ebuf);
+
+ if (ad)
+ {
+ /* Stop blinking (if it was blinking!)*/
+ if (if_info->blinking)
+ {
+ /* Turn on the light (if it was off) */
+ if (!(if_info->led)) airpcap_if_turn_led_on(ad, 0);
+ }
+
+ /* Apply settings... */
+ airpcap_if_set_device_channel_ex(ad,if_info->channelInfo);
+ airpcap_if_set_fcs_validation(ad,if_info->CrcValidationOn);
+ airpcap_if_set_fcs_presence(ad,if_info->IsFcsPresent);
+ airpcap_if_set_link_type(ad,if_info->linkType);
+ airpcap_if_set_decryption_state(ad, if_info->DecryptionOn);
+ airpcap_if_save_keys(ad,if_info);
+
+ /* ... and save them */
+ if (!airpcap_if_store_cur_config_as_adapter_default(ad))
+ {
+#if 0
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Cannot save Wireless configuration!!!\nRemember that in order to store the configuration in the registry you have to:\n\n- Close all the airpcap-based applications.\n- Be sure to have administrative privileges.");
+#endif
+ if_info->saved = FALSE;
+ airpcap_if_close(ad);
+ return;
+ }
+
+ if_info->saved = TRUE;
+ airpcap_if_close(ad);
+ }
+#if 0
+ else
+ {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, " Error in opening adapter for %s",if_info->description);
+ }
+#endif
+ }
+}
+
+/*
+ * Save the configuration for the specified interface
+ */
+void
+airpcap_save_driver_if_configuration(airpcap_if_info_t* fake_if_info)
+{
+ gchar ebuf[AIRPCAP_ERRBUF_SIZE];
+ PAirpcapHandle ad;
+
+ if (fake_if_info != NULL)
+ {
+ ad = airpcap_if_open(fake_if_info->name, ebuf);
+
+ if (ad)
+ {
+ /* Apply decryption settings... */
+ airpcap_if_set_driver_decryption_state(ad, fake_if_info->DecryptionOn);
+ airpcap_if_save_driver_keys(ad,fake_if_info);
+ airpcap_if_close(ad);
+ }
+#if 0
+ else
+ {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, " Error in opening adapter for %s",fake_if_info->description);
+ }
+#endif
+ }
+
+ return;
+}
+
+/*
+ * Free an instance of airpcap_if_info_t
+ */
+void
+airpcap_if_info_free(airpcap_if_info_t *if_info)
+{
+ if (if_info != NULL)
+ {
+ g_free(if_info->name);
+
+ g_free(if_info->description);
+
+ if (if_info->keysCollection != NULL)
+ {
+ g_free(if_info->keysCollection);
+ if_info->keysCollection = NULL;
+ }
+
+ if (if_info->ip_addr != NULL)
+ {
+ g_slist_free(if_info->ip_addr);
+ if_info->ip_addr = NULL;
+ }
+
+ g_free(if_info);
+ }
+}
+
+
+/* DYNAMIC LIBRARY LOADER */
+/*
+ * Used to dynamically load the airpcap library in order link it only when
+ * it's present on the system
+ */
+int load_airpcap(void)
+{
+#ifdef _WIN32
+ gboolean base_functions = TRUE;
+ gboolean eleven_n_functions = TRUE;
+
+ if ((AirpcapLib = ws_load_library("airpcap.dll")) == NULL)
+ {
+ /* Report the error but go on */
+ AirpcapVersion = AIRPCAP_DLL_NOT_FOUND;
+ return AirpcapVersion;
+ }
+ else
+ {
+ if ((g_PAirpcapGetLastError = (AirpcapGetLastErrorHandler) GetProcAddress(AirpcapLib, "AirpcapGetLastError")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetDeviceList = (AirpcapGetDeviceListHandler) GetProcAddress(AirpcapLib, "AirpcapGetDeviceList")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapFreeDeviceList = (AirpcapFreeDeviceListHandler) GetProcAddress(AirpcapLib, "AirpcapFreeDeviceList")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapOpen = (AirpcapOpenHandler) GetProcAddress(AirpcapLib, "AirpcapOpen")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapClose = (AirpcapCloseHandler) GetProcAddress(AirpcapLib, "AirpcapClose")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetLinkType = (AirpcapGetLinkTypeHandler) GetProcAddress(AirpcapLib, "AirpcapGetLinkType")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetLinkType = (AirpcapSetLinkTypeHandler) GetProcAddress(AirpcapLib, "AirpcapSetLinkType")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetKernelBuffer = (AirpcapSetKernelBufferHandler) GetProcAddress(AirpcapLib, "AirpcapSetKernelBuffer")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetFilter = (AirpcapSetFilterHandler) GetProcAddress(AirpcapLib, "AirpcapSetFilter")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetMacAddress = (AirpcapGetMacAddressHandler) GetProcAddress(AirpcapLib, "AirpcapGetMacAddress")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetMinToCopy = (AirpcapSetMinToCopyHandler) GetProcAddress(AirpcapLib, "AirpcapSetMinToCopy")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetReadEvent = (AirpcapGetReadEventHandler) GetProcAddress(AirpcapLib, "AirpcapGetReadEvent")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapRead = (AirpcapReadHandler) GetProcAddress(AirpcapLib, "AirpcapRead")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetStats = (AirpcapGetStatsHandler) GetProcAddress(AirpcapLib, "AirpcapGetStats")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapTurnLedOn = (AirpcapTurnLedOnHandler) GetProcAddress(AirpcapLib, "AirpcapTurnLedOn")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapTurnLedOff = (AirpcapTurnLedOffHandler) GetProcAddress(AirpcapLib, "AirpcapTurnLedOff")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetDeviceChannel = (AirpcapGetDeviceChannelHandler) GetProcAddress(AirpcapLib, "AirpcapGetDeviceChannel")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetDeviceChannel = (AirpcapSetDeviceChannelHandler) GetProcAddress(AirpcapLib, "AirpcapSetDeviceChannel")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetFcsPresence = (AirpcapGetFcsPresenceHandler) GetProcAddress(AirpcapLib, "AirpcapGetFcsPresence")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetFcsPresence = (AirpcapSetFcsPresenceHandler) GetProcAddress(AirpcapLib, "AirpcapSetFcsPresence")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetFcsValidation = (AirpcapGetFcsValidationHandler) GetProcAddress(AirpcapLib, "AirpcapGetFcsValidation")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetFcsValidation = (AirpcapSetFcsValidationHandler) GetProcAddress(AirpcapLib, "AirpcapSetFcsValidation")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetDeviceKeys = (AirpcapGetDeviceKeysHandler) GetProcAddress(AirpcapLib, "AirpcapGetDeviceKeys")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetDeviceKeys = (AirpcapSetDeviceKeysHandler) GetProcAddress(AirpcapLib, "AirpcapSetDeviceKeys")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetDecryptionState = (AirpcapGetDecryptionStateHandler) GetProcAddress(AirpcapLib, "AirpcapGetDecryptionState")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetDecryptionState = (AirpcapSetDecryptionStateHandler) GetProcAddress(AirpcapLib, "AirpcapSetDecryptionState")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapStoreCurConfigAsAdapterDefault = (AirpcapStoreCurConfigAsAdapterDefaultHandler) GetProcAddress(AirpcapLib, "AirpcapStoreCurConfigAsAdapterDefault")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetVersion = (AirpcapGetVersionHandler) GetProcAddress(AirpcapLib, "AirpcapGetVersion")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetDriverDecryptionState = (AirpcapGetDriverDecryptionStateHandler) GetProcAddress(AirpcapLib, "AirpcapGetDriverDecryptionState")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetDriverDecryptionState = (AirpcapSetDriverDecryptionStateHandler) GetProcAddress(AirpcapLib, "AirpcapSetDriverDecryptionState")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapGetDriverKeys = (AirpcapGetDriverKeysHandler) GetProcAddress(AirpcapLib, "AirpcapGetDriverKeys")) == NULL) base_functions = FALSE;
+ if ((g_PAirpcapSetDriverKeys = (AirpcapSetDriverKeysHandler) GetProcAddress(AirpcapLib, "AirpcapSetDriverKeys")) == NULL) base_functions = FALSE;
+
+ /* TEST IF AIRPCAP SUPPORTS 11N */
+ if ((g_PAirpcapSetDeviceChannelEx = (AirpcapSetDeviceChannelExHandler) GetProcAddress(AirpcapLib, "AirpcapSetDeviceChannelEx")) == NULL) eleven_n_functions = FALSE;
+ if ((g_PAirpcapGetDeviceChannelEx = (AirpcapGetDeviceChannelExHandler) GetProcAddress(AirpcapLib, "AirpcapGetDeviceChannelEx")) == NULL) eleven_n_functions = FALSE;
+ if ((g_PAirpcapGetDeviceSupportedChannels = (AirpcapGetDeviceSupportedChannelsHandler) GetProcAddress(AirpcapLib, "AirpcapGetDeviceSupportedChannels")) == NULL) eleven_n_functions = FALSE;
+
+ if (base_functions && eleven_n_functions){
+ AirpcapLoaded = TRUE;
+ AirpcapVersion = AIRPCAP_DLL_OK;
+ } else if (base_functions){
+ AirpcapLoaded = TRUE;
+ AirpcapVersion = AIRPCAP_DLL_OLD;
+ return AIRPCAP_DLL_OK;
+ }else{
+ AirpcapLoaded = FALSE;
+ AirpcapVersion = AIRPCAP_DLL_ERROR;
+ }
+ }
+ return AirpcapVersion;
+#else /* _WIN32 */
+ return AIRPCAP_DLL_NOT_FOUND;
+#endif /* _WIN32 */
+}
+
+/*
+ * Append the version of AirPcap with which we were compiled to a GString.
+ */
+void
+get_compiled_airpcap_version(GString *str)
+{
+ g_string_append(str, "with AirPcap");
+}
+
+/*
+ * Append the version of AirPcap with which we we're running to a GString.
+ */
+void
+get_runtime_airpcap_version(GString *str)
+{
+ guint vmaj, vmin, vrev, build;
+
+ /* See if the DLL has been loaded successfully. Bail if it hasn't */
+ if (AirpcapLoaded == FALSE) {
+ g_string_append(str, "without AirPcap");
+ return;
+ }
+
+ g_PAirpcapGetVersion(&vmaj, &vmin, &vrev, &build);
+ g_string_append_printf(str, "with AirPcap %d.%d.%d build %d", vmaj, vmin,
+ vrev, build);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/capture/airpcap_loader.h b/capture/airpcap_loader.h
new file mode 100644
index 0000000000..c1d612bd9f
--- /dev/null
+++ b/capture/airpcap_loader.h
@@ -0,0 +1,407 @@
+/* airpcap_loader.h
+ * Declarations of routines for the "About" dialog
+ *
+ * Giorgio Tino <giorgio.tino@cacetech.com>
+ * Copyright (c) CACE Technologies, LLC 2006
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __AIRPCAP_LOADER_H__
+#define __AIRPCAP_LOADER_H__
+
+#include <epan/crypt/dot11decrypt_system.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Error values from "get_airpcap_interface_list()". */
+#define CANT_GET_AIRPCAP_INTERFACE_LIST 0 /* error getting list */
+#define NO_AIRPCAP_INTERFACES_FOUND 1 /* list is empty */
+#define AIRPCAP_NOT_LOADED 2 /* Airpcap DLL not loaded */
+
+#define AIRPCAP_CHANNEL_ANY_NAME "ANY"
+
+#define AIRPCAP_WEP_KEY_STRING "WEP"
+/*
+ * XXX - WPA_PWD is the passphrase+ssid and WPA-PSK is the hexadecimal key
+ */
+#define AIRPCAP_WPA_PWD_KEY_STRING "WPA-PWD"
+#define AIRPCAP_WPA_BIN_KEY_STRING "WPA-PSK"
+
+#define AIRPCAP_DLL_OK 0
+#define AIRPCAP_DLL_OLD 1
+#define AIRPCAP_DLL_ERROR 2
+#define AIRPCAP_DLL_NOT_FOUND 3
+
+/* #define AIRPCAP_DEBUG 1 */
+
+typedef gchar * (*AirpcapGetLastErrorHandler)(PAirpcapHandle AdapterHandle);
+typedef gboolean (*AirpcapGetDeviceListHandler)(PAirpcapDeviceDescription *PPAllDevs, gchar * Ebuf);
+typedef void (*AirpcapFreeDeviceListHandler)(PAirpcapDeviceDescription PAllDevs);
+typedef PAirpcapHandle (*AirpcapOpenHandler)(gchar * DeviceName, gchar * Ebuf);
+typedef void (*AirpcapCloseHandler)(PAirpcapHandle AdapterHandle);
+typedef gboolean (*AirpcapGetLinkTypeHandler)(PAirpcapHandle AdapterHandle, PAirpcapLinkType PLinkType);
+typedef gboolean (*AirpcapSetLinkTypeHandler)(PAirpcapHandle AdapterHandle, AirpcapLinkType NewLinkType);
+typedef gboolean (*AirpcapSetKernelBufferHandler)(PAirpcapHandle AdapterHandle, guint BufferSize);
+typedef gboolean (*AirpcapSetFilterHandler)(PAirpcapHandle AdapterHandle, void * Instructions, guint Len);
+typedef gboolean (*AirpcapGetMacAddressHandler)(PAirpcapHandle AdapterHandle, PAirpcapMacAddress PMacAddress);
+typedef gboolean (*AirpcapSetMinToCopyHandler)(PAirpcapHandle AdapterHandle, guint MinToCopy);
+typedef gboolean (*AirpcapGetReadEventHandler)(PAirpcapHandle AdapterHandle, void *** PReadEvent);
+typedef gboolean (*AirpcapReadHandler)(PAirpcapHandle AdapterHandle, guint8 * Buffer, guint BufSize, guint * PReceievedBytes);
+typedef gboolean (*AirpcapGetStatsHandler)(PAirpcapHandle AdapterHandle, PAirpcapStats PStats);
+typedef gboolean (*AirpcapTurnLedOnHandler)(PAirpcapHandle AdapterHandle, guint LedNumber);
+typedef gboolean (*AirpcapTurnLedOffHandler)(PAirpcapHandle AdapterHandle, guint LedNumber);
+typedef gboolean (*AirpcapSetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, guint Channel);
+typedef gboolean (*AirpcapGetDeviceChannelHandler)(PAirpcapHandle AdapterHandle, guint * PChannel);
+typedef gboolean (*AirpcapSetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, gboolean IsFcsPresent);
+typedef gboolean (*AirpcapGetFcsPresenceHandler)(PAirpcapHandle AdapterHandle, gboolean * PIsFcsPresent);
+typedef gboolean (*AirpcapSetFcsValidationHandler)(PAirpcapHandle AdapterHandle, AirpcapValidationType ValidationType);
+typedef gboolean (*AirpcapGetFcsValidationHandler)(PAirpcapHandle AdapterHandle, PAirpcapValidationType PValidationType);
+typedef gboolean (*AirpcapSetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection);
+typedef gboolean (*AirpcapGetDeviceKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, guint * PKeysCollectionSize);
+typedef gboolean (*AirpcapSetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection);
+typedef gboolean (*AirpcapGetDriverKeysHandler)(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, guint * PKeysCollectionSize);
+typedef gboolean (*AirpcapSetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable);
+typedef gboolean (*AirpcapGetDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable);
+typedef gboolean (*AirpcapSetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, AirpcapDecryptionState Enable);
+typedef gboolean (*AirpcapGetDriverDecryptionStateHandler)(PAirpcapHandle AdapterHandle, PAirpcapDecryptionState PEnable);
+typedef gboolean (*AirpcapStoreCurConfigAsAdapterDefaultHandler)(PAirpcapHandle AdapterHandle);
+typedef void (*AirpcapGetVersionHandler)(guint * VersionMajor, guint * VersionMinor, guint * VersionRev, guint * VersionBuild);
+typedef gboolean (*AirpcapSetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo ChannelInfo);
+typedef gboolean (*AirpcapGetDeviceChannelExHandler)(PAirpcapHandle AdapterHandle, PAirpcapChannelInfo PChannelInfo);
+typedef gboolean (*AirpcapGetDeviceSupportedChannelsHandler)(PAirpcapHandle AdapterHandle, AirpcapChannelInfo **ppChannelInfo, guint32 * pNumChannelInfo);
+
+#define FLAG_CAN_BE_LOW 0x00000001
+#define FLAG_CAN_BE_HIGH 0x00000002
+#define FLAG_IS_BG_CHANNEL 0x00000004
+#define FLAG_IS_A_CHANNEL 0x00000008
+
+typedef struct _Dot11Channel
+{
+ guint Channel;
+ guint32 Frequency;
+ guint32 Flags;
+} Dot11Channel;
+
+/*
+ * The list of interfaces returned by "get_airpcap_interface_list()" is
+ * a list of these structures.
+ */
+typedef struct {
+ char *name; /* e.g. "eth0" */
+ char *description; /* from OS, e.g. "Local Area Connection" or NULL */
+ GSList *ip_addr; /* containing address values of if_addr_t */
+ gboolean loopback; /* TRUE if loopback, FALSE otherwise */
+ AirpcapLinkType linkType; /* The link layer type */
+ AirpcapChannelInfo channelInfo; /* Channel Information */
+ gboolean IsFcsPresent; /* Include 802.11 CRC in frames */
+ AirpcapValidationType CrcValidationOn; /* Capture Frames with Wrong CRC */
+ AirpcapDecryptionState DecryptionOn; /* TRUE if decryption is on, FALSE otherwise */
+ PAirpcapKeysCollection keysCollection; /* WEP Key collection for the adapter */
+ guint keysCollectionSize; /* Size of the key collection */
+ gboolean blinking; /* TRUE if is blinkng, FALSE otherwise */
+ gboolean led; /* TRUE if on, FALSE if off */
+ gboolean saved; /* TRUE if current configuration has been saved, FALSE otherwise */
+ gint tag; /* int for the gtk blinking callback */
+ Dot11Channel *pSupportedChannels;
+ guint32 numSupportedChannels;
+} airpcap_if_info_t;
+
+/*
+ * Struct used to store infos to pass to the preferences manager callbacks
+ */
+typedef struct {
+ GList *list;
+ int current_index;
+ int number_of_keys;
+} keys_cb_data_t;
+
+/* Airpcap interface list */
+extern GList *g_airpcap_if_list;
+
+/* Airpcap current selected interface */
+extern airpcap_if_info_t *airpcap_if_selected;
+
+/* Airpcap current active interface */
+extern airpcap_if_info_t *airpcap_if_active;
+
+#ifdef AIRPCAP_DEBUG
+/*
+ * USED FOR DEBUG ONLY... PRINTS AN AirPcap ADAPTER STRUCTURE in a fancy way.
+ */
+void
+airpcap_if_info_print(airpcap_if_info_t* if_info);
+#endif
+
+/*
+ * Used to retrieve the two chars string from interface
+ */
+gchar*
+airpcap_get_if_string_number_from_description(gchar* description);
+
+/*
+ * Function used to free the airpcap interface list
+ */
+void
+free_airpcap_interface_list(GList *if_list);
+
+/*
+ * Used to retrieve the interface given the name
+ * (the name is used in AirpcapOpen).
+ */
+airpcap_if_info_t* get_airpcap_if_from_name(GList* if_list, const gchar* name);
+
+/*
+ * Airpcap wrapper, used to store the current settings for the selected adapter
+ */
+gboolean
+airpcap_if_store_cur_config_as_adapter_default(PAirpcapHandle ah);
+
+/*
+ * Function used to load the WEP keys for a selected interface
+ */
+gboolean
+airpcap_if_load_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info);
+
+/*
+ * Function used to load the WEP keys from the global driver list
+ */
+gboolean
+airpcap_if_load_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info);
+
+/*
+ * Function used to save the WEP keys for a selected interface
+ */
+void
+airpcap_if_save_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info);
+
+/*
+ * Function used to save the WEP keys for a selected interface
+ */
+void
+airpcap_if_save_driver_keys(PAirpcapHandle ad, airpcap_if_info_t *if_info);
+
+/*
+ * Airpcap wrapper, used to get the fcs validation of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_fcs_validation(PAirpcapHandle ah, PAirpcapValidationType val);
+
+/*
+ * Airpcap wrapper, used to set the fcs validation of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_fcs_validation(PAirpcapHandle ah, AirpcapValidationType val);
+
+/* Many of these are GTK+ only. */
+/*
+ * Airpcap wrapper, used to get the decryption enabling of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState val);
+
+/*
+ * Airpcap wrapper, used to set the decryption enabling of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState val);
+
+/*
+ * Airpcap wrapper, used to get the fcs presence of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_fcs_presence(PAirpcapHandle ah, gboolean * ch);
+
+/*
+ * Airpcap wrapper, used to set the fcs presence of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_fcs_presence(PAirpcapHandle ah, gboolean ch);
+
+/*
+ * Airpcap wrapper, used to get the link type of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_link_type(PAirpcapHandle ah, PAirpcapLinkType lt);
+
+/*
+ * Airpcap wrapper, used to set the link type of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_link_type(PAirpcapHandle ah, AirpcapLinkType lt);
+
+/*
+ * Airpcap wrapper, used to get the channel of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_device_channel(PAirpcapHandle ah, guint * ch);
+
+/*
+ * Airpcap wrapper, get the channels supported by the adapter
+ */
+gboolean
+airpcap_if_get_device_supported_channels(PAirpcapHandle ah, AirpcapChannelInfo **cInfo, guint32 * nInfo);
+
+/*
+ * Airpcap wrapper, get supported channels formatted into an array
+ */
+Dot11Channel*
+airpcap_if_get_device_supported_channels_array(PAirpcapHandle ah, guint32 * pNumSupportedChannels);
+
+/*
+ * Airpcap wrapper, used to set the channel of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_device_channel(PAirpcapHandle ah, guint ch);
+
+/*
+ * Airpcap wrapper, used to get the frequency of an airpcap adapter
+ */
+gboolean
+airpcap_if_get_device_channel_ex(PAirpcapHandle ah, PAirpcapChannelInfo pChannelInfo);
+
+/*
+ * Airpcap wrapper, used to set the frequency of an airpcap adapter
+ */
+gboolean
+airpcap_if_set_device_channel_ex(PAirpcapHandle ah, AirpcapChannelInfo ChannelInfo);
+
+/*
+ * Airpcap wrapper, used to open an airpcap adapter
+ */
+PAirpcapHandle airpcap_if_open(gchar * name, gchar * err);
+
+/*
+ * Airpcap wrapper, used to close an airpcap adapter
+ */
+void airpcap_if_close(PAirpcapHandle handle);
+
+/*
+ * Retrieve the state of the Airpcap DLL
+ */
+int
+airpcap_get_dll_state(void);
+
+/*
+ * Airpcap wrapper, used to turn on the led of an airpcap adapter
+ */
+gboolean airpcap_if_turn_led_on(PAirpcapHandle AdapterHandle, guint LedNumber);
+
+/*
+ * Airpcap wrapper, used to turn off the led of an airpcap adapter
+ */
+gboolean airpcap_if_turn_led_off(PAirpcapHandle AdapterHandle, guint LedNumber);
+
+/*
+ * This function will create a new airpcap_if_info_t using a name and a description
+ */
+airpcap_if_info_t* airpcap_if_info_new(char *name, char *description);
+
+/*
+ * This function will create a new fake drivers' interface, to load global keys...
+ */
+airpcap_if_info_t* airpcap_driver_fake_if_info_new(void);
+
+/*
+ * Used to dinamically load the airpcap library in order link it only when
+ * it's present on the system.
+ */
+int load_airpcap(void);
+
+/*
+ * This function will use the airpcap.dll to find all the airpcap devices.
+ * Will return null if no device is found.
+ */
+GList* get_airpcap_interface_list(int *err, char **err_str);
+
+/*
+ * Load the configuration for the specified interface
+ */
+void
+airpcap_load_selected_if_configuration(airpcap_if_info_t* if_info);
+
+/*
+ * Save the configuration for the specified interface
+ */
+void
+airpcap_save_selected_if_configuration(airpcap_if_info_t* if_info);
+
+/*
+ * Used to retrieve the two chars string from interface description
+ */
+gchar*
+airpcap_get_if_string_number(airpcap_if_info_t* if_info);
+
+/*
+ * Airpcap wrapper, used to save the settings for the selected_if
+ */
+gboolean
+airpcap_if_set_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection);
+
+/*
+ * Airpcap wrapper, used to save the settings for the selected_if
+ */
+gboolean
+airpcap_if_get_device_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, guint * PKeysCollectionSize);
+
+/*
+ * Airpcap wrapper, used to save the settings for the selected_if
+ */
+gboolean
+airpcap_if_set_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection);
+
+/*
+ * Airpcap wrapper, used to save the settings for the selected_if
+ */
+gboolean
+airpcap_if_get_driver_keys(PAirpcapHandle AdapterHandle, PAirpcapKeysCollection KeysCollection, guint * PKeysCollectionSize);
+
+/*
+ * Airpcap wrapper, used to get the decryption enabling of an airpcap driver
+ */
+gboolean
+airpcap_if_get_driver_decryption_state(PAirpcapHandle ah, PAirpcapDecryptionState PEnable);
+/*
+ * Airpcap wrapper, used to set the decryption enabling of an airpcap driver
+ */
+gboolean
+airpcap_if_set_driver_decryption_state(PAirpcapHandle ah, AirpcapDecryptionState Enable);
+
+/*
+ * Save the configuration for the specified interface
+ */
+void
+airpcap_save_driver_if_configuration(airpcap_if_info_t* fake_if_info);
+
+/*
+ * Free an instance of airpcap_if_info_t
+ */
+void
+airpcap_if_info_free(airpcap_if_info_t *if_info);
+
+/*
+ * Clear keys and decryption status for the specified interface
+ */
+void
+airpcap_if_clear_decryption_settings(airpcap_if_info_t* info_if);
+
+/*
+ * Adds compiled version string to str
+ */
+void
+get_compiled_airpcap_version(GString *str);
+
+void
+get_runtime_airpcap_version(GString *str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AIRPCAP_LOADER_H__ */
diff --git a/capture/capture-pcap-util-int.h b/capture/capture-pcap-util-int.h
new file mode 100644
index 0000000000..efeb467409
--- /dev/null
+++ b/capture/capture-pcap-util-int.h
@@ -0,0 +1,61 @@
+/* capture-pcap-util-int.h
+ * Definitions of routines internal to the libpcap/WinPcap/Npcap utilities
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#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_REMOTE
+extern GList *get_interface_list_findalldevs_ex(const char *hostname,
+ const char *port, int auth_type, const char *username, const char *passwd,
+ int *err, char **err_str);
+#endif /* HAVE_PCAP_REMOTE */
+extern GList *get_interface_list_findalldevs(int *err, char **err_str);
+
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+/*
+ * Request that a pcap_t provide high-resolution (nanosecond) time
+ * stamps; if that request fails, we'll just silently continue to
+ * use the microsecond-resolution time stamps, and our caller will
+ * find out, when they call have_high_resolution_timestamp(), that
+ * we don't have high-resolution time stamps.
+ */
+extern void request_high_resolution_timestamp(pcap_t *pcap_h);
+#endif
+
+extern if_capabilities_t *get_if_capabilities_local(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str);
+extern pcap_t *open_capture_device_local(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ cap_device_open_err *open_err, char (*open_err_str)[PCAP_ERRBUF_SIZE]);
+#ifdef HAVE_PCAP_CREATE
+extern if_capabilities_t *get_if_capabilities_pcap_create(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str);
+extern pcap_t *open_capture_device_pcap_create(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ cap_device_open_err *open_err,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE]);
+#endif /* HAVE_PCAP_CREATE */
+extern if_capabilities_t *get_if_capabilities_pcap_open_live(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str);
+extern pcap_t *open_capture_device_pcap_open_live(interface_options *interface_opts,
+ int timeout, cap_device_open_err *open_err,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE]);
+
+/*
+ * 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/capture/capture-pcap-util-unix.c b/capture/capture-pcap-util-unix.c
new file mode 100644
index 0000000000..b83888e849
--- /dev/null
+++ b/capture/capture-pcap-util-unix.c
@@ -0,0 +1,202 @@
+/* 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
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <glib.h>
+
+#include <ws_attributes.h>
+
+#ifdef HAVE_LIBPCAP
+
+#include "wspcap.h"
+
+#ifdef HAVE_LIBCAP
+# include <sys/capability.h>
+#endif
+
+#include "capture/capture_ifinfo.h"
+#include "capture/capture-pcap-util.h"
+#include "capture/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)
+{
+ return get_interface_list_findalldevs_ex(hostname, port, auth_type,
+ username, passwd, err, err_str);
+}
+#endif
+
+GList *
+get_interface_list(int *err, char **err_str)
+{
+ return get_interface_list_findalldevs(err, err_str);
+}
+
+/*
+ * 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);
+}
+
+if_capabilities_t *
+get_if_capabilities_local(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str)
+{
+#ifdef HAVE_PCAP_CREATE
+ return get_if_capabilities_pcap_create(interface_opts, err, err_str);
+#else
+ return get_if_capabilities_pcap_open_live(interface_opts, err, err_str);
+#endif
+}
+
+pcap_t *
+open_capture_device_local(capture_options *capture_opts
+#ifndef HAVE_PCAP_CREATE
+ _U_
+#endif
+ ,
+ interface_options *interface_opts, int timeout,
+ cap_device_open_err *open_err, char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ /*
+ * We're not opening a remote device; use pcap_create() and
+ * pcap_activate() if we have them, so that we can set various
+ * options, otherwise use pcap_open_live().
+ */
+#ifdef HAVE_PCAP_CREATE
+ return open_capture_device_pcap_create(capture_opts,
+ interface_opts, timeout, open_err, open_err_str);
+#else
+ return open_capture_device_pcap_open_live(interface_opts, timeout,
+ open_err, open_err_str);
+#endif
+}
+
+/*
+ * 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");
+#ifdef HAVE_PCAP_REMOTE
+ /*
+ * We have remote pcap support in libpcap.
+ */
+ g_string_append(str, " (including remote capture support)");
+#endif
+
+ /*
+ * 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 ");
+ g_string_append(str, pcap_lib_version());
+}
+
+#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 */
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/capture/capture-pcap-util.c b/capture/capture-pcap-util.c
new file mode 100644
index 0000000000..5f8377a688
--- /dev/null
+++ b/capture/capture-pcap-util.c
@@ -0,0 +1,1626 @@
+/* capture-pcap-util.c
+ * Utility routines for packet capture
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LIBPCAP
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef __APPLE__
+#include <dlfcn.h>
+#endif
+
+#include "ws_attributes.h"
+
+/*
+ * Linux bonding devices mishandle unknown ioctls; they fail
+ * with ENODEV rather than ENOTSUP, EOPNOTSUPP, or ENOTTY,
+ * so pcap_can_set_rfmon() returns a "no such device" indication
+ * if we try to do SIOCGIWMODE on them.
+ *
+ * So, on Linux, we check for bonding devices, if we can, before
+ * trying pcap_can_set_rfmon(), as pcap_can_set_rfmon() will
+ * end up trying SIOCGIWMODE on the device if that ioctl exists.
+ */
+#if defined(HAVE_PCAP_CREATE) && defined(__linux__)
+
+#include <sys/ioctl.h>
+
+/*
+ * If we're building for a Linux version that supports bonding,
+ * HAVE_BONDING will be defined.
+ */
+
+#ifdef HAVE_LINUX_SOCKIOS_H
+#include <linux/sockios.h>
+#endif
+
+#ifdef HAVE_LINUX_IF_BONDING_H
+#include <linux/if_bonding.h>
+#endif
+
+#if defined(BOND_INFO_QUERY_OLD) || defined(SIOCBONDINFOQUERY)
+#define HAVE_BONDING
+#endif
+
+#endif /* defined(HAVE_PCAP_CREATE) && defined(__linux__) */
+
+#include "capture/capture_ifinfo.h"
+#include "capture/capture-pcap-util.h"
+#include "capture/capture-pcap-util-int.h"
+
+#include "log.h"
+
+#include <wsutil/file_util.h>
+#include <wsutil/please_report_bug.h>
+
+#ifndef _WIN32
+#include <netinet/in.h>
+#endif
+
+#ifdef _WIN32
+#include "capture/capture_win_ifnames.h" /* windows friendly interface names */
+#endif
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+/*
+ * Needed for the code to get a device description.
+ */
+#include <errno.h>
+#include <net/if.h>
+#include <sys/sockio.h>
+#endif
+
+/*
+ * Given an interface name, find the "friendly name" and interface
+ * type for the interface.
+ */
+
+#if defined(HAVE_MACOS_FRAMEWORKS)
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include <wsutil/cfutils.h>
+
+/*
+ * On macOS, 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 macOS 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".)
+ */
+static 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_get(const char *name)
+{
+ char *description = NULL;
+ if_info_t *if_info;
+#ifdef SIOCGIFDESCR
+ /*
+ * Try to fetch the description of this interface.
+ * XXX - this is only here because libpcap has no API to
+ * get the description of a *single* interface; it really
+ * needs both an API to get pcapng-IDB-style attributes
+ * for a single interface and to get a list of interfaces
+ * with pcapng-IDB-style attributes for each interface.
+ */
+ int s;
+ struct ifreq ifrdesc;
+#ifndef IFDESCRSIZE
+ size_t descrlen = 64;
+#else
+ size_t descrlen = IFDESCRSIZE;
+#endif /* IFDESCRSIZE */
+
+ /*
+ * Get the description for the interface.
+ */
+ memset(&ifrdesc, 0, sizeof ifrdesc);
+ g_strlcpy(ifrdesc.ifr_name, name, sizeof ifrdesc.ifr_name);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s >= 0) {
+#ifdef __FreeBSD__
+ /*
+ * On FreeBSD, if the buffer isn't big enough for the
+ * description, the ioctl succeeds, but the description
+ * isn't copied, ifr_buffer.length is set to the description
+ * length, and ifr_buffer.buffer is set to NULL.
+ */
+ for (;;) {
+ g_free(description);
+ if ((description = (char*)g_malloc(descrlen)) != NULL) {
+ ifrdesc.ifr_buffer.buffer = description;
+ ifrdesc.ifr_buffer.length = descrlen;
+ if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) {
+ if (ifrdesc.ifr_buffer.buffer ==
+ description)
+ break;
+ else
+ descrlen = ifrdesc.ifr_buffer.length;
+ } else {
+ /*
+ * Failed to get interface description.
+ */
+ g_free(description);
+ description = NULL;
+ break;
+ }
+ } else
+ break;
+ }
+#else /* __FreeBSD__ */
+ /*
+ * The only other OS that currently supports
+ * SIOCGIFDESCR is OpenBSD, and it has no way
+ * to get the description length - it's clamped
+ * to a maximum of IFDESCRSIZE.
+ */
+ if ((description = (char*)g_malloc(descrlen)) != NULL) {
+ ifrdesc.ifr_data = (caddr_t)description;
+ if (ioctl(s, SIOCGIFDESCR, &ifrdesc) != 0) {
+ /*
+ * Failed to get interface description.
+ */
+ g_free(description);
+ description = NULL;
+ }
+ }
+#endif /* __FreeBSD__ */
+ close(s);
+ if (description != NULL && strlen(description) == 0) {
+ /*
+ * Description is empty, so discard it.
+ */
+ g_free(description);
+ description = NULL;
+ }
+ }
+
+#ifdef __FreeBSD__
+ /*
+ * For FreeBSD, if we didn't get a description, and this is
+ * a device with a name of the form usbusN, label it as a USB
+ * bus.
+ */
+ if (description == NULL) {
+ if (strncmp(name, "usbus", 5) == 0) {
+ /*
+ * OK, it begins with "usbus".
+ */
+ long busnum;
+ char *p;
+
+ errno = 0;
+ busnum = strtol(name + 5, &p, 10);
+ if (errno == 0 && p != name + 5 && *p == '\0' &&
+ busnum >= 0 && busnum <= INT_MAX) {
+ /*
+ * OK, it's a valid number that's not
+ * bigger than INT_MAX. Construct
+ * a description from it.
+ */
+ static const char descr_prefix[] = "USB bus number ";
+ size_t descr_size;
+
+ /*
+ * Allow enough room for a 32-bit bus number.
+ * sizeof (descr_prefix) includes the
+ * terminating NUL.
+ */
+ descr_size = sizeof (descr_prefix) + 10;
+ description = g_malloc(descr_size);
+ if (description != NULL) {
+ g_snprintf(description, descr_size,
+ "%s%ld", descr_prefix, busnum);
+ }
+ }
+ }
+ }
+#endif /* __FreeBSD__ */
+#endif /* SIOCGIFDESCR */
+ if_info = if_info_new(name, description, FALSE);
+ g_free(description);
+ return if_info;
+}
+
+void
+if_info_free(if_info_t *if_info)
+{
+ g_free(if_info->name);
+ g_free(if_info->friendly_name);
+ g_free(if_info->vendor_description);
+ g_free(if_info->extcap);
+ g_slist_free_full(if_info->addrs, g_free);
+ g_free(if_info);
+}
+
+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 = g_new(if_info_t, 1);
+ if_info->name = g_strdup(name);
+ if_info->friendly_name = NULL; /* default - unknown */
+ if_info->vendor_description = NULL;
+ if_info->type = IF_WIRED; /* default */
+ if_info->extcap = g_strdup("");
+#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:
+ *
+ * https://www.iana.org/assignments/ianaiftype-mib/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 Npcap/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;
+ struct sockaddr_in6 *ai6;
+
+ 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_prepend(if_info->addrs, if_addr);
+ break;
+
+ 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_prepend(if_info->addrs, if_addr);
+ break;
+ }
+}
+
+/*
+ * 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);
+ }
+
+ if(if_info->addrs){
+ if_info->addrs = g_slist_reverse(if_info->addrs);
+ }
+}
+
+#ifdef HAVE_PCAP_REMOTE
+GList *
+get_interface_list_findalldevs_ex(const char *hostname, const char *port,
+ int auth_type, const char *username,
+ const char *passwd, int *err, char **err_str)
+{
+ char source[PCAP_BUF_SIZE];
+ struct pcap_rmtauth auth;
+ GList *il = NULL;
+ pcap_if_t *alldevs, *dev;
+ if_info_t *if_info;
+ /*
+ * WinPcap can overflow PCAP_ERRBUF_SIZE if the host is unreachable.
+ * Fudge a larger size.
+ */
+ char errbuf[PCAP_ERRBUF_SIZE*4];
+
+ 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);
+
+ if (pcap_findalldevs_ex(source, &auth, &alldevs, errbuf) == -1) {
+ *err = CANT_GET_INTERFACE_LIST;
+ if (err_str != NULL)
+ *err_str = cant_get_if_list_error_message(errbuf);
+ g_free(auth.username);
+ g_free(auth.password);
+ return NULL;
+ }
+
+ if (alldevs == NULL) {
+ /*
+ * No interfaces found.
+ */
+ *err = 0;
+ if (err_str != NULL)
+ *err_str = NULL;
+ g_free(auth.username);
+ g_free(auth.password);
+ 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);
+ g_free(auth.username);
+ g_free(auth.password);
+
+ 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 = 0;
+ 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;
+}
+
+static void
+free_if_cb(gpointer data, gpointer user_data _U_)
+{
+ if_info_free((if_info_t *)data);
+}
+
+void
+free_interface_list(GList *if_list)
+{
+ g_list_foreach(if_list, free_if_cb, NULL);
+ g_list_free(if_list);
+}
+
+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);
+ g_free(linktype_info);
+}
+
+static void
+free_timestamp_cb(gpointer data, gpointer user_data _U_)
+{
+ timestamp_info_t *timestamp_info = (timestamp_info_t *)data;
+
+ g_free(timestamp_info->name);
+ g_free(timestamp_info->description);
+ g_free(data);
+}
+
+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_list_foreach(caps->timestamp_types, free_timestamp_cb, NULL);
+ g_list_free(caps->timestamp_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);
+}
+
+/*
+ * Get the data-link type for a libpcap device.
+ * This works around AIX 5.x's non-standard and incompatible-with-the-
+ * rest-of-the-universe libpcap.
+ */
+int
+get_pcap_datalink(pcap_t *pch,
+#ifdef _AIX
+ const char* devicename
+#else
+ const char* devicename _U_
+#endif
+ )
+{
+ int datalink;
+#ifdef _AIX
+ const char *ifacename;
+#endif
+
+ datalink = pcap_datalink(pch);
+#ifdef _AIX
+
+ /*
+ * The libpcap that comes with AIX 5.x uses RFC 1573 ifType values
+ * rather than DLT_ values for link-layer types; the ifType values
+ * for LAN devices are:
+ *
+ * Ethernet 6
+ * 802.3 7
+ * Token Ring 9
+ * FDDI 15
+ *
+ * and the ifType value for a loopback device is 24.
+ *
+ * The AIX names for LAN devices begin with:
+ *
+ * Ethernet en
+ * 802.3 et
+ * Token Ring tr
+ * FDDI fi
+ *
+ * and the AIX names for loopback devices begin with "lo".
+ *
+ * (The difference between "Ethernet" and "802.3" is presumably
+ * whether packets have an Ethernet header, with a packet type,
+ * or an 802.3 header, with a packet length, followed by an 802.2
+ * header and possibly a SNAP header.)
+ *
+ * If the device name matches "datalink" interpreted as an ifType
+ * value, rather than as a DLT_ value, we will assume this is AIX's
+ * non-standard, incompatible libpcap, rather than a standard libpcap,
+ * and will map the link-layer type to the standard DLT_ value for
+ * that link-layer type, as that's what the rest of Wireshark expects.
+ *
+ * (This means the capture files won't be readable by a tcpdump
+ * linked with AIX's non-standard libpcap, but so it goes. They
+ * *will* be readable by standard versions of tcpdump, Wireshark,
+ * and so on.)
+ *
+ * XXX - if we conclude we're using AIX libpcap, should we also
+ * set a flag to cause us to assume the time stamps are in
+ * seconds-and-nanoseconds form, and to convert them to
+ * seconds-and-microseconds form before processing them and
+ * writing them out?
+ */
+
+ /*
+ * Find the last component of the device name, which is the
+ * interface name.
+ */
+ ifacename = strchr(devicename, '/');
+ if (ifacename == NULL)
+ ifacename = devicename;
+
+ /* See if it matches any of the LAN device names. */
+ if (strncmp(ifacename, "en", 2) == 0) {
+ if (datalink == 6) {
+ /*
+ * That's the RFC 1573 value for Ethernet;
+ * map it to DLT_EN10MB.
+ */
+ datalink = 1;
+ }
+ } else if (strncmp(ifacename, "et", 2) == 0) {
+ if (datalink == 7) {
+ /*
+ * That's the RFC 1573 value for 802.3;
+ * map it to DLT_EN10MB.
+ *
+ * (libpcap, tcpdump, Wireshark, etc. don't
+ * care if it's Ethernet or 802.3.)
+ */
+ datalink = 1;
+ }
+ } else if (strncmp(ifacename, "tr", 2) == 0) {
+ if (datalink == 9) {
+ /*
+ * That's the RFC 1573 value for 802.5 (Token Ring);
+ * map it to DLT_IEEE802, which is what's used for
+ * Token Ring.
+ */
+ datalink = 6;
+ }
+ } else if (strncmp(ifacename, "fi", 2) == 0) {
+ if (datalink == 15) {
+ /*
+ * That's the RFC 1573 value for FDDI;
+ * map it to DLT_FDDI.
+ */
+ datalink = 10;
+ }
+ } else if (strncmp(ifacename, "lo", 2) == 0) {
+ if (datalink == 24) {
+ /*
+ * That's the RFC 1573 value for "software loopback"
+ * devices; map it to DLT_NULL, which is what's used
+ * for loopback devices on BSD.
+ */
+ datalink = 0;
+ }
+ }
+#endif
+
+ return datalink;
+}
+
+/* Set the data link type on a pcap. */
+gboolean
+set_pcap_datalink(pcap_t *pcap_h, int datalink, char *name,
+ char *errmsg, size_t errmsg_len,
+ char *secondary_errmsg, size_t secondary_errmsg_len)
+{
+ char *set_datalink_err_str;
+
+ if (datalink == -1)
+ return TRUE; /* just use the default */
+ if (pcap_set_datalink(pcap_h, datalink) == 0)
+ return TRUE; /* no error */
+ set_datalink_err_str = pcap_geterr(pcap_h);
+ g_snprintf(errmsg, (gulong) errmsg_len, "Unable to set data link type on interface '%s' (%s).",
+ name, set_datalink_err_str);
+ /*
+ * If the error isn't "XXX is not one of the DLTs supported by this device",
+ * tell the user to tell the Wireshark developers about it.
+ */
+ if (strstr(set_datalink_err_str, "is not one of the DLTs supported by this device") == NULL)
+ g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len,
+ "%s", please_report_bug());
+ else
+ secondary_errmsg[0] = '\0';
+ return FALSE;
+}
+
+static data_link_info_t *
+create_data_link_info(int dlt)
+{
+ data_link_info_t *data_link_info;
+ const char *text;
+
+ data_link_info = g_new(data_link_info_t, 1);
+ data_link_info->dlt = dlt;
+ text = pcap_datalink_val_to_name(dlt);
+ if (text != NULL)
+ data_link_info->name = g_strdup(text);
+ else
+ data_link_info->name = g_strdup_printf("DLT %d", dlt);
+ text = pcap_datalink_val_to_description(dlt);
+ data_link_info->description = g_strdup(text);
+ return data_link_info;
+}
+
+static GList *
+get_data_link_types(pcap_t *pch, interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str)
+{
+ GList *data_link_types;
+ int deflt;
+ int *linktypes;
+ int i, nlt;
+ data_link_info_t *data_link_info;
+
+ deflt = get_pcap_datalink(pch, interface_opts->name);
+ nlt = pcap_list_datalinks(pch, &linktypes);
+ if (nlt < 0) {
+ /*
+ * A negative return is an error.
+ */
+#ifdef HAVE_PCAP_CREATE
+ /*
+ * If we have pcap_create(), we have
+ * pcap_statustostr(), and we can get back errors
+ * other than PCAP_ERROR (-1), such as
+ * PCAP_ERROR_NOT_ACTIVATED. and we should report
+ * them properly.
+ */
+ if (nlt == PCAP_ERROR) {
+ *err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *err_str = g_strdup_printf("pcap_list_datalinks() failed: %s",
+ pcap_geterr(pch));
+ } else {
+ if (nlt == PCAP_ERROR_PERM_DENIED)
+ *err = CAP_DEVICE_OPEN_ERR_PERMISSIONS;
+ else
+ *err = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ *err_str = g_strdup(pcap_statustostr(nlt));
+ }
+#else /* HAVE_PCAP_CREATE */
+ *err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *err_str = g_strdup_printf("pcap_list_datalinks() failed: %s",
+ pcap_geterr(pch));
+#endif /* HAVE_PCAP_CREATE */
+ return NULL;
+ }
+ data_link_types = NULL;
+ for (i = 0; i < nlt; i++) {
+ data_link_info = create_data_link_info(linktypes[i]);
+
+ /*
+ * XXX - for 802.11, make the most detailed 802.11
+ * version the default, rather than the one the
+ * device has as the default?
+ */
+ if (linktypes[i] == deflt)
+ data_link_types = g_list_prepend(data_link_types,
+ data_link_info);
+ else
+ data_link_types = g_list_append(data_link_types,
+ data_link_info);
+ }
+#ifdef HAVE_PCAP_FREE_DATALINKS
+ pcap_free_datalinks(linktypes);
+#else
+ /*
+ * In Windows, there's no guarantee that if you have a library
+ * built with one version of the MSVC++ run-time library, and
+ * it returns a pointer to allocated data, you can free that
+ * data from a program linked with another version of the
+ * MSVC++ run-time library.
+ *
+ * This is not an issue on UN*X.
+ *
+ * See the mail threads starting at
+ *
+ * https://www.winpcap.org/pipermail/winpcap-users/2006-September/001421.html
+ *
+ * and
+ *
+ * https://www.winpcap.org/pipermail/winpcap-users/2008-May/002498.html
+ */
+#ifndef _WIN32
+#define xx_free free /* hack so checkAPIs doesn't complain */
+ xx_free(linktypes);
+#endif /* _WIN32 */
+#endif /* HAVE_PCAP_FREE_DATALINKS */
+
+ *err_str = NULL;
+ return data_link_types;
+}
+
+/* Get supported timestamp types for a libpcap device. */
+static GList*
+get_pcap_timestamp_types(pcap_t *pch _U_, char **err_str _U_)
+{
+ GList *list = NULL;
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+ int *types;
+ int ntypes = pcap_list_tstamp_types(pch, &types);
+
+ if (err_str)
+ *err_str = ntypes < 0 ? pcap_geterr(pch) : NULL;
+
+ if (ntypes <= 0)
+ return NULL;
+
+ while (ntypes--) {
+ timestamp_info_t *info = (timestamp_info_t *)g_malloc(sizeof *info);
+ info->name = g_strdup(pcap_tstamp_type_val_to_name(types[ntypes]));
+ info->description = g_strdup(pcap_tstamp_type_val_to_description(types[ntypes]));
+ list = g_list_prepend(list, info);
+ }
+
+ pcap_free_tstamp_types(types);
+#endif
+ return list;
+}
+
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+/*
+ * Request high-resolution time stamps.
+ *
+ * We don't check for errors - if this fails, we just live with boring old
+ * microsecond-resolution time stamps. The only errors pcap_set_tstamp_precision()
+ * is documenting as returning are PCAP_ERROR_TSTAMP_PRECISION_NOTSUP, which just
+ * means we can't do nanosecond precision on this adapter, in which case we
+ * just live with whatever resolution we get by default, and
+ * PCAP_ERROR_ACTIVATED, which shouldn't happen as we shouldn't call this
+ * after we've activated the pcap_t.
+ */
+void
+request_high_resolution_timestamp(pcap_t *pcap_h)
+{
+#ifdef __APPLE__
+ /*
+ * On macOS, if you build with a newer SDK, pcap_set_tstamp_precision()
+ * is available, so the code will be built with it.
+ *
+ * However, if you then try to run on an older release that
+ * doesn't have pcap_set_tstamp_precision(), the dynamic linker
+ * will fail, as it won't find pcap_set_tstamp_precision().
+ *
+ * libpcap doesn't use macOS "weak linking" for new routines,
+ * so we can't just check whether a pointer to
+ * pcap_set_tstamp_precision() is null and, if it is, not
+ * call it. We have to, instead, use dlopen() to load
+ * libpcap, and dlsym() to find a pointer to pcap_set_tstamp_precision(),
+ * and if we find the pointer, call it.
+ */
+ static gboolean initialized = FALSE;
+ static int (*p_pcap_set_tstamp_precision)(pcap_t *, int);
+
+ if (!initialized) {
+ p_pcap_set_tstamp_precision =
+ (int (*)(pcap_t *, int))
+ dlsym(RTLD_NEXT, "pcap_set_tstamp_precision");
+ initialized = TRUE;
+ }
+ if (p_pcap_set_tstamp_precision != NULL)
+ (*p_pcap_set_tstamp_precision)(pcap_h, PCAP_TSTAMP_PRECISION_NANO);
+#else /* __APPLE__ */
+ /*
+ * On other UN*Xes we require that we be run on an OS version
+ * with a libpcap equal to or later than the version with which
+ * we were built.
+ */
+ pcap_set_tstamp_precision(pcap_h, PCAP_TSTAMP_PRECISION_NANO);
+#endif /* __APPLE__ */
+}
+
+/*
+ * Return TRUE if the pcap_t in question is set up for high-precision
+ * time stamps, FALSE otherwise.
+ */
+gboolean
+have_high_resolution_timestamp(pcap_t *pcap_h)
+{
+#ifdef __APPLE__
+ /*
+ * See above.
+ */
+ static gboolean initialized = FALSE;
+ static int (*p_pcap_get_tstamp_precision)(pcap_t *);
+
+ if (!initialized) {
+ p_pcap_get_tstamp_precision =
+ (int (*)(pcap_t *))
+ dlsym(RTLD_NEXT, "pcap_get_tstamp_precision");
+ initialized = TRUE;
+ }
+ if (p_pcap_get_tstamp_precision != NULL)
+ return (*p_pcap_get_tstamp_precision)(pcap_h) == PCAP_TSTAMP_PRECISION_NANO;
+ else
+ return FALSE; /* Can't get implies couldn't set */
+#else /* __APPLE__ */
+ /*
+ * On other UN*Xes we require that we be run on an OS version
+ * with a libpcap equal to or later than the version with which
+ * we were built.
+ */
+ return pcap_get_tstamp_precision(pcap_h) == PCAP_TSTAMP_PRECISION_NANO;
+#endif /* __APPLE__ */
+}
+
+#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
+
+#ifdef HAVE_PCAP_CREATE
+#ifdef HAVE_BONDING
+static gboolean
+is_linux_bonding_device(const char *ifname)
+{
+ int fd;
+ struct ifreq ifr;
+ ifbond ifb;
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd == -1)
+ return FALSE;
+
+ memset(&ifr, 0, sizeof ifr);
+ g_strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
+ memset(&ifb, 0, sizeof ifb);
+ ifr.ifr_data = (caddr_t)&ifb;
+#if defined(SIOCBONDINFOQUERY)
+ if (ioctl(fd, SIOCBONDINFOQUERY, &ifr) == 0) {
+ close(fd);
+ return TRUE;
+ }
+#else
+ if (ioctl(fd, BOND_INFO_QUERY_OLD, &ifr) == 0) {
+ close(fd);
+ return TRUE;
+ }
+#endif
+
+ close(fd);
+ return FALSE;
+}
+#else
+static gboolean
+is_linux_bonding_device(const char *ifname _U_)
+{
+ return FALSE;
+}
+#endif
+
+if_capabilities_t *
+get_if_capabilities_pcap_create(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str)
+{
+ if_capabilities_t *caps;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pch;
+ int status;
+
+ pch = pcap_create(interface_opts->name, errbuf);
+ if (pch == NULL) {
+ *err = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ *err_str = g_strdup(errbuf);
+ return NULL;
+ }
+
+ if (is_linux_bonding_device(interface_opts->name)) {
+ /*
+ * Linux bonding device; not Wi-Fi, so no monitor mode, and
+ * calling pcap_can_set_rfmon() might get a "no such device"
+ * error.
+ */
+ status = 0;
+ } else {
+ /*
+ * Not a Linux bonding device, so go ahead.
+ */
+ status = pcap_can_set_rfmon(pch);
+ }
+ if (status < 0) {
+ /* Error. */
+ if (status == PCAP_ERROR) {
+ *err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *err_str = g_strdup_printf("pcap_can_set_rfmon() failed: %s",
+ pcap_geterr(pch));
+ } else {
+ if (status == PCAP_ERROR_PERM_DENIED)
+ *err = CAP_DEVICE_OPEN_ERR_PERMISSIONS;
+ else
+ *err = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ *err_str = g_strdup(pcap_statustostr(status));
+ }
+ pcap_close(pch);
+ return NULL;
+ }
+ caps = (if_capabilities_t *)g_malloc(sizeof *caps);
+ if (status == 0)
+ caps->can_set_rfmon = FALSE;
+ else if (status == 1) {
+ caps->can_set_rfmon = TRUE;
+ if (interface_opts->monitor_mode)
+ pcap_set_rfmon(pch, 1);
+ } else {
+ *err = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ *err_str = g_strdup_printf("pcap_can_set_rfmon() returned %d",
+ status);
+ pcap_close(pch);
+ g_free(caps);
+ return NULL;
+ }
+
+ status = pcap_activate(pch);
+ if (status < 0) {
+ /* Error. We ignore warnings (status > 0). */
+ if (status == PCAP_ERROR) {
+ *err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *err_str = g_strdup_printf("pcap_activate() failed: %s",
+ pcap_geterr(pch));
+ } else {
+ if (status == PCAP_ERROR_PERM_DENIED)
+ *err = CAP_DEVICE_OPEN_ERR_PERMISSIONS;
+ else
+ *err = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ *err_str = g_strdup(pcap_statustostr(status));
+ }
+ pcap_close(pch);
+ g_free(caps);
+ return NULL;
+ }
+
+ caps->data_link_types = get_data_link_types(pch, interface_opts,
+ err, err_str);
+ if (caps->data_link_types == NULL) {
+ pcap_close(pch);
+ g_free(caps);
+ return NULL;
+ }
+
+ caps->timestamp_types = get_pcap_timestamp_types(pch, NULL);
+
+ pcap_close(pch);
+
+ if (err_str != NULL)
+ *err_str = NULL;
+ return caps;
+}
+
+pcap_t *
+open_capture_device_pcap_create(
+#if defined(HAVE_PCAP_SET_TSTAMP_PRECISION)
+ capture_options* capture_opts,
+#else
+ capture_options* capture_opts _U_,
+#endif
+ interface_options *interface_opts, int timeout,
+ cap_device_open_err *open_err,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ pcap_t *pcap_h;
+ int status;
+
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "Calling pcap_create() using %s.", interface_opts->name);
+ pcap_h = pcap_create(interface_opts->name, *open_err_str);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_create() returned %p.", (void *)pcap_h);
+ if (pcap_h == NULL) {
+ *open_err = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ return NULL;
+ }
+ if (interface_opts->has_snaplen) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "Calling pcap_set_snaplen() with snaplen %d.",
+ interface_opts->snaplen);
+ pcap_set_snaplen(pcap_h, interface_opts->snaplen);
+ }
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "Calling pcap_set_promisc() with promisc_mode %d.",
+ interface_opts->promisc_mode);
+ pcap_set_promisc(pcap_h, interface_opts->promisc_mode);
+ pcap_set_timeout(pcap_h, timeout);
+
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+ /*
+ * If we're writing pcapng files, try to enable
+ * nanosecond-resolution capture; any code that
+ * can read pcapng files must be able to handle
+ * nanosecond-resolution time stamps. We don't
+ * care whether it succeeds or fails - if it fails,
+ * we just use the microsecond-precision time stamps
+ * we get.
+ *
+ * If we're writing pcap files, don't try to enable
+ * nanosecond-resolution capture, as not all code
+ * that reads pcap files recognizes the nanosecond-
+ * resolution pcap file magic number.
+ * We don't care whether this succeeds or fails; if it
+ * fails (because we don't have pcap_set_tstamp_precision(),
+ * or because we do but the OS or device doesn't support
+ * nanosecond resolution timing), we just use microsecond-
+ * resolution time stamps.
+ */
+ if (capture_opts->use_pcapng)
+ request_high_resolution_timestamp(pcap_h);
+#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
+
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+ if (interface_opts->timestamp_type) {
+ status = pcap_set_tstamp_type(pcap_h, interface_opts->timestamp_type_id);
+ /*
+ * XXX - what if it fails because that time stamp type
+ * isn't supported?
+ */
+ if (status == PCAP_ERROR) {
+ *open_err = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ g_strlcpy(*open_err_str, pcap_geterr(pcap_h),
+ sizeof *open_err_str);
+ pcap_close(pcap_h);
+ return NULL;
+ }
+ }
+#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
+
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "buffersize %d.", interface_opts->buffer_size);
+ if (interface_opts->buffer_size != 0)
+ pcap_set_buffer_size(pcap_h,
+ interface_opts->buffer_size * 1024 * 1024);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "monitor_mode %d.", interface_opts->monitor_mode);
+ if (interface_opts->monitor_mode)
+ pcap_set_rfmon(pcap_h, 1);
+ status = pcap_activate(pcap_h);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_activate() returned %d.", status);
+ if (status < 0) {
+ /* Failed to activate, set to NULL */
+ if (status == PCAP_ERROR) {
+ *open_err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ g_strlcpy(*open_err_str, pcap_geterr(pcap_h),
+ sizeof *open_err_str);
+ } else {
+ if (status == PCAP_ERROR_PERM_DENIED)
+ *open_err = CAP_DEVICE_OPEN_ERR_PERMISSIONS;
+ else
+ *open_err = CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS;
+ g_strlcpy(*open_err_str, pcap_statustostr(status),
+ sizeof *open_err_str);
+ }
+ pcap_close(pcap_h);
+ return NULL;
+ }
+ return pcap_h;
+}
+#endif /* HAVE_PCAP_CREATE */
+
+if_capabilities_t *
+get_if_capabilities_pcap_open_live(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str)
+{
+ if_capabilities_t *caps;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pch;
+
+ pch = pcap_open_live(interface_opts->name, MIN_PACKET_SIZE, 0, 0,
+ errbuf);
+ if (pch == NULL) {
+ *err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *err_str = g_strdup(errbuf[0] == '\0' ? "Unknown error (pcap bug; actual error cause not reported)" : errbuf);
+ return NULL;
+ }
+
+ caps = (if_capabilities_t *)g_malloc(sizeof *caps);
+ caps->can_set_rfmon = FALSE;
+ caps->data_link_types = get_data_link_types(pch, interface_opts,
+ err, err_str);
+ if (caps->data_link_types == NULL) {
+ pcap_close(pch);
+ g_free(caps);
+ return NULL;
+ }
+
+ caps->timestamp_types = get_pcap_timestamp_types(pch, NULL);
+
+ pcap_close(pch);
+
+ *err_str = NULL;
+ return caps;
+}
+
+pcap_t *
+open_capture_device_pcap_open_live(interface_options *interface_opts,
+ int timeout, cap_device_open_err *open_err,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ pcap_t *pcap_h;
+ int snaplen;
+
+ if (interface_opts->has_snaplen)
+ snaplen = interface_opts->snaplen;
+ else {
+ /*
+ * Default - use the non-D-Bus maximum snapshot length of
+ * 256KB, which should be big enough (libpcap didn't get
+ * D-Bus support until after it goet pcap_create() and
+ * pcap_activate(), so we don't have D-Bus support and
+ * don't have to worry about really huge packets).
+ */
+ snaplen = 256*1024;
+ }
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_open_live() calling using name %s, snaplen %d, promisc_mode %d.",
+ interface_opts->name, snaplen, interface_opts->promisc_mode);
+ pcap_h = pcap_open_live(interface_opts->name, snaplen,
+ interface_opts->promisc_mode, timeout, *open_err_str);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_open_live() returned %p.", (void *)pcap_h);
+ if (pcap_h == NULL) {
+ *open_err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ return NULL;
+ }
+
+#ifdef _WIN32
+ /* Try to set the capture buffer size. */
+ if (interface_opts->buffer_size > 1) {
+ /*
+ * We have no mechanism to report a warning if this
+ * fails; we just keep capturing with the smaller buffer,
+ * as is the case on systems with BPF and pcap_create()
+ * and pcap_set_buffer_size(), where pcap_activate() just
+ * silently clamps the buffer size to the maximum.
+ */
+ pcap_setbuff(pcap_h, interface_opts->buffer_size * 1024 * 1024);
+ }
+#endif
+
+ return pcap_h;
+}
+
+/*
+ * Get the capabilities of a network device.
+ */
+if_capabilities_t *
+get_if_capabilities(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str)
+{
+#if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE)
+ if_capabilities_t *caps;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *pch;
+ int deflt;
+ data_link_info_t *data_link_info;
+
+ if (strncmp (interface_opts->name, "rpcap://", 8) == 0) {
+ struct pcap_rmtauth auth;
+
+ auth.type = interface_opts->auth_type == CAPTURE_AUTH_PWD ?
+ RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
+ auth.username = interface_opts->auth_username;
+ auth.password = interface_opts->auth_password;
+
+ /*
+ * WinPcap 4.1.2, and possibly earlier versions, have a bug
+ * wherein, when an open with an rpcap: URL fails, the error
+ * message for the error is not copied to errbuf and whatever
+ * on-the-stack junk is in errbuf is treated as the error
+ * message.
+ *
+ * To work around that (and any other bugs of that sort), we
+ * initialize errbuf to an empty string. If we get an error
+ * and the string is empty, we report it as an unknown error.
+ * (If we *don't* get an error, and the string is *non*-empty,
+ * that could be a warning returned, such as "can't turn
+ * promiscuous mode on"; we currently don't do so.)
+ */
+ errbuf[0] = '\0';
+ pch = pcap_open(interface_opts->name, MIN_PACKET_SIZE, 0, 0, &auth,
+ errbuf);
+ if (pch == NULL) {
+ /*
+ * We don't know whether it's a permission error or not.
+ * (If it is, maybe we can give ourselves permission or
+ * maybe we just have to ask politely for permission.)
+ */
+ *err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ *err_str = g_strdup(errbuf[0] == '\0' ? "Unknown error (pcap bug; actual error cause not reported)" : errbuf);
+ return NULL;
+ }
+
+ caps = (if_capabilities_t *)g_malloc(sizeof *caps);
+ caps->can_set_rfmon = FALSE;
+ caps->data_link_types = NULL;
+ deflt = get_pcap_datalink(pch, interface_opts->name);
+ data_link_info = create_data_link_info(deflt);
+ caps->data_link_types = g_list_append(caps->data_link_types, data_link_info);
+ caps->timestamp_types = get_pcap_timestamp_types(pch, NULL);
+ pcap_close(pch);
+
+ *err_str = NULL;
+ return caps;
+ }
+#endif /* defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE) */
+
+ /*
+ * Local interface.
+ */
+ return get_if_capabilities_local(interface_opts, err, err_str);
+}
+
+pcap_t *
+open_capture_device(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ cap_device_open_err *open_err,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ pcap_t *pcap_h;
+#if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE)
+ struct pcap_rmtauth auth;
+#endif
+
+ /* Open the network interface to capture from it.
+ Some versions of libpcap may put warnings into the error buffer
+ if they succeed; to tell if that's happened, we have to clear
+ the error buffer, and check if it's still a null string. */
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Entering open_capture_device().");
+ *open_err = CAP_DEVICE_OPEN_NO_ERR;
+ (*open_err_str)[0] = '\0';
+#if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE)
+ /*
+ * If we're opening a remote device, use pcap_open(); that's currently
+ * the only open routine that supports remote devices.
+ */
+ if (strncmp (interface_opts->name, "rpcap://", 8) == 0) {
+ int snaplen;
+
+ auth.type = interface_opts->auth_type == CAPTURE_AUTH_PWD ?
+ RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
+ auth.username = interface_opts->auth_username;
+ auth.password = interface_opts->auth_password;
+
+ if (interface_opts->has_snaplen)
+ snaplen = interface_opts->snaplen;
+ else {
+ /*
+ * Default - use the non-D-Bus maximum snapshot length,
+ * which should be big enough, except for D-Bus.
+ */
+ snaplen = 256*1024;
+ }
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "Calling pcap_open() using name %s, snaplen %d, promisc_mode %d, datatx_udp %d, nocap_rpcap %d.",
+ interface_opts->name, snaplen,
+ interface_opts->promisc_mode, interface_opts->datatx_udp,
+ interface_opts->nocap_rpcap);
+ pcap_h = pcap_open(interface_opts->name, snaplen,
+ /* flags */
+ (interface_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
+ (interface_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
+ (interface_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
+ timeout, &auth, *open_err_str);
+ if (pcap_h == NULL) {
+ /*
+ * Error.
+ *
+ * We don't know whether it's a permission error
+ * or not.
+ * (If it is, maybe we can give ourselves permission
+ * or maybe we just have to ask politely for
+ * permission.)
+ */
+ *open_err = CAP_DEVICE_OPEN_ERR_GENERIC;
+ /* Did pcap actually supply an error message? */
+ if ((*open_err_str)[0] == '\0') {
+ /*
+ * Work around known WinPcap bug wherein
+ * no error message is filled in on a
+ * failure to open an rpcap: URL.
+ */
+ g_strlcpy(*open_err_str,
+ "Unknown error (pcap bug; actual error cause not reported)",
+ sizeof *open_err_str);
+ }
+ }
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
+ "pcap_open() returned %p.", (void *)pcap_h);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "open_capture_device %s : %s", pcap_h ? "SUCCESS" : "FAILURE", interface_opts->name);
+ return pcap_h;
+ }
+#endif
+
+ pcap_h = open_capture_device_local(capture_opts, interface_opts,
+ timeout, open_err, open_err_str);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "open_capture_device %s : %s", pcap_h ? "SUCCESS" : "FAILURE", interface_opts->name);
+ return pcap_h;
+}
+
+#endif /* HAVE_LIBPCAP */
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/capture/capture-pcap-util.h b/capture/capture-pcap-util.h
new file mode 100644
index 0000000000..33c87c2542
--- /dev/null
+++ b/capture/capture-pcap-util.h
@@ -0,0 +1,93 @@
+/* capture-pcap-util.h
+ * Utility definitions for packet capture
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __CAPTURE_PCAP_UTIL_H__
+#define __CAPTURE_PCAP_UTIL_H__
+
+#ifdef HAVE_LIBPCAP
+
+#include "wspcap.h"
+
+#include "capture_opts.h"
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef HAVE_LIBPCAP
+/*
+ * A snapshot length of 0 is useless - and libpcap/WinPcap/Npcap 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 /* HAVE_PCAP_REMOTE */
+
+const char *linktype_val_to_name(int dlt);
+int linktype_name_to_val(const char *linktype);
+
+int get_pcap_datalink(pcap_t *pch, const char *devicename);
+
+gboolean set_pcap_datalink(pcap_t *pcap_h, int datalink, char *name,
+ char *errmsg, size_t errmsg_len,
+ char *secondary_errmsg, size_t secondary_errmsg_len);
+
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+/*
+ * Return TRUE if the pcap_t in question is set up for high-precision
+ * time stamps, FALSE otherwise.
+ */
+gboolean have_high_resolution_timestamp(pcap_t *pcap_h);
+#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
+
+/*
+ * Error values.
+ */
+typedef enum {
+ CAP_DEVICE_OPEN_NO_ERR, /* No error */
+ CAP_DEVICE_OPEN_ERR_PERMISSIONS, /* Error is known to be a permissions error */
+ CAP_DEVICE_OPEN_ERR_NOT_PERMISSIONS, /* Error is known not to be a permissions error */
+ CAP_DEVICE_OPEN_ERR_GENERIC /* Error is not known to be one or the other */
+} cap_device_open_err;
+extern if_capabilities_t *get_if_capabilities(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str);
+extern pcap_t *open_capture_device(capture_options *capture_opts,
+ interface_options *interface_opts,
+ int timeout, cap_device_open_err *open_err,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE]);
+
+#endif /* HAVE_LIBPCAP */
+
+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 or Npcap but
+ * WinPcap/Npcap wasn't loaded, or nothing, if we weren't compiled with
+ * libpcap/WinPcap/Npcap.
+ */
+extern void get_runtime_caplibs_version(GString *str);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CAPTURE_PCAP_UTIL_H__ */
diff --git a/capture/capture-wpcap.c b/capture/capture-wpcap.c
new file mode 100644
index 0000000000..c3d8fdfea4
--- /dev/null
+++ b/capture/capture-wpcap.c
@@ -0,0 +1,915 @@
+/* capture-wpcap.c
+ * WinPcap/Npcap-specific interfaces for capturing. We load WinPcap/Npcap
+ * at run time, so that we only need one Wireshark binary and one TShark
+ * binary for Windows, regardless of whether WinPcap/Npcap is installed
+ * or not.
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <windows.h>
+#include <wchar.h>
+#include <tchar.h>
+
+#include <stdio.h>
+#include <glib.h>
+
+#include "capture/capture-wpcap.h"
+
+gboolean has_wpcap = FALSE;
+
+#ifdef HAVE_LIBPCAP
+
+#include <gmodule.h>
+
+#include <epan/strutil.h>
+
+#include "capture/capture_ifinfo.h"
+#include "capture/capture-pcap-util.h"
+#include "capture/capture-pcap-util-int.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
+
+/*
+ * XXX - should we require at least WinPcap 3.1 both for building an
+ * for using Wireshark?
+ */
+
+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 *);
+static pcap_t* (*p_pcap_open_dead) (int, int);
+static void (*p_pcap_freecode) (struct bpf_program *);
+static int (*p_pcap_findalldevs) (pcap_if_t **, char *);
+static void (*p_pcap_freealldevs) (pcap_if_t *);
+static int (*p_pcap_datalink_name_to_val) (const char *);
+static const char *(*p_pcap_datalink_val_to_name) (int);
+static const char *(*p_pcap_datalink_val_to_description) (int);
+static void (*p_pcap_breakloop) (pcap_t *);
+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) (const 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
+
+static int (*p_pcap_list_datalinks)(pcap_t *, int **);
+static int (*p_pcap_set_datalink)(pcap_t *, int);
+
+#ifdef HAVE_PCAP_FREE_DATALINKS
+static int (*p_pcap_free_datalinks)(int *);
+#endif
+
+static char *(*p_bpf_image)(const struct bpf_insn *, int);
+
+#ifdef HAVE_PCAP_CREATE
+static pcap_t *(*p_pcap_create)(const char *, char *);
+static int (*p_pcap_set_snaplen)(pcap_t *, int);
+static int (*p_pcap_set_promisc)(pcap_t *, int);
+static int (*p_pcap_can_set_rfmon)(pcap_t *);
+static int (*p_pcap_set_rfmon)(pcap_t *, int);
+static int (*p_pcap_set_timeout)(pcap_t *, int);
+static int (*p_pcap_set_buffer_size)(pcap_t *, int);
+static int (*p_pcap_activate)(pcap_t *);
+static const char *(*p_pcap_statustostr)(int);
+#endif
+
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+static int (*p_pcap_set_tstamp_type)(pcap_t *, int);
+static int (*p_pcap_set_tstamp_precision)(pcap_t *, int);
+static int (*p_pcap_get_tstamp_precision)(pcap_t *);
+static int (*p_pcap_list_tstamp_types)(pcap_t *, int **);
+static void (*p_pcap_free_tstamp_types)(int *);
+static int (*p_pcap_tstamp_type_name_to_val)(const char *);
+static const char * (*p_pcap_tstamp_type_val_to_name)(int);
+static const char * (*p_pcap_tstamp_type_val_to_description)(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_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),
+ SYM(pcap_open_dead, FALSE),
+#ifdef HAVE_PCAP_SETSAMPLING
+ SYM(pcap_setsampling, TRUE),
+#endif
+ SYM(pcap_loop, FALSE),
+ SYM(pcap_freecode, FALSE),
+ SYM(pcap_findalldevs, FALSE),
+ SYM(pcap_freealldevs, FALSE),
+ SYM(pcap_datalink_name_to_val, FALSE),
+ SYM(pcap_datalink_val_to_name, FALSE),
+ SYM(pcap_datalink_val_to_description, FALSE),
+ SYM(pcap_breakloop, FALSE),
+ SYM(pcap_lib_version, FALSE),
+ SYM(pcap_setbuff, TRUE),
+ SYM(pcap_next_ex, TRUE),
+ SYM(pcap_list_datalinks, FALSE),
+ SYM(pcap_set_datalink, FALSE),
+#ifdef HAVE_PCAP_FREE_DATALINKS
+ SYM(pcap_free_datalinks, TRUE),
+#endif
+ SYM(bpf_image, FALSE),
+#ifdef HAVE_PCAP_CREATE
+ SYM(pcap_create, TRUE),
+ SYM(pcap_set_snaplen, TRUE),
+ SYM(pcap_set_promisc, TRUE),
+ SYM(pcap_can_set_rfmon, TRUE),
+ SYM(pcap_set_rfmon, TRUE),
+ SYM(pcap_set_timeout, FALSE),
+ SYM(pcap_set_buffer_size, FALSE),
+ SYM(pcap_activate, TRUE),
+ SYM(pcap_statustostr, TRUE),
+#endif
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+ SYM(pcap_set_tstamp_type, TRUE),
+ SYM(pcap_set_tstamp_precision, TRUE),
+ SYM(pcap_get_tstamp_precision, TRUE),
+ SYM(pcap_list_tstamp_types, TRUE),
+ SYM(pcap_free_tstamp_types, TRUE),
+ SYM(pcap_tstamp_type_name_to_val, TRUE),
+ SYM(pcap_tstamp_type_val_to_name, TRUE),
+ SYM(pcap_tstamp_type_val_to_description, TRUE),
+#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;
+}
+
+static char *
+local_code_page_str_to_utf8(char *str)
+{
+ ULONG utf16_len;
+ wchar_t *utf16_str;
+ char *utf8_str;
+
+ if (str == NULL) {
+ return NULL;
+ }
+
+ utf16_len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+ utf16_str = g_malloc_n(utf16_len, sizeof(wchar_t));
+ MultiByteToWideChar(CP_ACP, 0, str, -1, utf16_str, utf16_len);
+
+ utf8_str = g_utf16_to_utf8(utf16_str, -1, NULL, NULL, NULL);
+
+ g_free(utf16_str);
+ return utf8_str;
+}
+
+static void
+prepare_errbuf(char *errbuf)
+{
+ g_assert(errbuf);
+ errbuf[0] = '\0';
+}
+
+static void
+convert_errbuf_to_utf8(char *errbuf)
+{
+ gchar *utf8_err;
+ if (errbuf[0] == '\0') {
+ return;
+ }
+ errbuf[PCAP_ERRBUF_SIZE - 1] = '\0';
+ utf8_err = local_code_page_str_to_utf8(errbuf);
+ g_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", utf8_err);
+ g_free(utf8_err);
+}
+
+static char *
+cant_load_winpcap_err(const char *app_name)
+{
+ return g_strdup_printf(
+"Unable to load Npcap or WinPcap (wpcap.dll); %s will not be able to\n"
+"capture packets.\n"
+"\n"
+"In order to capture packets Npcap or WinPcap must be installed. See\n"
+"\n"
+" https://nmap.org/npcap/\n"
+"\n"
+"for a downloadable version of Npcap and for instructions on how to\n"
+"install it.",
+ app_name);
+}
+
+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);
+}
+
+int
+pcap_set_datalink(pcap_t *p, int dlt)
+{
+ g_assert(has_wpcap);
+ return p_pcap_set_datalink(p, dlt);
+}
+
+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)
+{
+ char *errbuf;
+ g_assert(has_wpcap);
+ errbuf = p_pcap_geterr(a);
+ convert_errbuf_to_utf8(errbuf);
+ return errbuf;
+}
+
+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 *errbuf)
+{
+ int ret;
+ g_assert(has_wpcap);
+ ret = p_pcap_lookupnet(a, b, c, errbuf);
+ if (ret == -1)
+ convert_errbuf_to_utf8(errbuf);
+ return ret;
+}
+
+pcap_t*
+pcap_open_live(const char *a, int b, int c, int d, char *errbuf)
+{
+ pcap_t *p;
+ if (!has_wpcap) {
+ g_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "unable to load Npcap or WinPcap (wpcap.dll); can't open %s to capture",
+ a);
+ return NULL;
+ }
+ prepare_errbuf(errbuf);
+ p = p_pcap_open_live(a, b, c, d, errbuf);
+ convert_errbuf_to_utf8(errbuf);
+ return p;
+}
+
+pcap_t*
+pcap_open_dead(int a, int b)
+{
+ if (!has_wpcap) {
+ return NULL;
+ }
+ return p_pcap_open_dead(a, b);
+}
+
+char *
+bpf_image(const struct bpf_insn *a, int b)
+{
+ if (!has_wpcap) {
+ return NULL;
+ }
+ return p_bpf_image(a, b);
+}
+
+#ifdef HAVE_PCAP_REMOTE
+pcap_t*
+pcap_open(const char *a, int b, int c, int d, struct pcap_rmtauth *e, char *errbuf)
+{
+ pcap_t *ret;
+ if (!has_wpcap) {
+ g_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "unable to load Npcap or WinPcap (wpcap.dll); can't open %s to capture",
+ a);
+ return NULL;
+ }
+ prepare_errbuf(errbuf);
+ ret = p_pcap_open(a, b, c, d, e, errbuf);
+ convert_errbuf_to_utf8(errbuf);
+ return ret;
+}
+
+int
+pcap_findalldevs_ex(const char *a, struct pcap_rmtauth *b, pcap_if_t **c, char *errbuf)
+{
+ int ret;
+ g_assert(has_wpcap);
+ ret = p_pcap_findalldevs_ex(a, b, c, errbuf);
+ if (ret == -1)
+ convert_errbuf_to_utf8(errbuf);
+ return ret;
+}
+
+int
+pcap_createsrcstr(char *a, int b, const char *c, const char *d, const char *e,
+ char *errbuf)
+{
+ int ret;
+ g_assert(has_wpcap);
+ ret = p_pcap_createsrcstr(a, b, c, d, e, errbuf);
+ if (ret == -1)
+ convert_errbuf_to_utf8(errbuf);
+ return ret;
+}
+#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);
+ p_pcap_freecode(a);
+}
+
+int
+pcap_findalldevs(pcap_if_t **a, char *errbuf)
+{
+ int ret;
+ g_assert(has_wpcap);
+ ret = p_pcap_findalldevs(a, errbuf);
+ if (ret == -1)
+ convert_errbuf_to_utf8(errbuf);
+ return ret;
+}
+
+void
+pcap_freealldevs(pcap_if_t *a)
+{
+ g_assert(has_wpcap);
+ p_pcap_freealldevs(a);
+}
+
+#ifdef HAVE_PCAP_CREATE
+pcap_t *
+pcap_create(const char *a, char *errbuf)
+{
+ pcap_t *p;
+ g_assert(has_wpcap && p_pcap_create != NULL);
+ p = p_pcap_create(a, errbuf);
+ if (p == NULL)
+ convert_errbuf_to_utf8(errbuf);
+ return p;
+}
+
+int
+pcap_set_snaplen(pcap_t *a, int b)
+{
+ g_assert(has_wpcap && p_pcap_set_snaplen != NULL);
+ return p_pcap_set_snaplen(a, b);
+}
+
+int
+pcap_set_promisc(pcap_t *a, int b)
+{
+ g_assert(has_wpcap && p_pcap_set_promisc != NULL);
+ return p_pcap_set_promisc(a, b);
+}
+
+int
+pcap_can_set_rfmon(pcap_t *a)
+{
+ g_assert(has_wpcap);
+ if (p_pcap_can_set_rfmon != NULL) {
+ return p_pcap_can_set_rfmon(a);
+ }
+ return 0;
+}
+
+int
+pcap_set_rfmon(pcap_t *a, int b)
+{
+ g_assert(has_wpcap && p_pcap_set_rfmon != NULL);
+ return p_pcap_set_rfmon(a, b);
+}
+
+int
+pcap_set_timeout(pcap_t *a, int b)
+{
+ g_assert(has_wpcap && p_pcap_set_timeout != NULL);
+ return p_pcap_set_timeout(a, b);
+}
+int
+pcap_set_buffer_size(pcap_t *a, int b)
+{
+ g_assert(has_wpcap && p_pcap_set_buffer_size != NULL);
+ return p_pcap_set_buffer_size(a, b);
+}
+
+int
+pcap_activate(pcap_t *a)
+{
+ g_assert(has_wpcap && p_pcap_activate != NULL);
+ return p_pcap_activate(a);
+
+}
+
+const char *
+pcap_statustostr(int a)
+{
+ static char ebuf[15 + 10 + 1];
+
+ g_assert(has_wpcap);
+ if (p_pcap_statustostr != NULL) {
+ return p_pcap_statustostr(a);
+ }
+
+ /* XXX copy routine from pcap.c ??? */
+ (void)g_snprintf(ebuf, sizeof ebuf, "Don't have pcap_statustostr(), can't translate error: %d", a);
+ return(ebuf);
+
+}
+#endif
+
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+int
+pcap_set_tstamp_type(pcap_t *a, int b) {
+ g_assert(has_wpcap);
+ if (p_pcap_set_tstamp_type != NULL) {
+ return p_pcap_set_tstamp_type(a, b);
+ }
+ return PCAP_ERROR_CANTSET_TSTAMP_TYPE;
+}
+
+int
+pcap_set_tstamp_precision(pcap_t *a, int b) {
+ g_assert(has_wpcap);
+ if (p_pcap_set_tstamp_precision != NULL) {
+ return p_pcap_set_tstamp_precision(a, b);
+ }
+ // No error code defined so return NOTSUP.
+ return PCAP_ERROR_TSTAMP_PRECISION_NOTSUP;
+}
+
+int
+pcap_get_tstamp_precision(pcap_t *a) {
+ g_assert(has_wpcap);
+ if (p_pcap_get_tstamp_precision != NULL) {
+ return p_pcap_get_tstamp_precision(a);
+ }
+ // No error code defined so return MICRO.
+ return PCAP_TSTAMP_PRECISION_MICRO;
+}
+
+int
+pcap_list_tstamp_types(pcap_t *a, int **b) {
+ g_assert(has_wpcap);
+ if (p_pcap_list_tstamp_types != NULL) {
+ return p_pcap_list_tstamp_types(a, b);
+ }
+ return PCAP_ERROR;
+}
+
+void
+pcap_free_tstamp_types(int *a) {
+ g_assert(has_wpcap);
+ if (p_pcap_free_tstamp_types != NULL) {
+ p_pcap_free_tstamp_types(a);
+ }
+}
+
+int
+pcap_tstamp_type_name_to_val(const char *a) {
+ g_assert(has_wpcap);
+ if (p_pcap_tstamp_type_name_to_val != NULL) {
+ return p_pcap_tstamp_type_name_to_val(a);
+ }
+ return PCAP_ERROR;
+}
+
+const char *
+pcap_tstamp_type_val_to_name(int a) {
+ g_assert(has_wpcap);
+ if (p_pcap_tstamp_type_val_to_name != NULL) {
+ return p_pcap_tstamp_type_val_to_name(a);
+ }
+ return NULL;
+}
+
+const char *
+pcap_tstamp_type_val_to_description(int a) {
+ g_assert(has_wpcap);
+ if (p_pcap_tstamp_type_val_to_description != NULL) {
+ return p_pcap_tstamp_type_val_to_description(a);
+ }
+ return NULL;
+}
+#endif
+
+int
+pcap_datalink_name_to_val(const char *name)
+{
+ if (has_wpcap)
+ return p_pcap_datalink_name_to_val(name);
+ else
+ return -1;
+}
+
+int
+pcap_list_datalinks(pcap_t *p, int **ddlt)
+{
+ if (has_wpcap)
+ return p_pcap_list_datalinks(p, ddlt);
+ else
+ return -1;
+}
+
+#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
+
+const char *
+pcap_datalink_val_to_name(int dlt)
+{
+ if (has_wpcap)
+ return p_pcap_datalink_val_to_name(dlt);
+ else
+ return NULL;
+}
+
+const char *
+pcap_datalink_val_to_description(int dlt)
+{
+ if (has_wpcap)
+ return p_pcap_datalink_val_to_description(dlt);
+ return NULL;
+}
+
+void pcap_breakloop(pcap_t *a)
+{
+ p_pcap_breakloop(a);
+}
+
+/* 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)
+{
+ if (!has_wpcap) {
+ /*
+ * We don't have Npcap or WinPcap, so we can't get a list of
+ * interfaces.
+ */
+ *err = DONT_HAVE_PCAP;
+ if (err_str != NULL)
+ *err_str = cant_load_winpcap_err("you");
+ return NULL;
+ }
+
+ return get_interface_list_findalldevs_ex(hostname, port, auth_type,
+ username, passwd, err, err_str);
+}
+#endif
+
+GList *
+get_interface_list(int *err, char **err_str)
+{
+ if (!has_wpcap) {
+ /*
+ * We don't have Npcap or WinPcap, so we can't get a list of
+ * interfaces.
+ */
+ *err = DONT_HAVE_PCAP;
+ if (err_str != NULL)
+ *err_str = cant_load_winpcap_err("you");
+ return NULL;
+ }
+
+ return get_interface_list_findalldevs(err, err_str);
+}
+
+/*
+ * 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"
+"Npcap. See https://nmap.org/npcap/ for more information.",
+ err_str);
+ }
+ return g_strdup_printf("Can't get list of interfaces: %s", err_str);
+}
+
+if_capabilities_t *
+get_if_capabilities_local(interface_options *interface_opts,
+ cap_device_open_err *err, char **err_str)
+{
+ /*
+ * We're not getting capaibilities for a remote device; use
+ * pcap_create() and pcap_activate() if we have them, so that
+ * we can set various options, otherwise use pcap_open_live().
+ */
+#ifdef HAVE_PCAP_CREATE
+ if (p_pcap_create != NULL)
+ return get_if_capabilities_pcap_create(interface_opts, err, err_str);
+#endif
+ return get_if_capabilities_pcap_open_live(interface_opts, err, err_str);
+}
+
+pcap_t *
+open_capture_device_local(capture_options *capture_opts,
+ interface_options *interface_opts, int timeout,
+ cap_device_open_err *open_err,
+ char (*open_err_str)[PCAP_ERRBUF_SIZE])
+{
+ /*
+ * We're not opening a remote device; use pcap_create() and
+ * pcap_activate() if we have them, so that we can set various
+ * options, otherwise use pcap_open_live().
+ */
+#ifdef HAVE_PCAP_CREATE
+ if (p_pcap_create != NULL)
+ return open_capture_device_pcap_create(capture_opts,
+ interface_opts, timeout, open_err, open_err_str);
+#endif
+ return open_capture_device_pcap_open_live(interface_opts, timeout,
+ open_err, open_err_str);
+}
+
+/*
+ * Append the WinPcap or Npcap SDK version with which we were compiled to a GString.
+ */
+void
+get_compiled_caplibs_version(GString *str)
+{
+ g_string_append(str, "with libpcap");
+}
+
+/*
+ * Append the version of Npcap with which we we're running to a GString.
+ */
+void
+get_runtime_caplibs_version(GString *str)
+{
+ /*
+ * On Windows, we might have been compiled with WinPcap/Npcap but
+ * might not have it loaded; indicate whether we have it or
+ * not and, if we have it, what version we have.
+ */
+ if (has_wpcap) {
+ g_string_append_printf(str, "with ");
+ g_string_append_printf(str, p_pcap_lib_version());
+ } else
+ g_string_append(str, "without Npcap or WinPcap");
+}
+
+/*
+ * If npf.sys is running, return TRUE.
+ */
+gboolean
+npf_sys_is_running(void)
+{
+ SC_HANDLE h_scm, h_serv;
+ SERVICE_STATUS ss;
+
+ h_scm = OpenSCManager(NULL, NULL, 0);
+ if (!h_scm)
+ return FALSE;
+
+ h_serv = OpenService(h_scm, _T("npcap"), SC_MANAGER_CONNECT|SERVICE_QUERY_STATUS);
+ if (!h_serv) {
+ h_serv = OpenService(h_scm, _T("npf"), SC_MANAGER_CONNECT|SERVICE_QUERY_STATUS);
+ if (!h_serv) {
+ CloseServiceHandle(h_scm);
+ return FALSE;
+ }
+ }
+
+ if (QueryServiceStatus(h_serv, &ss)) {
+ if (ss.dwCurrentState & SERVICE_RUNNING) {
+ CloseServiceHandle(h_serv);
+ CloseServiceHandle(h_scm);
+ return TRUE;
+ }
+ }
+ CloseServiceHandle(h_serv);
+ CloseServiceHandle(h_scm);
+ return FALSE;
+}
+
+#else /* HAVE_LIBPCAP */
+
+void
+load_wpcap(void)
+{
+ return;
+}
+
+/*
+ * Append an indication that we were not compiled with WinPcap
+ * to a GString.
+ */
+void
+get_compiled_caplibs_version(GString *str)
+{
+ g_string_append(str, "without Npcap or WinPcap");
+}
+
+/*
+ * Don't append anything, as we weren't even compiled to use WinPcap/Npcap.
+ */
+void
+get_runtime_caplibs_version(GString *str _U_)
+{
+}
+
+#endif /* HAVE_LIBPCAP */
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/capture/capture-wpcap.h b/capture/capture-wpcap.h
new file mode 100644
index 0000000000..3e18a79de4
--- /dev/null
+++ b/capture/capture-wpcap.h
@@ -0,0 +1,32 @@
+/* capture-wpcap.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 2001 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef CAPTURE_WPCAP_H
+#define CAPTURE_WPCAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern gboolean has_wpcap;
+
+extern void load_wpcap(void);
+
+/**
+ * Check to see if npf.sys is running.
+ * @return TRUE if npf.sys is running, FALSE if it's not or if there was
+ * an error checking its status.
+ */
+gboolean npf_sys_is_running(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CAPTURE_WPCAP_H */
diff --git a/capture/capture_ifinfo.c b/capture/capture_ifinfo.c
new file mode 100644
index 0000000000..d8f2d33bc9
--- /dev/null
+++ b/capture/capture_ifinfo.c
@@ -0,0 +1,373 @@
+/* capture_ifinfo.c
+ * Routines for getting interface information from dumpcap
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LIBPCAP
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include "capture_opts.h"
+
+#include "capture/capture_session.h"
+#include "capture/capture_sync.h"
+#include "extcap.h"
+#include "log.h"
+
+#include <capture/capture_ifinfo.h>
+#include <wsutil/inet_addr.h>
+
+#ifdef HAVE_PCAP_REMOTE
+static GList *remote_interface_list = NULL;
+
+static GList * append_remote_list(GList *iflist)
+{
+ GSList *list;
+ GList *rlist;
+ if_addr_t *if_addr, *temp_addr;
+ if_info_t *if_info, *temp;
+
+ for (rlist = g_list_nth(remote_interface_list, 0); rlist != NULL; rlist = g_list_next(rlist)) {
+ if_info = (if_info_t *)rlist->data;
+ temp = g_new0(if_info_t, 1);
+ temp->name = g_strdup(if_info->name);
+ temp->friendly_name = g_strdup(if_info->friendly_name);
+ temp->vendor_description = g_strdup(if_info->vendor_description);
+ for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
+ temp_addr = g_new0(if_addr_t, 1);
+ if_addr = (if_addr_t *)list->data;
+ if (if_addr) {
+ temp_addr->ifat_type = if_addr->ifat_type;
+ if (temp_addr->ifat_type == IF_AT_IPv4) {
+ temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
+ } else {
+ memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
+ }
+ } else {
+ g_free(temp_addr);
+ temp_addr = NULL;
+ }
+ if (temp_addr) {
+ temp->addrs = g_slist_append(temp->addrs, temp_addr);
+ }
+ }
+ temp->loopback = if_info->loopback;
+ iflist = g_list_append(iflist, temp);
+ }
+ return iflist;
+}
+#endif
+
+/**
+ * Fetch the interface list from a child process (dumpcap).
+ *
+ * @return A GList containing if_info_t structs if successful, NULL (with err and possibly err_str set) otherwise.
+ *
+ */
+
+/* XXX - We parse simple text output to get our interface list. Should
+ * we use "real" data serialization instead, e.g. via XML? */
+GList *
+capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
+{
+ int ret;
+ GList *if_list = NULL;
+ int i, j;
+ gchar *data, *primary_msg, *secondary_msg;
+ gchar **raw_list, **if_parts, **addr_parts;
+ gchar *name;
+ if_info_t *if_info;
+ if_addr_t *if_addr;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
+
+ *err = 0;
+ if (err_str) {
+ *err_str = NULL;
+ }
+
+ /* Try to get our interface list */
+ ret = sync_interface_list_open(&data, &primary_msg, &secondary_msg, update_cb);
+ if (ret != 0) {
+ /* Add the extcap interfaces that can exist, even if no native interfaces have been found */
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Loading External Capture Interface List ...");
+ if_list = append_extcap_interface_list(if_list, err_str);
+ /* err_str is ignored, as the error for the interface loading list will take precedence */
+ if ( g_list_length(if_list) == 0 ) {
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed. Error %d, %s (%s)",
+ *err, primary_msg ? primary_msg : "no message",
+ secondary_msg ? secondary_msg : "no secondary message");
+ if (err_str) {
+ *err_str = primary_msg;
+ } else {
+ g_free(primary_msg);
+ }
+ g_free(secondary_msg);
+ *err = CANT_GET_INTERFACE_LIST;
+
+ }
+ return if_list;
+ }
+
+ /* Split our lines */
+#ifdef _WIN32
+ raw_list = g_strsplit(data, "\r\n", 0);
+#else
+ raw_list = g_strsplit(data, "\n", 0);
+#endif
+ g_free(data);
+
+ for (i = 0; raw_list[i] != NULL; i++) {
+ if_parts = g_strsplit(raw_list[i], "\t", 7);
+ if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
+ if_parts[3] == NULL || if_parts[4] == NULL || if_parts[5] == NULL ||
+ if_parts[6] == NULL) {
+ g_strfreev(if_parts);
+ continue;
+ }
+
+ /* Number followed by the name, e.g "1. eth0" */
+ name = strchr(if_parts[0], ' ');
+ if (name) {
+ name++;
+ } else {
+ g_strfreev(if_parts);
+ continue;
+ }
+
+ if_info = g_new0(if_info_t,1);
+ if_info->name = g_strdup(name);
+ if (strlen(if_parts[1]) > 0)
+ if_info->vendor_description = g_strdup(if_parts[1]);
+ if (strlen(if_parts[2]) > 0)
+ if_info->friendly_name = g_strdup(if_parts[2]);
+ if_info->type = (interface_type)(int)strtol(if_parts[3], NULL, 10);
+ addr_parts = g_strsplit(if_parts[4], ",", 0);
+ for (j = 0; addr_parts[j] != NULL; j++) {
+ if_addr = g_new0(if_addr_t,1);
+ if (ws_inet_pton4(addr_parts[j], &if_addr->addr.ip4_addr)) {
+ if_addr->ifat_type = IF_AT_IPv4;
+ } else if (ws_inet_pton6(addr_parts[j], (ws_in6_addr *)&if_addr->addr.ip6_addr)) {
+ if_addr->ifat_type = IF_AT_IPv6;
+ } else {
+ g_free(if_addr);
+ if_addr = NULL;
+ }
+ if (if_addr) {
+ if_info->addrs = g_slist_append(if_info->addrs, if_addr);
+ }
+ }
+ if (strcmp(if_parts[5], "loopback") == 0)
+ if_info->loopback = TRUE;
+ if_info->extcap = g_strdup(if_parts[6]);
+ g_strfreev(if_parts);
+ g_strfreev(addr_parts);
+ if_list = g_list_append(if_list, if_info);
+ }
+ g_strfreev(raw_list);
+
+#ifdef HAVE_PCAP_REMOTE
+ if (remote_interface_list && g_list_length(remote_interface_list) > 0) {
+ if_list = append_remote_list(if_list);
+ }
+#endif
+
+ /* Add the extcap interfaces after the native and remote interfaces */
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Loading External Capture Interface List ...");
+ if_list = append_extcap_interface_list(if_list, err_str);
+
+ return if_list;
+}
+
+/* XXX - We parse simple text output to get our interface list. Should
+ * we use "real" data serialization instead, e.g. via XML? */
+if_capabilities_t *
+capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode,
+ const gchar *auth_string,
+ char **err_primary_msg, char **err_secondary_msg,
+ void (*update_cb)(void))
+{
+ if_capabilities_t *caps;
+ GList *linktype_list = NULL, *timestamp_list = NULL;
+ int err, i;
+ gchar *data, *primary_msg, *secondary_msg;
+ gchar **raw_list;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities ...");
+
+ /* see if the interface is from extcap */
+ caps = extcap_get_if_dlts(ifname, err_primary_msg);
+ if (caps != NULL)
+ return caps;
+
+ /* return if the extcap interface generated an error */
+ if (err_primary_msg != NULL && *err_primary_msg != NULL)
+ return NULL;
+
+ /* Try to get our interface list */
+ err = sync_if_capabilities_open(ifname, monitor_mode, auth_string, &data,
+ &primary_msg, &secondary_msg, update_cb);
+ if (err != 0) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities failed. Error %d, %s",
+ err, primary_msg ? primary_msg : "no message");
+ if (err_primary_msg)
+ *err_primary_msg = primary_msg;
+ else
+ g_free(primary_msg);
+ if (err_secondary_msg)
+ *err_secondary_msg = secondary_msg;
+ else
+ g_free(secondary_msg);
+ return NULL;
+ }
+
+ /* Split our lines */
+#ifdef _WIN32
+ raw_list = g_strsplit(data, "\r\n", 0);
+#else
+ raw_list = g_strsplit(data, "\n", 0);
+#endif
+ g_free(data);
+
+ /*
+ * First line is 0 if monitor mode isn't supported, 1 if it is.
+ */
+ if (raw_list[0] == NULL || *raw_list[0] == '\0') {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned no information.");
+ if (err_primary_msg) {
+ *err_primary_msg = g_strdup("Dumpcap returned no interface capability information");
+ }
+ g_strfreev(raw_list);
+ return NULL;
+ }
+
+ /*
+ * Allocate the interface capabilities structure.
+ */
+ caps = (if_capabilities_t *)g_malloc(sizeof *caps);
+ switch (*raw_list[0]) {
+
+ case '0':
+ caps->can_set_rfmon = FALSE;
+ break;
+
+ case '1':
+ caps->can_set_rfmon = TRUE;
+ break;
+
+ default:
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned bad information.");
+ if (err_primary_msg) {
+ *err_primary_msg = g_strdup_printf("Dumpcap returned \"%s\" for monitor-mode capability",
+ raw_list[0]);
+ }
+ g_free(caps);
+ g_strfreev(raw_list);
+ return NULL;
+ }
+
+ /*
+ * The following are link-layer types.
+ */
+ for (i = 1; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) {
+ data_link_info_t *data_link_info;
+ /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
+ char **lt_parts = g_strsplit(raw_list[i], "\t", 3);
+ if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
+ g_strfreev(lt_parts);
+ continue;
+ }
+
+ data_link_info = g_new(data_link_info_t,1);
+ data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
+ data_link_info->name = g_strdup(lt_parts[1]);
+ if (strcmp(lt_parts[2], "(not supported)") != 0)
+ data_link_info->description = g_strdup(lt_parts[2]);
+ else
+ data_link_info->description = NULL;
+ g_strfreev(lt_parts);
+
+ linktype_list = g_list_append(linktype_list, data_link_info);
+ }
+
+ if (raw_list[i]) { /* Oh, timestamp types! */
+ for (i++; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) {
+ timestamp_info_t *timestamp_info;
+ char **tt_parts = g_strsplit(raw_list[i], "\t", 2);
+ if (tt_parts[0] == NULL || tt_parts[1] == NULL) {
+ g_strfreev(tt_parts);
+ continue;
+ }
+
+ timestamp_info = g_new(timestamp_info_t,1);
+ timestamp_info->name = g_strdup(tt_parts[0]);
+ timestamp_info->description = g_strdup(tt_parts[1]);
+ g_strfreev(tt_parts);
+
+ timestamp_list = g_list_append(timestamp_list, timestamp_info);
+ }
+ }
+
+ g_strfreev(raw_list);
+
+ /* Check to see if we built a list */
+ if (linktype_list == NULL) {
+ /* No. */
+ if (err_primary_msg)
+ *err_primary_msg = g_strdup("Dumpcap returned no link-layer types");
+ g_free(caps);
+ return NULL;
+ }
+
+ caps->data_link_types = linktype_list;
+ /* Might be NULL. Not all systems report timestamp types */
+ caps->timestamp_types = timestamp_list;
+
+ return caps;
+}
+
+#ifdef HAVE_PCAP_REMOTE
+void add_interface_to_remote_list(if_info_t *if_info)
+{
+ GSList *list;
+ if_addr_t *if_addr, *temp_addr;
+
+ if_info_t *temp = g_new0(if_info_t, 1);
+ temp->name = g_strdup(if_info->name);
+ temp->friendly_name = g_strdup(if_info->friendly_name);
+ temp->vendor_description = g_strdup(if_info->vendor_description);
+ for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
+ temp_addr = g_new0(if_addr_t, 1);
+ if_addr = (if_addr_t *)list->data;
+ if (if_addr) {
+ temp_addr->ifat_type = if_addr->ifat_type;
+ if (temp_addr->ifat_type == IF_AT_IPv4) {
+ temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
+ } else {
+ memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
+ }
+ } else {
+ g_free(temp_addr);
+ temp_addr = NULL;
+ }
+ if (temp_addr) {
+ temp->addrs = g_slist_append(temp->addrs, temp_addr);
+ }
+ }
+ temp->loopback = if_info->loopback;
+ remote_interface_list = g_list_append(remote_interface_list, temp);
+}
+#endif
+#endif /* HAVE_LIBPCAP */
diff --git a/capture/capture_ifinfo.h b/capture/capture_ifinfo.h
new file mode 100644
index 0000000000..5034ddb720
--- /dev/null
+++ b/capture/capture_ifinfo.h
@@ -0,0 +1,138 @@
+/* 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
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __CAPTURE_IFINFO_H__
+#define __CAPTURE_IFINFO_H__
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * Explicitly set the interface_type enum values as these values are exposed
+ * in the preferences gui.interfaces_hidden_types string.
+ */
+typedef enum {
+ IF_WIRED = 0,
+ IF_AIRPCAP = 1,
+ IF_PIPE = 2,
+ IF_STDIN = 3,
+ IF_BLUETOOTH = 4,
+ IF_WIRELESS = 5,
+ IF_DIALUP = 6,
+ IF_USB = 7,
+ IF_EXTCAP = 8,
+ IF_VIRTUAL = 9
+} 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 */
+ char *extcap; /* extcap arguments, which present the data to call the extcap interface */
+} 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 DONT_HAVE_PCAP 2 /* couldn't load WinPcap/Npcap */
+
+void free_interface_list(GList *if_list);
+
+/**
+ * Get an if_info_t for a particular interface.
+ * (May require privilege, so should only be used by dumpcap.)
+ */
+extern if_info_t *if_info_get(const char *name);
+
+/**
+ * Free an if_info_t.
+ */
+void if_info_free(if_info_t *if_info);
+
+/*
+ * "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 */
+ GList *timestamp_types; /* GList of timestamp_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;
+
+/*
+ * Information about timestamp types.
+ */
+typedef struct {
+ char *name; /* e.g. "adapter_unsynced" */
+ char *description; /* description from libpcap e.g. "Adapter, not synced with system time" */
+} timestamp_info_t;
+
+/**
+ * Fetch the linktype list for the specified interface from a child process.
+ */
+extern if_capabilities_t *
+capture_get_if_capabilities(const gchar *devname, gboolean monitor_mode,
+ const gchar *auth_string,
+ char **err_primary_msg, char **err_secondary_msg,
+ 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/capture/capture_session.h b/capture/capture_session.h
new file mode 100644
index 0000000000..36773a5daf
--- /dev/null
+++ b/capture/capture_session.h
@@ -0,0 +1,135 @@
+/* capture_session.h
+ * State of a capture session
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __CAPCHILD_CAPTURE_SESSION_H__
+#define __CAPCHILD_CAPTURE_SESSION_H__
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <stdint.h>
+#endif
+
+#include "capture_opts.h"
+
+#include <wsutil/processes.h>
+
+#include "cfile.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef HAVE_LIBPCAP
+/* Current state of capture engine. XXX - differentiate states */
+typedef enum {
+ CAPTURE_STOPPED, /**< stopped */
+ CAPTURE_PREPARING, /**< preparing, but still no response from capture child */
+ CAPTURE_RUNNING /**< capture child signalled ok, capture is running now */
+} capture_state;
+
+struct _info_data;
+
+/*
+ * State of a capture session.
+ */
+typedef struct _capture_session capture_session;
+
+/*
+ * Types of callbacks.
+ */
+
+/**
+ * Capture child told us we have a new (or the first) capture file.
+ */
+typedef gboolean (*new_file_fn)(capture_session *cap_session, gchar *new_file);
+
+/**
+ * Capture child told us we have new packets to read.
+ */
+typedef void (*new_packets_fn)(capture_session *cap_session, int to_read);
+
+/**
+ * Capture child told us how many dropped packets it counted.
+ */
+typedef void (*drops_fn)(capture_session *cap_session, guint32 dropped,
+ const char *interface_name);
+
+/**
+ * Capture child told us that an error has occurred while starting
+ * the capture.
+ */
+typedef void (*error_fn)(capture_session *cap_session, char *error_msg,
+ char *secondary_error_msg);
+
+/**
+ * Capture child told us that an error has occurred while parsing a
+ * capture filter when starting/running the capture.
+ */
+typedef void (*cfilter_error_fn)(capture_session *cap_session, guint i,
+ const char *error_message);
+
+/**
+ * Capture child closed its side of the pipe, report any error and
+ * do the required cleanup.
+ */
+typedef void (*closed_fn)(capture_session *cap_session, gchar *msg);
+
+/*
+ * The structure for the session.
+ */
+struct _capture_session {
+ ws_process_id fork_child; /**< If not WS_INVALID_PID, in parent, process ID of child */
+ int fork_child_status; /**< Child exit status */
+#ifdef _WIN32
+ int signal_pipe_write_fd; /**< the pipe to signal the child */
+#endif
+ capture_state state; /**< current state of the capture engine */
+#ifndef _WIN32
+ uid_t owner; /**< owner of the cfile */
+ gid_t group; /**< group of the cfile */
+#endif
+ gboolean session_will_restart; /**< Set when session will restart */
+ guint32 count; /**< Total number of frames captured */
+ capture_options *capture_opts; /**< options for this capture */
+ capture_file *cf; /**< handle to cfile */
+ wtap_rec rec; /**< record we're reading packet metadata into */
+ Buffer buf; /**< Buffer we're reading packet data into */
+ struct wtap *wtap; /**< current wtap file */
+ struct _info_data *cap_data_info; /**< stats for this capture */
+
+ /*
+ * Routines supplied by our caller; we call them back to notify them
+ * of various events.
+ */
+ new_file_fn new_file;
+ new_packets_fn new_packets;
+ drops_fn drops;
+ error_fn error;
+ cfilter_error_fn cfilter_error;
+ closed_fn closed;
+};
+
+extern void
+capture_session_init(capture_session *cap_session, capture_file *cf,
+ new_file_fn new_file, new_packets_fn new_packets,
+ drops_fn drops, error_fn error,
+ cfilter_error_fn cfilter_error, closed_fn closed);
+#else
+
+/* dummy is needed because clang throws the error: empty struct has size 0 in C, size 1 in C++ */
+typedef struct _capture_session {int dummy;} capture_session;
+
+#endif /* HAVE_LIBPCAP */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CAPCHILD_CAPTURE_SESSION_H__ */
diff --git a/capture/capture_sync.c b/capture/capture_sync.c
new file mode 100644
index 0000000000..afd9f47778
--- /dev/null
+++ b/capture/capture_sync.c
@@ -0,0 +1,2100 @@
+/* capture_sync.c
+ * Synchronisation between Wireshark capture parent and child instances
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LIBPCAP
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <signal.h>
+
+#include <wsutil/strtoi.h>
+
+#ifdef _WIN32
+#include <wsutil/unicode-utils.h>
+#include <wsutil/win32-utils.h>
+#include <wsutil/ws_pipe.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#include "capture/capture-pcap-util.h"
+
+#ifndef _WIN32
+/*
+ * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
+ * macros) on UNIX systems that don't have them.
+ */
+#ifndef WIFEXITED
+# define WIFEXITED(status) (((status) & 0177) == 0)
+#endif
+#ifndef WIFSTOPPED
+# define WIFSTOPPED(status) (((status) & 0177) == 0177)
+#endif
+#ifndef WIFSIGNALED
+# define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(status) ((status) >> 8)
+#endif
+#ifndef WTERMSIG
+# define WTERMSIG(status) ((status) & 0177)
+#endif
+#ifndef WCOREDUMP
+# define WCOREDUMP(status) ((status) & 0200)
+#endif
+#ifndef WSTOPSIG
+# define WSTOPSIG(status) ((status) >> 8)
+#endif
+#endif /* _WIN32 */
+
+#include <epan/packet.h>
+#include <epan/prefs.h>
+
+#include "file.h"
+
+#include "ui/capture.h"
+#include <capture/capture_sync.h>
+
+#include "sync_pipe.h"
+
+#ifdef _WIN32
+#include "capture/capture-wpcap.h"
+#endif
+
+#include "ui/ws_ui_util.h"
+
+#include <wsutil/filesystem.h>
+#include <wsutil/file_util.h>
+#include <wsutil/report_message.h>
+#include "extcap.h"
+#include "log.h"
+
+#ifdef _WIN32
+#include <process.h> /* For spawning child process */
+#endif
+
+#include <wsutil/ws_pipe.h>
+
+#ifdef _WIN32
+static void create_dummy_signal_pipe();
+static HANDLE dummy_signal_pipe; /* Dummy named pipe which lets the child check for a dropped connection */
+static gchar *dummy_control_id;
+#else
+static const char *sync_pipe_signame(int);
+#endif
+
+
+static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
+static int sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp);
+static void pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len);
+static ssize_t pipe_read_block(int pipe_fd, char *indicator, int len, char *msg,
+ char **err_msg);
+
+static void (*fetch_dumpcap_pid)(ws_process_id) = NULL;
+
+static void free_argv(char** argv, int argc)
+{
+ int i;
+ for (i = 0; i < argc; i++)
+ g_free(argv[i]);
+ g_free(argv);
+}
+
+void
+capture_session_init(capture_session *cap_session, capture_file *cf,
+ new_file_fn new_file, new_packets_fn new_packets,
+ drops_fn drops, error_fn error,
+ cfilter_error_fn cfilter_error, closed_fn closed)
+{
+ cap_session->cf = cf;
+ cap_session->fork_child = WS_INVALID_PID; /* invalid process handle */
+#ifdef _WIN32
+ cap_session->signal_pipe_write_fd = -1;
+#endif
+ cap_session->state = CAPTURE_STOPPED;
+#ifndef _WIN32
+ cap_session->owner = getuid();
+ cap_session->group = getgid();
+#endif
+ cap_session->count = 0;
+ cap_session->session_will_restart = FALSE;
+
+ cap_session->new_file = new_file;
+ cap_session->new_packets = new_packets;
+ cap_session->drops = drops;
+ cap_session->error = error;
+ cap_session->cfilter_error = cfilter_error;
+ cap_session->closed = closed;
+}
+
+/* Append an arg (realloc) to an argc/argv array */
+/* (add a string pointer to a NULL-terminated array of string pointers) */
+static char **
+sync_pipe_add_arg(char **args, int *argc, const char *arg)
+{
+ /* Grow the array; "*argc" currently contains the number of string
+ pointers, *not* counting the NULL pointer at the end, so we have
+ to add 2 in order to get the new size of the array, including the
+ new pointer and the terminating NULL pointer. */
+ args = (char **)g_realloc( (gpointer) args, (*argc + 2) * sizeof (char *));
+
+ /* Stuff the pointer into the penultimate element of the array, which
+ is the one at the index specified by "*argc". */
+ args[*argc] = g_strdup(arg);
+ /* Now bump the count. */
+ (*argc)++;
+
+ /* We overwrite the NULL pointer; put it back right after the
+ element we added. */
+ args[*argc] = NULL;
+
+ return args;
+}
+
+/* Initialize an argument list and add dumpcap to it. */
+static char **
+init_pipe_args(int *argc) {
+ char **argv;
+ const char *progfile_dir;
+ char *exename;
+
+ progfile_dir = get_progfile_dir();
+ if (progfile_dir == NULL) {
+ return NULL;
+ }
+
+ /* Allocate the string pointer array with enough space for the
+ terminating NULL pointer. */
+ *argc = 0;
+ argv = (char **)g_malloc(sizeof (char *));
+ *argv = NULL;
+
+ /* take Wireshark's absolute program path and replace "Wireshark" with "dumpcap" */
+#ifdef _WIN32
+ exename = g_strdup_printf("%s\\dumpcap.exe", progfile_dir);
+#else
+ exename = g_strdup_printf("%s/dumpcap", progfile_dir);
+#endif
+
+ /* Make that the first argument in the argument list (argv[0]). */
+ argv = sync_pipe_add_arg(argv, argc, exename);
+
+ /* sync_pipe_add_arg strdupes exename, so we should free our copy */
+ g_free(exename);
+
+ return argv;
+}
+
+#define ARGV_NUMBER_LEN 24
+/* a new capture run: start a new dumpcap task and hand over parameters through command line */
+gboolean
+sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, info_data_t* cap_data, void (*update_cb)(void))
+{
+#ifdef _WIN32
+ HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */
+ HANDLE sync_pipe_write; /* pipe used to send messages from child to parent */
+ int signal_pipe_write_fd;
+ HANDLE signal_pipe; /* named pipe used to send messages from parent to child (currently only stop) */
+ GString *args = g_string_sized_new(200);
+ gchar *quoted_arg;
+ SECURITY_ATTRIBUTES sa;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ char control_id[ARGV_NUMBER_LEN];
+ gchar *signal_pipe_name;
+#else
+ char errmsg[1024+1];
+ int sync_pipe[2]; /* pipe used to send messages from child to parent */
+ enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
+#endif
+ int sync_pipe_read_fd;
+ int argc;
+ char **argv;
+ int i;
+ guint j;
+ interface_options *interface_opts;
+
+ if (capture_opts->ifaces->len > 1)
+ capture_opts->use_pcapng = TRUE;
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_start");
+ capture_opts_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, capture_opts);
+
+ cap_session->fork_child = WS_INVALID_PID;
+
+ if (!extcap_init_interfaces(capture_opts)) {
+ report_failure("Unable to init extcaps. (tmp fifo already exists?)");
+ return FALSE;
+ }
+
+ argv = init_pipe_args(&argc);
+ if (!argv) {
+ /* We don't know where to find dumpcap. */
+ report_failure("We don't know where to find dumpcap.");
+ return FALSE;
+ }
+
+ if (capture_opts->ifaces->len > 1)
+ argv = sync_pipe_add_arg(argv, &argc, "-t");
+
+ if (capture_opts->use_pcapng)
+ argv = sync_pipe_add_arg(argv, &argc, "-n");
+ else
+ argv = sync_pipe_add_arg(argv, &argc, "-P");
+
+ if (capture_opts->capture_comment) {
+ argv = sync_pipe_add_arg(argv, &argc, "--capture-comment");
+ argv = sync_pipe_add_arg(argv, &argc, capture_opts->capture_comment);
+ }
+
+ if (capture_opts->multi_files_on) {
+ if (capture_opts->has_autostop_filesize) {
+ char sfilesize[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-b");
+ g_snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
+ argv = sync_pipe_add_arg(argv, &argc, sfilesize);
+ }
+
+ if (capture_opts->has_file_duration) {
+ char sfile_duration[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-b");
+ g_snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->file_duration);
+ argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
+ }
+
+ if (capture_opts->has_file_interval) {
+ char sfile_interval[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-b");
+ g_snprintf(sfile_interval, ARGV_NUMBER_LEN, "interval:%d",capture_opts->file_interval);
+ argv = sync_pipe_add_arg(argv, &argc, sfile_interval);
+ }
+
+ if (capture_opts->has_file_packets) {
+ char sfile_packets[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-b");
+ g_snprintf(sfile_packets, ARGV_NUMBER_LEN, "packets:%d",capture_opts->file_packets);
+ argv = sync_pipe_add_arg(argv, &argc, sfile_packets);
+ }
+
+ if (capture_opts->has_ring_num_files) {
+ char sring_num_files[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-b");
+ g_snprintf(sring_num_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->ring_num_files);
+ argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
+ }
+
+ if (capture_opts->has_autostop_files) {
+ char sautostop_files[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-a");
+ g_snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files);
+ argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
+ }
+ } else {
+ if (capture_opts->has_autostop_filesize) {
+ char sautostop_filesize[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-a");
+ g_snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%u",capture_opts->autostop_filesize);
+ argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
+ }
+ }
+
+ if (capture_opts->has_autostop_packets) {
+ char scount[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-c");
+ g_snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets);
+ argv = sync_pipe_add_arg(argv, &argc, scount);
+ }
+
+ if (capture_opts->has_autostop_duration) {
+ char sautostop_duration[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-a");
+ g_snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%f",capture_opts->autostop_duration);
+ argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
+ }
+
+ if (capture_opts->group_read_access) {
+ argv = sync_pipe_add_arg(argv, &argc, "-g");
+ }
+
+ for (j = 0; j < capture_opts->ifaces->len; j++) {
+ interface_opts = &g_array_index(capture_opts->ifaces, interface_options, j);
+
+ argv = sync_pipe_add_arg(argv, &argc, "-i");
+ if (interface_opts->extcap_fifo != NULL)
+ {
+#ifdef _WIN32
+ char *pipe = g_strdup_printf("%s%" G_GUINTPTR_FORMAT, EXTCAP_PIPE_PREFIX, interface_opts->extcap_pipe_h);
+ argv = sync_pipe_add_arg(argv, &argc, pipe);
+ g_free(pipe);
+#else
+ argv = sync_pipe_add_arg(argv, &argc, interface_opts->extcap_fifo);
+#endif
+ /* Add a name for the interface, to put into an IDB. */
+ argv = sync_pipe_add_arg(argv, &argc, "--ifname");
+ argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
+ if (interface_opts->descr != NULL)
+ {
+ /* Add a description for the interface, to put into an IDB. */
+ argv = sync_pipe_add_arg(argv, &argc, "--ifdescr");
+ argv = sync_pipe_add_arg(argv, &argc, interface_opts->descr);
+ }
+ }
+ else
+ argv = sync_pipe_add_arg(argv, &argc, interface_opts->name);
+
+ if (interface_opts->cfilter != NULL && strlen(interface_opts->cfilter) != 0) {
+ argv = sync_pipe_add_arg(argv, &argc, "-f");
+ argv = sync_pipe_add_arg(argv, &argc, interface_opts->cfilter);
+ }
+ if (interface_opts->has_snaplen) {
+ char ssnap[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-s");
+ g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d", interface_opts->snaplen);
+ argv = sync_pipe_add_arg(argv, &argc, ssnap);
+ }
+
+ if (interface_opts->linktype != -1) {
+ const char *linktype = linktype_val_to_name(interface_opts->linktype);
+ if ( linktype != NULL )
+ {
+ argv = sync_pipe_add_arg(argv, &argc, "-y");
+ argv = sync_pipe_add_arg(argv, &argc, linktype);
+ }
+ }
+
+ if (!interface_opts->promisc_mode) {
+ argv = sync_pipe_add_arg(argv, &argc, "-p");
+ }
+
+#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
+ if (interface_opts->buffer_size != DEFAULT_CAPTURE_BUFFER_SIZE) {
+ char buffer_size[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-B");
+ if(interface_opts->buffer_size == 0x00)
+ interface_opts->buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE;
+ g_snprintf(buffer_size, ARGV_NUMBER_LEN, "%d", interface_opts->buffer_size);
+ argv = sync_pipe_add_arg(argv, &argc, buffer_size);
+ }
+#endif
+
+#ifdef HAVE_PCAP_CREATE
+ if (interface_opts->monitor_mode) {
+ argv = sync_pipe_add_arg(argv, &argc, "-I");
+ }
+#endif
+
+#ifdef HAVE_PCAP_REMOTE
+ if (interface_opts->datatx_udp)
+ argv = sync_pipe_add_arg(argv, &argc, "-u");
+
+ if (!interface_opts->nocap_rpcap)
+ argv = sync_pipe_add_arg(argv, &argc, "-r");
+
+ if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
+ char sauth[256];
+ argv = sync_pipe_add_arg(argv, &argc, "-A");
+ g_snprintf(sauth, sizeof(sauth), "%s:%s",
+ interface_opts->auth_username,
+ interface_opts->auth_password);
+ argv = sync_pipe_add_arg(argv, &argc, sauth);
+ }
+#endif
+
+#ifdef HAVE_PCAP_SETSAMPLING
+ if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) {
+ char ssampling[ARGV_NUMBER_LEN];
+ argv = sync_pipe_add_arg(argv, &argc, "-m");
+ g_snprintf(ssampling, ARGV_NUMBER_LEN, "%s:%d",
+ interface_opts->sampling_method == CAPTURE_SAMP_BY_COUNT ? "count" :
+ interface_opts->sampling_method == CAPTURE_SAMP_BY_TIMER ? "timer" :
+ "undef",
+ interface_opts->sampling_param);
+ argv = sync_pipe_add_arg(argv, &argc, ssampling);
+ }
+#endif
+ if (interface_opts->timestamp_type) {
+ argv = sync_pipe_add_arg(argv, &argc, "--time-stamp-type");
+ argv = sync_pipe_add_arg(argv, &argc, interface_opts->timestamp_type);
+ }
+ }
+
+ /* dumpcap should be running in capture child mode (hidden feature) */
+#ifndef DEBUG_CHILD
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+#ifdef _WIN32
+ g_snprintf(control_id, ARGV_NUMBER_LEN, "%d", GetCurrentProcessId());
+ argv = sync_pipe_add_arg(argv, &argc, control_id);
+#else
+ argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
+#endif
+#endif
+
+ if (capture_opts->save_file) {
+ argv = sync_pipe_add_arg(argv, &argc, "-w");
+ argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
+ }
+ for (i = 0; i < argc; i++) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "argv[%d]: %s", i, argv[i]);
+ }
+ if (capture_opts->compress_type) {
+ argv = sync_pipe_add_arg(argv, &argc, "--compress-type");
+ argv = sync_pipe_add_arg(argv, &argc, capture_opts->compress_type);
+ }
+
+#ifdef _WIN32
+ /* init SECURITY_ATTRIBUTES */
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ /* Create a pipe for the child process */
+ /* (increase this value if you have trouble while fast capture file switches) */
+ if (! CreatePipe(&sync_pipe_read, &sync_pipe_write, &sa, 5120)) {
+ /* Couldn't create the pipe between parent and child. */
+ report_failure("Couldn't create sync pipe: %s",
+ win32strerror(GetLastError()));
+ free_argv(argv, argc);
+ return FALSE;
+ }
+
+ /*
+ * Associate a C run-time file handle with the Windows HANDLE for the
+ * read side of the message pipe.
+ *
+ * (See http://www.flounder.com/handles.htm for information on various
+ * types of file handle in C/C++ on Windows.)
+ */
+ sync_pipe_read_fd = _open_osfhandle( (intptr_t) sync_pipe_read, _O_BINARY);
+ if (sync_pipe_read_fd == -1) {
+ /* Couldn't create the pipe between parent and child. */
+ report_failure("Couldn't get C file handle for sync pipe: %s", g_strerror(errno));
+ CloseHandle(sync_pipe_read);
+ CloseHandle(sync_pipe_write);
+ free_argv(argv, argc);
+ return FALSE;
+ }
+
+ /* Create the signal pipe */
+ signal_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT, control_id);
+ signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name),
+ PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL);
+ g_free(signal_pipe_name);
+
+ if (signal_pipe == INVALID_HANDLE_VALUE) {
+ /* Couldn't create the signal pipe between parent and child. */
+ report_failure("Couldn't create signal pipe: %s",
+ win32strerror(GetLastError()));
+ ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
+ CloseHandle(sync_pipe_write);
+ free_argv(argv, argc);
+ return FALSE;
+ }
+
+ /*
+ * Associate a C run-time file handle with the Windows HANDLE for the
+ * read side of the message pipe.
+ *
+ * (See http://www.flounder.com/handles.htm for information on various
+ * types of file handle in C/C++ on Windows.)
+ */
+ signal_pipe_write_fd = _open_osfhandle( (intptr_t) signal_pipe, _O_BINARY);
+ if (sync_pipe_read_fd == -1) {
+ /* Couldn't create the pipe between parent and child. */
+ report_failure("Couldn't get C file handle for sync pipe: %s", g_strerror(errno));
+ ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
+ CloseHandle(sync_pipe_write);
+ CloseHandle(signal_pipe);
+ free_argv(argv, argc);
+ return FALSE;
+ }
+
+ /* init STARTUPINFO & PROCESS_INFORMATION */
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ memset(&pi, 0, sizeof(pi));
+#ifdef DEBUG_CHILD
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOW;
+#else
+ si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE; /* this hides the console window */
+ si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ si.hStdError = sync_pipe_write;
+ /*si.hStdError = (HANDLE) _get_osfhandle(2);*/
+#endif
+
+ /* convert args array into a single string */
+ /* XXX - could change sync_pipe_add_arg() instead */
+ /* there is a drawback here: the length is internally limited to 1024 bytes */
+ for(i=0; argv[i] != 0; i++) {
+ if(i != 0) g_string_append_c(args, ' '); /* don't prepend a space before the path!!! */
+ quoted_arg = protect_arg(argv[i]);
+ g_string_append(args, quoted_arg);
+ g_free(quoted_arg);
+ }
+
+ /* call dumpcap */
+ if(!win32_create_process(argv[0], args->str, NULL, NULL, TRUE,
+ CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
+ report_failure("Couldn't run %s in child process: %s",
+ args->str, win32strerror(GetLastError()));
+ ws_close(sync_pipe_read_fd); /* Should close sync_pipe_read */
+ CloseHandle(sync_pipe_write);
+ CloseHandle(signal_pipe);
+ free_argv(argv, argc);
+ g_string_free(args, TRUE);
+ return FALSE;
+ }
+ cap_session->fork_child = pi.hProcess;
+ /* We may need to store this and close it later */
+ CloseHandle(pi.hThread);
+ g_string_free(args, TRUE);
+
+ cap_session->signal_pipe_write_fd = signal_pipe_write_fd;
+
+#else /* _WIN32 */
+ if (pipe(sync_pipe) < 0) {
+ /* Couldn't create the pipe between parent and child. */
+ report_failure("Couldn't create sync pipe: %s", g_strerror(errno));
+ free_argv(argv, argc);
+ return FALSE;
+ }
+
+ if ((cap_session->fork_child = fork()) == 0) {
+ /*
+ * Child process - run dumpcap with the right arguments to make
+ * it just capture with the specified capture parameters
+ */
+ dup2(sync_pipe[PIPE_WRITE], 2);
+ ws_close(sync_pipe[PIPE_READ]);
+ execv(argv[0], argv);
+ g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
+ argv[0], g_strerror(errno));
+ sync_pipe_errmsg_to_parent(2, errmsg, "");
+
+ /* Exit with "_exit()", so that we don't close the connection
+ to the X server (and cause stuff buffered up by our parent but
+ not yet sent to be sent, as that stuff should only be sent by
+ our parent). We've sent an error message to the parent, so
+ we exit with an exit status of 1 (any exit status other than
+ 0 or 1 will cause an additional message to report that exit
+ status, over and above the error message we sent to the parent). */
+ _exit(1);
+ }
+
+ if (fetch_dumpcap_pid && cap_session->fork_child > 0)
+ fetch_dumpcap_pid(cap_session->fork_child);
+
+ sync_pipe_read_fd = sync_pipe[PIPE_READ];
+#endif
+
+ /* Parent process - read messages from the child process over the
+ sync pipe. */
+ free_argv(argv, argc);
+
+ /* Close the write side of the pipe, so that only the child has it
+ open, and thus it completely closes, and thus returns to us
+ an EOF indication, if the child closes it (either deliberately
+ or by exiting abnormally). */
+#ifdef _WIN32
+ CloseHandle(sync_pipe_write);
+#else
+ ws_close(sync_pipe[PIPE_WRITE]);
+#endif
+
+ if (cap_session->fork_child == WS_INVALID_PID) {
+ /* We couldn't even create the child process. */
+ report_failure("Couldn't create child process: %s", g_strerror(errno));
+ ws_close(sync_pipe_read_fd);
+#ifdef _WIN32
+ ws_close(cap_session->signal_pipe_write_fd);
+#endif
+ return FALSE;
+ }
+
+ cap_session->fork_child_status = 0;
+ cap_session->capture_opts = capture_opts;
+ cap_session->cap_data_info = cap_data;
+
+ /* we might wait for a moment till child is ready, so update screen now */
+ if (update_cb) update_cb();
+
+ /* We were able to set up to read the capture file;
+ arrange that our callback be called whenever it's possible
+ to read from the sync pipe, so that it's called when
+ the child process wants to tell us something. */
+
+ /* we have a running capture, now wait for the real capture filename */
+ pipe_input_set_handler(sync_pipe_read_fd, (gpointer) cap_session,
+ &cap_session->fork_child, sync_pipe_input_cb);
+
+ return TRUE;
+}
+
+/*
+ * Open two pipes to dumpcap with the supplied arguments, one for its
+ * standard output and one for its standard error.
+ *
+ * On success, *msg is unchanged and 0 is returned; data_read_fd,
+ * message_read_fd, and fork_child point to the standard output pipe's
+ * file descriptor, the standard error pipe's file descriptor, and
+ * the child's PID/handle, respectively.
+ *
+ * On failure, *msg points to an error message for the failure, and -1 is
+ * returned, in which case *msg must be freed with g_free().
+ */
+/* XXX - This duplicates a lot of code in sync_pipe_start() */
+/* XXX - assumes PIPE_BUF_SIZE > SP_MAX_MSG_LEN */
+#define PIPE_BUF_SIZE 5120
+static int
+sync_pipe_open_command(char* const argv[], int *data_read_fd,
+ int *message_read_fd, ws_process_id *fork_child, gchar **msg, void(*update_cb)(void))
+{
+ enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
+#ifdef _WIN32
+ HANDLE sync_pipe[2]; /* pipe used to send messages from child to parent */
+ HANDLE data_pipe[2]; /* pipe used to send data from child to parent */
+ GString *args = g_string_sized_new(200);
+ gchar *quoted_arg;
+ SECURITY_ATTRIBUTES sa;
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ int i;
+#else
+ char errmsg[1024+1];
+ int sync_pipe[2]; /* pipe used to send messages from child to parent */
+ int data_pipe[2]; /* pipe used to send data from child to parent */
+#endif
+ *fork_child = WS_INVALID_PID;
+ *data_read_fd = -1;
+ *message_read_fd = -1;
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_open_command");
+
+ if (!msg) {
+ /* We can't return anything */
+#ifdef _WIN32
+ g_string_free(args, TRUE);
+#endif
+ return -1;
+ }
+
+#ifdef _WIN32
+ /* init SECURITY_ATTRIBUTES */
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ /* Create a pipe for the child process to send us messages */
+ /* (increase this value if you have trouble while fast capture file switches) */
+ if (! CreatePipe(&sync_pipe[PIPE_READ], &sync_pipe[PIPE_WRITE], &sa, 5120)) {
+ /* Couldn't create the message pipe between parent and child. */
+ *msg = g_strdup_printf("Couldn't create sync pipe: %s",
+ win32strerror(GetLastError()));
+ return -1;
+ }
+
+ /*
+ * Associate a C run-time file handle with the Windows HANDLE for the
+ * read side of the message pipe.
+ *
+ * (See http://www.flounder.com/handles.htm for information on various
+ * types of file handle in C/C++ on Windows.)
+ */
+ *message_read_fd = _open_osfhandle( (intptr_t) sync_pipe[PIPE_READ], _O_BINARY);
+ if (*message_read_fd == -1) {
+ *msg = g_strdup_printf("Couldn't get C file handle for message read pipe: %s", g_strerror(errno));
+ CloseHandle(sync_pipe[PIPE_READ]);
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+
+ /* Create a pipe for the child process to send us data */
+ /* (increase this value if you have trouble while fast capture file switches) */
+ if (! CreatePipe(&data_pipe[PIPE_READ], &data_pipe[PIPE_WRITE], &sa, 5120)) {
+ /* Couldn't create the message pipe between parent and child. */
+ *msg = g_strdup_printf("Couldn't create data pipe: %s",
+ win32strerror(GetLastError()));
+ ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+
+ /*
+ * Associate a C run-time file handle with the Windows HANDLE for the
+ * read side of the data pipe.
+ *
+ * (See http://www.flounder.com/handles.htm for information on various
+ * types of file handle in C/C++ on Windows.)
+ */
+ *data_read_fd = _open_osfhandle( (intptr_t) data_pipe[PIPE_READ], _O_BINARY);
+ if (*data_read_fd == -1) {
+ *msg = g_strdup_printf("Couldn't get C file handle for data read pipe: %s", g_strerror(errno));
+ CloseHandle(data_pipe[PIPE_READ]);
+ CloseHandle(data_pipe[PIPE_WRITE]);
+ ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+
+ /* init STARTUPINFO & PROCESS_INFORMATION */
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ memset(&pi, 0, sizeof(pi));
+#ifdef DEBUG_CHILD
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOW;
+#else
+ si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE; /* this hides the console window */
+ si.hStdInput = NULL; /* handle for named pipe*/
+
+ si.hStdOutput = data_pipe[PIPE_WRITE];
+ si.hStdError = sync_pipe[PIPE_WRITE];
+#endif
+
+ /* convert args array into a single string */
+ /* XXX - could change sync_pipe_add_arg() instead */
+ /* there is a drawback here: the length is internally limited to 1024 bytes */
+ for(i=0; argv[i] != 0; i++) {
+ if(i != 0) g_string_append_c(args, ' '); /* don't prepend a space before the path!!! */
+ quoted_arg = protect_arg(argv[i]);
+ g_string_append(args, quoted_arg);
+ g_free(quoted_arg);
+ }
+
+ /* call dumpcap */
+ if(!win32_create_process(argv[0], args->str, NULL, NULL, TRUE,
+ CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
+ *msg = g_strdup_printf("Couldn't run %s in child process: %s",
+ args->str, win32strerror(GetLastError()));
+ ws_close(*data_read_fd); /* Should close data_pipe[PIPE_READ] */
+ CloseHandle(data_pipe[PIPE_WRITE]);
+ ws_close(*message_read_fd); /* Should close sync_pipe[PIPE_READ] */
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+ g_string_free(args, TRUE);
+ return -1;
+ }
+ *fork_child = pi.hProcess;
+ /* We may need to store this and close it later */
+ CloseHandle(pi.hThread);
+ g_string_free(args, TRUE);
+#else /* _WIN32 */
+ /* Create a pipe for the child process to send us messages */
+ if (pipe(sync_pipe) < 0) {
+ /* Couldn't create the message pipe between parent and child. */
+ *msg = g_strdup_printf("Couldn't create sync pipe: %s", g_strerror(errno));
+ return -1;
+ }
+
+ /* Create a pipe for the child process to send us data */
+ if (pipe(data_pipe) < 0) {
+ /* Couldn't create the data pipe between parent and child. */
+ *msg = g_strdup_printf("Couldn't create data pipe: %s", g_strerror(errno));
+ ws_close(sync_pipe[PIPE_READ]);
+ ws_close(sync_pipe[PIPE_WRITE]);
+ return -1;
+ }
+
+ if ((*fork_child = fork()) == 0) {
+ /*
+ * Child process - run dumpcap with the right arguments to make
+ * it just capture with the specified capture parameters
+ */
+ dup2(data_pipe[PIPE_WRITE], 1);
+ ws_close(data_pipe[PIPE_READ]);
+ ws_close(data_pipe[PIPE_WRITE]);
+ dup2(sync_pipe[PIPE_WRITE], 2);
+ ws_close(sync_pipe[PIPE_READ]);
+ ws_close(sync_pipe[PIPE_WRITE]);
+ execv(argv[0], argv);
+ g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
+ argv[0], g_strerror(errno));
+ sync_pipe_errmsg_to_parent(2, errmsg, "");
+
+ /* Exit with "_exit()", so that we don't close the connection
+ to the X server (and cause stuff buffered up by our parent but
+ not yet sent to be sent, as that stuff should only be sent by
+ our parent). We've sent an error message to the parent, so
+ we exit with an exit status of 1 (any exit status other than
+ 0 or 1 will cause an additional message to report that exit
+ status, over and above the error message we sent to the parent). */
+ _exit(1);
+ }
+
+ if (fetch_dumpcap_pid && *fork_child > 0)
+ fetch_dumpcap_pid(*fork_child);
+
+ *data_read_fd = data_pipe[PIPE_READ];
+ *message_read_fd = sync_pipe[PIPE_READ];
+#endif
+
+ /* Parent process - read messages from the child process over the
+ sync pipe. */
+
+ /* Close the write sides of the pipes, so that only the child has them
+ open, and thus they completely close, and thus return to us
+ an EOF indication, if the child closes them (either deliberately
+ or by exiting abnormally). */
+#ifdef _WIN32
+ CloseHandle(data_pipe[PIPE_WRITE]);
+ CloseHandle(sync_pipe[PIPE_WRITE]);
+#else
+ ws_close(data_pipe[PIPE_WRITE]);
+ ws_close(sync_pipe[PIPE_WRITE]);
+#endif
+
+ if (*fork_child == WS_INVALID_PID) {
+ /* We couldn't even create the child process. */
+ *msg = g_strdup_printf("Couldn't create child process: %s", g_strerror(errno));
+ ws_close(*data_read_fd);
+ ws_close(*message_read_fd);
+ return -1;
+ }
+
+ /* we might wait for a moment till child is ready, so update screen now */
+ if (update_cb) update_cb();
+ return 0;
+}
+
+/*
+ * Close the pipes we're using to read from dumpcap, and wait for it
+ * to exit. On success, *msgp is unchanged, and the exit status of
+ * dumpcap is returned. On failure (which includes "dumpcap exited
+ * due to being killed by a signal or an exception"), *msgp points
+ * to an error message for the failure, and -1 is returned. In the
+ * latter case, *msgp must be freed with g_free().
+ */
+static int
+sync_pipe_close_command(int *data_read_fd, int *message_read_fd,
+ ws_process_id *fork_child, gchar **msgp)
+{
+ ws_close(*data_read_fd);
+ if (message_read_fd != NULL)
+ ws_close(*message_read_fd);
+
+#ifdef _WIN32
+ /* XXX - Should we signal the child somehow? */
+ sync_pipe_kill(*fork_child);
+#endif
+
+ return sync_pipe_wait_for_child(*fork_child, msgp);
+}
+
+/*
+ * Run dumpcap with the supplied arguments.
+ *
+ * On success, *data points to a buffer containing the dumpcap output,
+ * *primary_msg and *secondary_message are NULL, and 0 is returned; *data
+ * must be freed with g_free().
+ *
+ * On failure, *data is NULL, *primary_msg points to an error message,
+ * *secondary_msg either points to an additional error message or is
+ * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
+ * must be freed with g_free().
+ */
+/* XXX - This duplicates a lot of code in sync_pipe_start() */
+/* XXX - assumes PIPE_BUF_SIZE > SP_MAX_MSG_LEN */
+#define PIPE_BUF_SIZE 5120
+static int
+sync_pipe_run_command_actual(char* const argv[], gchar **data, gchar **primary_msg,
+ gchar **secondary_msg, void(*update_cb)(void))
+{
+ gchar *msg;
+ int data_pipe_read_fd, sync_pipe_read_fd, ret;
+ ws_process_id fork_child;
+ char *wait_msg;
+ gchar buffer[PIPE_BUF_SIZE+1] = {0};
+ ssize_t nread;
+ char indicator;
+ int primary_msg_len;
+ char *primary_msg_text;
+ int secondary_msg_len;
+ char *secondary_msg_text;
+ char *combined_msg;
+ GString *data_buf = NULL;
+ ssize_t count;
+
+ ret = sync_pipe_open_command(argv, &data_pipe_read_fd, &sync_pipe_read_fd,
+ &fork_child, &msg, update_cb);
+ if (ret == -1) {
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ *data = NULL;
+ return -1;
+ }
+
+ /*
+ * We were able to set up to read dumpcap's output. Do so.
+ *
+ * First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
+ */
+ nread = pipe_read_block(sync_pipe_read_fd, &indicator, SP_MAX_MSG_LEN,
+ buffer, primary_msg);
+ if(nread <= 0) {
+ /* We got a read error from the sync pipe, or we got no data at
+ all from the sync pipe, so we're not going to be getting any
+ data or error message from the child process. Pick up its
+ exit status, and complain.
+
+ We don't have to worry about killing the child, if the sync pipe
+ returned an error. Usually this error is caused as the child killed
+ itself while going down. Even in the rare cases that this isn't the
+ case, the child will get an error when writing to the broken pipe
+ the next time, cleaning itself up then. */
+ ret = sync_pipe_wait_for_child(fork_child, &wait_msg);
+ if(nread == 0) {
+ /* We got an EOF from the sync pipe. That means that it exited
+ before giving us any data to read. If ret is -1, we report
+ that as a bad exit (e.g., exiting due to a signal); otherwise,
+ we report it as a premature exit. */
+ if (ret == -1)
+ *primary_msg = wait_msg;
+ else
+ *primary_msg = g_strdup("Child dumpcap closed sync pipe prematurely");
+ } else {
+ /* We got an error from the sync pipe. If ret is -1, report
+ both the sync pipe I/O error and the wait error. */
+ if (ret == -1) {
+ combined_msg = g_strdup_printf("%s\n\n%s", *primary_msg, wait_msg);
+ g_free(*primary_msg);
+ g_free(wait_msg);
+ *primary_msg = combined_msg;
+ }
+ }
+ *secondary_msg = NULL;
+ *data = NULL;
+
+ return -1;
+ }
+
+ /* we got a valid message block from the child, process it */
+ switch(indicator) {
+
+ case SP_ERROR_MSG:
+ /*
+ * Error from dumpcap; there will be a primary message and a
+ * secondary message.
+ */
+
+ /* convert primary message */
+ pipe_convert_header((guchar*)buffer, 4, &indicator, &primary_msg_len);
+ primary_msg_text = buffer+4;
+ /* convert secondary message */
+ pipe_convert_header((guchar*)primary_msg_text + primary_msg_len, 4, &indicator,
+ &secondary_msg_len);
+ secondary_msg_text = primary_msg_text + primary_msg_len + 4;
+ /* the capture child will close the sync_pipe, nothing to do */
+
+ /*
+ * Pick up the child status.
+ */
+ ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+ &fork_child, &msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ } else {
+ /*
+ * Child process failed, but returned the expected exit status.
+ * Return the messages it gave us, and indicate failure.
+ */
+ *primary_msg = g_strdup(primary_msg_text);
+ *secondary_msg = g_strdup(secondary_msg_text);
+ ret = -1;
+ }
+ *data = NULL;
+ break;
+
+ case SP_SUCCESS:
+ /* read the output from the command */
+ data_buf = g_string_new("");
+ while ((count = ws_read(data_pipe_read_fd, buffer, PIPE_BUF_SIZE)) > 0) {
+ buffer[count] = '\0';
+ g_string_append(data_buf, buffer);
+ }
+
+ /*
+ * Pick up the child status.
+ */
+ ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+ &fork_child, &msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ g_string_free(data_buf, TRUE);
+ *data = NULL;
+ } else {
+ /*
+ * Child process succeeded.
+ */
+ *primary_msg = NULL;
+ *secondary_msg = NULL;
+ *data = g_string_free(data_buf, FALSE);
+ }
+ break;
+
+ default:
+ /*
+ * Pick up the child status.
+ */
+ ret = sync_pipe_close_command(&data_pipe_read_fd, &sync_pipe_read_fd,
+ &fork_child, &msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ *primary_msg = msg;
+ *secondary_msg = NULL;
+ } else {
+ /*
+ * Child process returned an unknown status.
+ */
+ *primary_msg = g_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
+ indicator);
+ *secondary_msg = NULL;
+ ret = -1;
+ }
+ *data = NULL;
+ break;
+ }
+ return ret;
+}
+
+/* centralised logging and timing for sync_pipe_run_command_actual(),
+* redirects to sync_pipe_run_command_actual()
+*/
+static int
+sync_pipe_run_command(char* const argv[], gchar **data, gchar **primary_msg,
+ gchar **secondary_msg, void (*update_cb)(void))
+{
+ int ret, i;
+ gint64 start_time;
+ double elapsed;
+ int logging_enabled;
+
+ /* check if logging is actually enabled, otherwise don't expend the CPU generating logging */
+ logging_enabled=( (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO) & G_LOG_LEVEL_MASK & prefs.console_log_level);
+ if(logging_enabled){
+ start_time = g_get_monotonic_time();
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "sync_pipe_run_command() starts");
+ for(i=0; argv[i] != 0; i++) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, " argv[%d]: %s", i, argv[i]);
+ }
+ }
+ /* do the actual sync pipe run command */
+ ret=sync_pipe_run_command_actual(argv, data, primary_msg, secondary_msg, update_cb);
+
+ if(logging_enabled){
+ elapsed = (g_get_monotonic_time() - start_time) / 1e6;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "sync_pipe_run_command() ends, taking %.3fs, result=%d", elapsed, ret);
+
+ }
+ return ret;
+}
+
+
+int
+sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar *type,
+ const gchar *center_freq1, const gchar *center_freq2,
+ gchar **data, gchar **primary_msg,
+ gchar **secondary_msg, void (*update_cb)(void))
+{
+ int argc, ret;
+ char **argv;
+ gchar *opt;
+
+ argv = init_pipe_args(&argc);
+
+ if (!argv) {
+ *primary_msg = g_strdup("We don't know where to find dumpcap.");
+ *secondary_msg = NULL;
+ *data = NULL;
+ return -1;
+ }
+
+ argv = sync_pipe_add_arg(argv, &argc, "-i");
+ argv = sync_pipe_add_arg(argv, &argc, iface);
+
+ if (center_freq2)
+ opt = g_strdup_printf("%s,%s,%s,%s", freq, type, center_freq1, center_freq2);
+ else if (center_freq1)
+ opt = g_strdup_printf("%s,%s,%s", freq, type, center_freq1);
+ else if (type)
+ opt = g_strdup_printf("%s,%s", freq, type);
+ else
+ opt = g_strdup(freq);
+
+ if (!opt) {
+ *primary_msg = g_strdup("Out of mem.");
+ *secondary_msg = NULL;
+ *data = NULL;
+ free_argv(argv, argc);
+ return -1;
+ }
+
+ argv = sync_pipe_add_arg(argv, &argc, "-k");
+ argv = sync_pipe_add_arg(argv, &argc, opt);
+
+#ifndef DEBUG_CHILD
+ /* Run dumpcap in capture child mode */
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+ argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
+#endif
+
+ ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
+ g_free(opt);
+ free_argv(argv, argc);
+ return ret;
+}
+
+/*
+ * Get the list of interfaces using dumpcap.
+ *
+ * On success, *data points to a buffer containing the dumpcap output,
+ * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
+ * must be freed with g_free().
+ *
+ * On failure, *data is NULL, *primary_msg points to an error message,
+ * *secondary_msg either points to an additional error message or is
+ * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
+ * must be freed with g_free().
+ */
+int
+sync_interface_list_open(gchar **data, gchar **primary_msg,
+ gchar **secondary_msg, void (*update_cb)(void))
+{
+ int argc;
+ char **argv;
+ int ret;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_interface_list_open");
+
+ argv = init_pipe_args(&argc);
+
+ if (!argv) {
+ *primary_msg = g_strdup("We don't know where to find dumpcap..");
+ *secondary_msg = NULL;
+ *data = NULL;
+ return -1;
+ }
+
+ /* Ask for the interface list */
+ argv = sync_pipe_add_arg(argv, &argc, "-D");
+
+#ifndef DEBUG_CHILD
+ /* Run dumpcap in capture child mode */
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+ argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
+#endif
+ ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
+ free_argv(argv, argc);
+ return ret;
+}
+
+/*
+ * Get the capabilities of an interface using dumpcap.
+ *
+ * On success, *data points to a buffer containing the dumpcap output,
+ * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
+ * must be freed with g_free().
+ *
+ * On failure, *data is NULL, *primary_msg points to an error message,
+ * *secondary_msg either points to an additional error message or is
+ * NULL, and -1 is returned; *primary_msg, and *secondary_msg if not NULL,
+ * must be freed with g_free().
+ */
+int
+sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode, const gchar* auth,
+ gchar **data, gchar **primary_msg,
+ gchar **secondary_msg, void (*update_cb)(void))
+{
+ int argc;
+ char **argv;
+ int ret;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_if_capabilities_open");
+
+ argv = init_pipe_args(&argc);
+
+ if (!argv) {
+ *primary_msg = g_strdup("We don't know where to find dumpcap.");
+ *secondary_msg = NULL;
+ *data = NULL;
+ return -1;
+ }
+
+ /* Ask for the interface capabilities */
+ argv = sync_pipe_add_arg(argv, &argc, "-i");
+ argv = sync_pipe_add_arg(argv, &argc, ifname);
+ argv = sync_pipe_add_arg(argv, &argc, "-L");
+ argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types");
+ if (monitor_mode)
+ argv = sync_pipe_add_arg(argv, &argc, "-I");
+ if (auth) {
+ argv = sync_pipe_add_arg(argv, &argc, "-A");
+ argv = sync_pipe_add_arg(argv, &argc, auth);
+ }
+
+#ifndef DEBUG_CHILD
+ /* Run dumpcap in capture child mode */
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+ argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
+#endif
+ ret = sync_pipe_run_command(argv, data, primary_msg, secondary_msg, update_cb);
+ free_argv(argv, argc);
+ return ret;
+}
+
+/*
+ * Start getting interface statistics using dumpcap. On success, read_fd
+ * contains the file descriptor for the pipe's stdout, *msg is unchanged,
+ * and zero is returned. On failure, *msg will point to an error message
+ * that must be g_free()d, and -1 will be returned.
+ */
+int
+sync_interface_stats_open(int *data_read_fd, ws_process_id *fork_child, gchar **msg, void (*update_cb)(void))
+{
+ int argc;
+ char **argv;
+ int message_read_fd, ret;
+ char *wait_msg;
+ gchar buffer[PIPE_BUF_SIZE+1] = {0};
+ ssize_t nread;
+ char indicator;
+ int primary_msg_len;
+ char *primary_msg_text;
+ int secondary_msg_len;
+ /*char *secondary_msg_text;*/
+ char *combined_msg;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_interface_stats_open");
+
+ argv = init_pipe_args(&argc);
+
+ if (!argv) {
+ *msg = g_strdup("We don't know where to find dumpcap.");
+ return -1;
+ }
+
+ /* Ask for the interface statistics */
+ argv = sync_pipe_add_arg(argv, &argc, "-S");
+
+#ifndef DEBUG_CHILD
+ argv = sync_pipe_add_arg(argv, &argc, "-Z");
+#ifdef _WIN32
+ create_dummy_signal_pipe();
+ argv = sync_pipe_add_arg(argv, &argc, dummy_control_id);
+#else
+ argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE);
+#endif
+#endif
+ ret = sync_pipe_open_command(argv, data_read_fd, &message_read_fd,
+ fork_child, msg, update_cb);
+ free_argv(argv, argc);
+ if (ret == -1) {
+ return -1;
+ }
+
+ /*
+ * We were able to set up to read dumpcap's output. Do so.
+ *
+ * First, wait for an SP_ERROR_MSG message or SP_SUCCESS message.
+ */
+ nread = pipe_read_block(message_read_fd, &indicator, SP_MAX_MSG_LEN,
+ buffer, msg);
+ if(nread <= 0) {
+ /* We got a read error from the sync pipe, or we got no data at
+ all from the sync pipe, so we're not going to be getting any
+ data or error message from the child process. Pick up its
+ exit status, and complain.
+
+ We don't have to worry about killing the child, if the sync pipe
+ returned an error. Usually this error is caused as the child killed
+ itself while going down. Even in the rare cases that this isn't the
+ case, the child will get an error when writing to the broken pipe
+ the next time, cleaning itself up then. */
+ ret = sync_pipe_wait_for_child(*fork_child, &wait_msg);
+ ws_close(message_read_fd);
+ ws_close(*data_read_fd);
+ if(nread == 0) {
+ /* We got an EOF from the sync pipe. That means that it exited
+ before giving us any data to read. If ret is -1, we report
+ that as a bad exit (e.g., exiting due to a signal); otherwise,
+ we report it as a premature exit. */
+ if (ret == -1)
+ *msg = wait_msg;
+ else
+ *msg = g_strdup("Child dumpcap closed sync pipe prematurely");
+ } else {
+ /* We got an error from the sync pipe. If ret is -1, report
+ both the sync pipe I/O error and the wait error. */
+ if (ret == -1) {
+ combined_msg = g_strdup_printf("%s\n\n%s", *msg, wait_msg);
+ g_free(*msg);
+ g_free(wait_msg);
+ *msg = combined_msg;
+ }
+ }
+ return -1;
+ }
+
+ /* we got a valid message block from the child, process it */
+ switch(indicator) {
+
+ case SP_ERROR_MSG:
+ /*
+ * Error from dumpcap; there will be a primary message and a
+ * secondary message.
+ */
+
+ /* convert primary message */
+ pipe_convert_header((guchar*)buffer, 4, &indicator, &primary_msg_len);
+ primary_msg_text = buffer+4;
+ /* convert secondary message */
+ pipe_convert_header((guchar*)primary_msg_text + primary_msg_len, 4, &indicator,
+ &secondary_msg_len);
+ /*secondary_msg_text = primary_msg_text + primary_msg_len + 4;*/
+ /* the capture child will close the sync_pipe, nothing to do */
+
+ /*
+ * Pick up the child status.
+ */
+ ret = sync_pipe_close_command(data_read_fd, &message_read_fd,
+ fork_child, msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ } else {
+ /*
+ * Child process failed, but returned the expected exit status.
+ * Return the messages it gave us, and indicate failure.
+ */
+ *msg = g_strdup(primary_msg_text);
+ ret = -1;
+ }
+ break;
+
+ case SP_SUCCESS:
+ /* Close the message pipe. */
+ ws_close(message_read_fd);
+ break;
+
+ default:
+ /*
+ * Pick up the child status.
+ */
+ ret = sync_pipe_close_command(data_read_fd, &message_read_fd,
+ fork_child, msg);
+ if (ret == -1) {
+ /*
+ * Child process failed unexpectedly, or wait failed; msg is the
+ * error message.
+ */
+ } else {
+ /*
+ * Child process returned an unknown status.
+ */
+ *msg = g_strdup_printf("dumpcap process gave an unexpected message type: 0x%02x",
+ indicator);
+ ret = -1;
+ }
+ break;
+ }
+ return ret;
+}
+
+/* Close down the stats process */
+int
+sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, gchar **msg)
+{
+#ifndef _WIN32
+ /*
+ * Don't bother waiting for the child. sync_pipe_close_command
+ * does this for us on Windows.
+ */
+ sync_pipe_kill(*fork_child);
+#endif
+ return sync_pipe_close_command(read_fd, NULL, fork_child, msg);
+}
+
+/* read a number of bytes from a pipe */
+/* (blocks until enough bytes read or an error occurs) */
+static ssize_t
+pipe_read_bytes(int pipe_fd, char *bytes, int required, char **msg)
+{
+ ssize_t newly;
+ ssize_t offset = 0;
+ int error;
+
+ while(required) {
+ newly = ws_read(pipe_fd, &bytes[offset], required);
+ if (newly == 0) {
+ /* EOF */
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read from pipe %d: EOF (capture closed?)", pipe_fd);
+ *msg = 0;
+ return offset;
+ }
+ if (newly < 0) {
+ /* error */
+ error = errno;
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read from pipe %d: error(%u): %s", pipe_fd, error,
+ g_strerror(error));
+ *msg = g_strdup_printf("Error reading from sync pipe: %s",
+ g_strerror(error));
+ return newly;
+ }
+
+ required -= (int)newly;
+ offset += newly;
+ }
+
+ *msg = NULL;
+ return offset;
+}
+
+/*
+ * Read a line from a pipe; similar to fgets, but doesn't block.
+ *
+ * XXX - just stops reading if there's nothing to be read right now;
+ * that could conceivably mean that you don't get a complete line.
+ */
+int
+sync_pipe_gets_nonblock(int pipe_fd, char *bytes, int max) {
+ ssize_t newly;
+ int offset = -1;
+
+ while(offset < max - 1) {
+ offset++;
+ if (! ws_pipe_data_available(pipe_fd))
+ break;
+ newly = ws_read(pipe_fd, &bytes[offset], 1);
+ if (newly == 0) {
+ /* EOF - not necessarily an error */
+ break;
+ } else if (newly == -1) {
+ /* error */
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read from pipe %d: error(%u): %s", pipe_fd, errno, g_strerror(errno));
+ return -1;
+ } else if (bytes[offset] == '\n') {
+ break;
+ }
+ }
+
+ if (offset >= 0)
+ bytes[offset] = '\0';
+
+ return offset;
+}
+
+
+/* convert header values (indicator and 3-byte length) */
+static void
+pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len) {
+
+ g_assert(header_len == 4);
+
+ /* convert header values */
+ *indicator = header[0];
+ *block_len = (header[1]&0xFF)<<16 | (header[2]&0xFF)<<8 | (header[3]&0xFF);
+}
+
+/* read a message from the sending pipe in the standard format
+ (1-byte message indicator, 3-byte message length (excluding length
+ and indicator field), and the rest is the message) */
+static ssize_t
+pipe_read_block(int pipe_fd, char *indicator, int len, char *msg,
+ char **err_msg)
+{
+ int required;
+ ssize_t newly;
+ gchar header[4];
+
+ /* read header (indicator and 3-byte length) */
+ newly = pipe_read_bytes(pipe_fd, header, 4, err_msg);
+ if(newly != 4) {
+ if (newly == 0) {
+ /*
+ * Immediate EOF; if the capture child exits normally, this
+ * is an "I'm done" indication, so don't report it as an
+ * error.
+ */
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read %d got an EOF", pipe_fd);
+ return 0;
+ }
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read %d failed to read header: %lu", pipe_fd, (long)newly);
+ if (newly != -1) {
+ /*
+ * Short read, but not an immediate EOF.
+ */
+ *err_msg = g_strdup_printf("Premature EOF reading from sync pipe: got only %ld bytes",
+ (long)newly);
+ }
+ return -1;
+ }
+
+ /* convert header values */
+ pipe_convert_header((guchar*)header, 4, indicator, &required);
+
+ /* only indicator with no value? */
+ if(required == 0) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read %d indicator: %c empty value", pipe_fd, *indicator);
+ return 4;
+ }
+
+ /* does the data fit into the given buffer? */
+ if(required > len) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read %d length error, required %d > len %d, header: 0x%02x 0x%02x 0x%02x 0x%02x",
+ pipe_fd, required, len,
+ header[0], header[1], header[2], header[3]);
+
+ /* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */
+ memcpy(msg, header, sizeof(header));
+ newly = ws_read(pipe_fd, &msg[sizeof(header)], len-sizeof(header));
+ if (newly < 0) { /* error */
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read from pipe %d: error(%u): %s", pipe_fd, errno, g_strerror(errno));
+ }
+ *err_msg = g_strdup_printf("Unknown message from dumpcap reading header, try to show it as a string: %s",
+ msg);
+ return -1;
+ }
+ len = required;
+
+ /* read the actual block data */
+ newly = pipe_read_bytes(pipe_fd, msg, required, err_msg);
+ if(newly != required) {
+ if (newly != -1) {
+ *err_msg = g_strdup_printf("Unknown message from dumpcap reading data, try to show it as a string: %s",
+ msg);
+ }
+ return -1;
+ }
+
+ /* XXX If message is "2part", the msg probably won't be sent to debug log correctly */
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ "read %d ok indicator: %c len: %u msg: %s", pipe_fd, *indicator,
+ len, msg);
+ *err_msg = NULL;
+ return newly + 4;
+}
+
+
+/* There's stuff to read from the sync pipe, meaning the child has sent
+ us a message, or the sync pipe has closed, meaning the child has
+ closed it (perhaps because it exited). */
+static gboolean
+sync_pipe_input_cb(gint source, gpointer user_data)
+{
+ capture_session *cap_session = (capture_session *)user_data;
+ int ret;
+ char buffer[SP_MAX_MSG_LEN+1] = {0};
+ ssize_t nread;
+ char indicator;
+ int primary_len;
+ char *primary_msg;
+ int secondary_len;
+ char *secondary_msg;
+ char *wait_msg, *combined_msg;
+ guint32 npackets = 0;
+
+ nread = pipe_read_block(source, &indicator, SP_MAX_MSG_LEN, buffer,
+ &primary_msg);
+ if(nread <= 0) {
+ /* We got a read error, or a bad message, or an EOF, from the sync pipe.
+
+ If we got a read error or a bad message, nread is -1 and
+ primary_msg is set to point to an error message. We don't
+ have to worry about killing the child; usually this error
+ is caused as the child killed itself while going down.
+ Even in the rare cases that this isn't the case, the child
+ will get an error when writing to the broken pipe the next time,
+ cleaning itself up then.
+
+ If we got an EOF, nread is 0 and primary_msg isn't set. This
+ is an indication that the capture is finished. */
+ ret = sync_pipe_wait_for_child(cap_session->fork_child, &wait_msg);
+ if(nread == 0) {
+ /* We got an EOF from the sync pipe. That means that the capture
+ child exited, and not in the middle of a message; we treat
+ that as an indication that it's done, and only report an
+ error if ret is -1, in which case wait_msg is the error
+ message. */
+ if (ret == -1)
+ primary_msg = wait_msg;
+ } else {
+ /* We got an error from the sync pipe. If ret is -1, report
+ both the sync pipe I/O error and the wait error. */
+ if (ret == -1) {
+ combined_msg = g_strdup_printf("%s\n\n%s", primary_msg, wait_msg);
+ g_free(primary_msg);
+ g_free(wait_msg);
+ primary_msg = combined_msg;
+ }
+ }
+
+ /* No more child process. */
+ cap_session->fork_child = WS_INVALID_PID;
+ cap_session->fork_child_status = ret;
+
+#ifdef _WIN32
+ ws_close(cap_session->signal_pipe_write_fd);
+#endif
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: cleaning extcap pipe");
+ extcap_if_cleanup(cap_session->capture_opts, &primary_msg);
+ cap_session->closed(cap_session, primary_msg);
+ g_free(primary_msg);
+ return FALSE;
+ }
+
+ /* we got a valid message block from the child, process it */
+ switch(indicator) {
+ case SP_FILE:
+ if(!cap_session->new_file(cap_session, buffer)) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: file failed, closing capture");
+
+ /* We weren't able to open the new capture file; user has been
+ alerted. Close the sync pipe. */
+ ws_close(source);
+
+ /* The child has sent us a filename which we couldn't open.
+
+ This could mean that the child is creating and deleting files
+ (ring buffer mode) faster than we can handle it.
+
+ That should only be the case for very fast file switches;
+ We can't do much more than telling the child to stop.
+ (This is the "emergency brake" if the user e.g. wants to
+ switch files every second).
+
+ This can also happen if the user specified "-", meaning
+ "standard output", as the capture file. */
+ sync_pipe_stop(cap_session);
+ cap_session->closed(cap_session, NULL);
+ return FALSE;
+ }
+ break;
+ case SP_PACKET_COUNT:
+ if (!ws_strtou32(buffer, NULL, &npackets)) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "Invalid packets number: %s", buffer);
+ }
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: new packets %u", npackets);
+ cap_session->count += npackets;
+ cap_session->new_packets(cap_session, npackets);
+ break;
+ case SP_ERROR_MSG:
+ /* convert primary message */
+ pipe_convert_header((guchar*)buffer, 4, &indicator, &primary_len);
+ primary_msg = buffer+4;
+ /* convert secondary message */
+ pipe_convert_header((guchar*)primary_msg + primary_len, 4, &indicator, &secondary_len);
+ secondary_msg = primary_msg + primary_len + 4;
+ /* message output */
+ cap_session->error(cap_session, primary_msg, secondary_msg);
+ /* the capture child will close the sync_pipe, nothing to do for now */
+ /* (an error message doesn't mean we have to stop capturing) */
+ break;
+ case SP_BAD_FILTER: {
+ const char *message=NULL;
+ guint32 indx = 0;
+ const gchar* end;
+
+ if (ws_strtou32(buffer, &end, &indx) && end[0] == ':') {
+ message = end + 1;
+ }
+
+ cap_session->cfilter_error(cap_session, indx, message);
+ /* the capture child will close the sync_pipe, nothing to do for now */
+ break;
+ }
+ case SP_DROPS: {
+ const char *name = NULL;
+ const gchar* end;
+ guint32 num = 0;
+
+ if (ws_strtou32(buffer, &end, &num) && end[0] == ':') {
+ name = end + 1;
+ }
+
+ cap_session->drops(cap_session, num, name);
+ break;
+ }
+ default:
+ g_assert_not_reached();
+ }
+
+ return TRUE;
+}
+
+
+
+/*
+ * dumpcap is exiting; wait for it to exit. On success, *msgp is
+ * unchanged, and the exit status of dumpcap is returned. On
+ * failure (which includes "dumpcap exited due to being killed by
+ * a signal or an exception"), *msgp points to an error message
+ * for the failure, and -1 is returned. In the latter case, *msgp
+ * must be freed with g_free().
+ */
+static int
+sync_pipe_wait_for_child(ws_process_id fork_child, gchar **msgp)
+{
+ int fork_child_status;
+#ifndef _WIN32
+ int retry_waitpid = 3;
+#endif
+ int ret = -1;
+ gint64 start_time;
+ double elapsed;
+
+ start_time = g_get_monotonic_time();
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: wait till child closed");
+ g_assert(fork_child != WS_INVALID_PID);
+
+ *msgp = NULL; /* assume no error */
+#ifdef _WIN32
+ if (_cwait(&fork_child_status, (intptr_t) fork_child, _WAIT_CHILD) == -1) {
+ *msgp = g_strdup_printf("Error from cwait(): %s", g_strerror(errno));
+ ret = -1;
+ } else {
+ /*
+ * The child exited; return its exit status. Do not treat this as
+ * an error.
+ */
+ ret = fork_child_status;
+ if ((fork_child_status & 0xC0000000) == ERROR_SEVERITY_ERROR) {
+ /* Probably an exception code */
+ *msgp = g_strdup_printf("Child dumpcap process died: %s",
+ win32strexception(fork_child_status));
+ ret = -1;
+ }
+ }
+#else
+ while (--retry_waitpid >= 0) {
+ if (waitpid(fork_child, &fork_child_status, 0) != -1) {
+ /* waitpid() succeeded */
+ if (WIFEXITED(fork_child_status)) {
+ /*
+ * The child exited; return its exit status. Do not treat this as
+ * an error.
+ */
+ ret = WEXITSTATUS(fork_child_status);
+ } else if (WIFSTOPPED(fork_child_status)) {
+ /* It stopped, rather than exiting. "Should not happen." */
+ *msgp = g_strdup_printf("Child dumpcap process stopped: %s",
+ sync_pipe_signame(WSTOPSIG(fork_child_status)));
+ ret = -1;
+ } else if (WIFSIGNALED(fork_child_status)) {
+ /* It died with a signal. */
+ *msgp = g_strdup_printf("Child dumpcap process died: %s%s",
+ sync_pipe_signame(WTERMSIG(fork_child_status)),
+ WCOREDUMP(fork_child_status) ? " - core dumped" : "");
+ ret = -1;
+ } else {
+ /* What? It had to either have exited, or stopped, or died with
+ a signal; what happened here? */
+ *msgp = g_strdup_printf("Bad status from waitpid(): %#o",
+ fork_child_status);
+ ret = -1;
+ }
+ } else {
+ /* waitpid() failed */
+ if (errno == EINTR) {
+ /*
+ * Signal interrupted waitpid().
+ *
+ * If it's SIGALRM, we just want to keep waiting, in case
+ * there's some timer using it (e.g., in a GUI toolkit).
+ *
+ * If you ^C TShark (or Wireshark), that should deliver
+ * SIGINT to dumpcap as well. dumpcap catches SIGINT,
+ * and should clean up and exit, so we should eventually
+ * see that and clean up and terminate.
+ *
+ * If we're sent a SIGTERM, we should (and do) catch it,
+ * and TShark, at least, calls sync_pipe_stop(). which
+ * kills dumpcap, so we should eventually see that and
+ * clean up and terminate.
+ */
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "sync_pipe_wait_for_child: waitpid returned EINTR. retrying.");
+ continue;
+ } else if (errno == ECHILD) {
+ /*
+ * The process identified by fork_child either doesn't
+ * exist any more or isn't our child process (anymore?).
+ *
+ * echld might have already reaped the child.
+ */
+ ret = fetch_dumpcap_pid ? 0 : -1;
+ } else {
+ /* Unknown error. */
+ *msgp = g_strdup_printf("Error from waitpid(): %s", g_strerror(errno));
+ ret = -1;
+ }
+ }
+ break;
+ }
+#endif
+
+ elapsed = (g_get_monotonic_time() - start_time) / 1e6;
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: capture child closed after %.3fs", elapsed);
+ return ret;
+}
+
+
+#ifndef _WIN32
+/* convert signal to corresponding name */
+static const char *
+sync_pipe_signame(int sig)
+{
+ const char *sigmsg;
+ static char sigmsg_buf[6+1+3+1];
+
+ switch (sig) {
+
+ case SIGHUP:
+ sigmsg = "Hangup";
+ break;
+
+ case SIGINT:
+ sigmsg = "Interrupted";
+ break;
+
+ case SIGQUIT:
+ sigmsg = "Quit";
+ break;
+
+ case SIGILL:
+ sigmsg = "Illegal instruction";
+ break;
+
+ case SIGTRAP:
+ sigmsg = "Trace trap";
+ break;
+
+ case SIGABRT:
+ sigmsg = "Abort";
+ break;
+
+ case SIGFPE:
+ sigmsg = "Arithmetic exception";
+ break;
+
+ case SIGKILL:
+ sigmsg = "Killed";
+ break;
+
+ case SIGBUS:
+ sigmsg = "Bus error";
+ break;
+
+ case SIGSEGV:
+ sigmsg = "Segmentation violation";
+ break;
+
+ /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
+ Linux is POSIX compliant. These are not POSIX-defined signals ---
+ ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
+
+ ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
+ were omitted from POSIX.1 because their behavior is
+ implementation dependent and could not be adequately catego-
+ rized. Conforming implementations may deliver these sig-
+ nals, but must document the circumstances under which they
+ are delivered and note any restrictions concerning their
+ delivery.''
+
+ So we only check for SIGSYS on those systems that happen to
+ implement them (a system can be POSIX-compliant and implement
+ them, it's just that POSIX doesn't *require* a POSIX-compliant
+ system to implement them).
+ */
+
+#ifdef SIGSYS
+ case SIGSYS:
+ sigmsg = "Bad system call";
+ break;
+#endif
+
+ case SIGPIPE:
+ sigmsg = "Broken pipe";
+ break;
+
+ case SIGALRM:
+ sigmsg = "Alarm clock";
+ break;
+
+ case SIGTERM:
+ sigmsg = "Terminated";
+ break;
+
+ default:
+ /* Returning a static buffer is ok in the context we use it here */
+ g_snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
+ sigmsg = sigmsg_buf;
+ break;
+ }
+ return sigmsg;
+}
+#endif
+
+
+#ifdef _WIN32
+
+static void create_dummy_signal_pipe() {
+ gchar *dummy_signal_pipe_name;
+
+ if (dummy_signal_pipe != NULL) return;
+
+ if (!dummy_control_id) {
+ dummy_control_id = g_strdup_printf("%d.dummy", GetCurrentProcessId());
+ }
+
+ /* Create the signal pipe */
+ dummy_signal_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT, dummy_control_id);
+ dummy_signal_pipe = CreateNamedPipe(utf_8to16(dummy_signal_pipe_name),
+ PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL);
+ g_free(dummy_signal_pipe_name);
+}
+
+/* tell the child through the signal pipe that we want to quit the capture */
+static void
+signal_pipe_capquit_to_child(capture_session *cap_session)
+{
+ const char quit_msg[] = "QUIT";
+ int ret;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "signal_pipe_capquit_to_child");
+
+ /* it doesn't matter *what* we send here, the first byte will stop the capture */
+ /* simply sending a "QUIT" string */
+ /*pipe_write_block(cap_session->signal_pipe_write_fd, SP_QUIT, quit_msg);*/
+ ret = ws_write(cap_session->signal_pipe_write_fd, quit_msg, sizeof quit_msg);
+ if(ret == -1) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
+ "signal_pipe_capquit_to_child: %d header: error %s", cap_session->signal_pipe_write_fd, g_strerror(errno));
+ }
+}
+#endif
+
+
+/* user wants to stop the capture run */
+void
+sync_pipe_stop(capture_session *cap_session)
+{
+#ifdef _WIN32
+ int count;
+ DWORD childstatus;
+ gboolean terminate = TRUE;
+#endif
+ if (cap_session->fork_child != WS_INVALID_PID) {
+#ifndef _WIN32
+ /* send the SIGINT signal to close the capture child gracefully. */
+ int sts = kill(cap_session->fork_child, SIGINT);
+ if (sts != 0) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
+ "Sending SIGINT to child failed: %s\n", g_strerror(errno));
+ }
+#else
+#define STOP_SLEEP_TIME 500 /* ms */
+#define STOP_CHECK_TIME 50
+ /* First, use the special signal pipe to try to close the capture child
+ * gracefully.
+ */
+ signal_pipe_capquit_to_child(cap_session);
+
+ /* Next, wait for the process to exit on its own */
+ for (count = 0; count < STOP_SLEEP_TIME / STOP_CHECK_TIME; count++) {
+ if (GetExitCodeProcess((HANDLE) cap_session->fork_child, &childstatus) &&
+ childstatus != STILL_ACTIVE) {
+ terminate = FALSE;
+ break;
+ }
+ Sleep(STOP_CHECK_TIME);
+ }
+
+ /* Force the issue. */
+ if (terminate) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
+ "sync_pipe_stop: forcing child to exit");
+ sync_pipe_kill(cap_session->fork_child);
+ }
+#endif
+ }
+}
+
+
+/* Wireshark has to exit, force the capture child to close */
+void
+sync_pipe_kill(ws_process_id fork_child)
+{
+ if (fork_child != WS_INVALID_PID) {
+#ifndef _WIN32
+ int sts = kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
+ if (sts != 0) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
+ "Sending SIGTERM to child failed: %s\n", g_strerror(errno));
+ }
+#else
+ /* Remark: This is not the preferred method of closing a process!
+ * the clean way would be getting the process id of the child process,
+ * then getting window handle hWnd of that process (using EnumChildWindows),
+ * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
+ *
+ * Unfortunately, I don't know how to get the process id from the
+ * handle. OpenProcess will get an handle (not a window handle)
+ * from the process ID; it will not get a window handle from the
+ * process ID. (How could it? A process can have more than one
+ * window. For that matter, a process might have *no* windows,
+ * as a process running dumpcap, the normal child process program,
+ * probably does.)
+ *
+ * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
+ * running in the same console; that's not necessarily the case for
+ * us, as we might not be running in a console.
+ * And this also will require to have the process id.
+ */
+ TerminateProcess((HANDLE) (fork_child), 0);
+
+#endif
+ }
+}
+
+void capture_sync_set_fetch_dumpcap_pid_cb(void(*cb)(ws_process_id pid)) {
+ fetch_dumpcap_pid = cb;
+}
+
+#endif /* HAVE_LIBPCAP */
diff --git a/capture/capture_sync.h b/capture/capture_sync.h
new file mode 100644
index 0000000000..b2c6751eff
--- /dev/null
+++ b/capture/capture_sync.h
@@ -0,0 +1,112 @@
+/* capture_sync.h
+ * Synchronisation between Wireshark capture parent and child instances
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+
+/** @file
+ *
+ * Sync mode capture (internal interface).
+ *
+ * Will start a new Wireshark child instance which will do the actual capture
+ * work.
+ */
+
+#ifndef __CAPTURE_SYNC_H__
+#define __CAPTURE_SYNC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct _info_data;
+
+/**
+ * Start a new capture session.
+ * Create a capture child which is doing the real capture work.
+ * The various capture_input_... functions will be called, if something had
+ * happened.
+ *
+ * Most of the parameters are passed through the global capture_opts.
+ *
+ * @param capture_opts the options
+ * @param cap_session a handle for the capture session
+ * @param cap_data a struct with capture info data
+ * @param update_cb update screen
+ * @return TRUE if a capture could be started, FALSE if not
+ */
+extern gboolean
+sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, struct _info_data* cap_data, void(*update_cb)(void));
+
+/** User wants to stop capturing, gracefully close the capture child */
+extern void
+sync_pipe_stop(capture_session *cap_session);
+
+/** User wants to stop the program, just kill the child as soon as possible */
+extern void
+sync_pipe_kill(ws_process_id fork_child);
+
+/**
+ * Set wireless channel using dumpcap
+ * On success, *data points to a buffer containing the dumpcap output,
+ * *primary_msg and *secondary_msg are NULL, and 0 is returned. *data
+ * must be freed with g_free().
+ *
+ * On failure, *data is NULL, *primary_msg points to an error message,
+ * *secondary_msg either points to an additional error message or is
+ * NULL, and -1 or errno value is returned; *primary_msg, and
+ * *secondary_msg if not NULL must be freed with g_free().
+ *
+ * @param iface (monitor) network interface name
+ * @param freq channel control frequency string (in MHz)
+ * @param type channel type string (or NULL if not used)
+ * @param center_freq1 VHT channel center frequency (or NULL if not used)
+ * @param center_freq2 VHT channel center frequency 2 (or NULL if not used)
+ * @param data On success, *data points to a buffer containing the dumpcap output, On failure *data is NULL
+ * @param primary_msg On success NULL, On failure points to an error message
+ * @param secondary_msg On success NULL, On failure either points to an additional error message or is NULL
+ * @param update_cb update callback
+ * @return 0 on success
+ */
+extern int
+sync_interface_set_80211_chan(const gchar *iface, const char *freq, const gchar *type,
+ const gchar *center_freq1, const gchar *center_freq2,
+ gchar **data, gchar **primary_msg,
+ gchar **secondary_msg, void (*update_cb)(void));
+
+/** Get an interface list using dumpcap */
+extern int
+sync_interface_list_open(gchar **data, gchar **primary_msg,
+ gchar **secondary_msg, void (*update_cb)(void));
+
+/** Get interface capabilities using dumpcap */
+extern int
+sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode, const gchar* auth,
+ gchar **data, gchar **primary_msg,
+ gchar **secondary_msg, void (*update_cb)(void));
+
+/** Start getting interface statistics using dumpcap. */
+extern int
+sync_interface_stats_open(int *read_fd, ws_process_id *fork_child, gchar **msg, void (*update_cb)(void));
+
+/** Stop gathering statistics. */
+extern int
+sync_interface_stats_close(int *read_fd, ws_process_id *fork_child, gchar **msg);
+
+/** Read a line from a pipe, similar to fgets. Non-blocking. */
+extern int
+sync_pipe_gets_nonblock(int pipe_fd, char *bytes, int max);
+
+/* set a callback to be called after fork with the pid of the forked child */
+extern void capture_sync_set_fetch_dumpcap_pid_cb(void(*cb)(ws_process_id pid));
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __CAPTURE_SYNC_H__ */
diff --git a/capture/capture_win_ifnames.c b/capture/capture_win_ifnames.c
new file mode 100644
index 0000000000..90cc1cbffd
--- /dev/null
+++ b/capture/capture_win_ifnames.c
@@ -0,0 +1,271 @@
+/* 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
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#ifdef _WIN32
+
+#include <winsock2.h>
+#include <windows.h>
+#include <iphlpapi.h>
+#include <stdio.h>
+#include <stdlib.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 "capture/capture_ifinfo.h"
+#include "capture/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;
+}
+
+/**********************************************************************************/
+/* Get the friendly name for the given GUID */
+char *
+get_interface_friendly_name_from_device_guid(__in GUID *guid)
+{
+ HRESULT hr;
+
+ /* 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
+ */
+
+ NET_LUID InterfaceLuid;
+ hr = ConvertInterfaceGuidToLuid(guid, &InterfaceLuid);
+ if(hr == NO_ERROR) {
+ /* guid->luid success */
+ WCHAR wName[NDIS_IF_MAX_STRING_SIZE + 1];
+ hr = ConvertInterfaceLuidToAlias(&InterfaceLuid, wName, NDIS_IF_MAX_STRING_SIZE+1);
+ if(hr == NO_ERROR) {
+ /* luid->friendly name success */
+
+ /* Get the required buffer size, and then convert the string
+ * from UTF-16 to UTF-8. */
+ int size;
+ char *name;
+ size = WideCharToMultiByte(CP_UTF8, 0, wName, -1, NULL, 0, NULL, NULL);
+ if(size != 0) {
+ name = (char *) g_malloc(size);
+ if (name != NULL) {
+ size = WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, size, NULL, NULL);
+ if(size != 0) {
+ return name;
+ }
+ /* Failed, clean up the allocation */
+ g_free(name);
+ }
+ }
+ }
+ }
+
+ /* Failed to get a name */
+ return NULL;
+}
+
+/*
+ * 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
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/capture/capture_win_ifnames.h b/capture/capture_win_ifnames.h
new file mode 100644
index 0000000000..9289d2499f
--- /dev/null
+++ b/capture/capture_win_ifnames.h
@@ -0,0 +1,34 @@
+/* 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
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#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/capture/iface_monitor.c b/capture/iface_monitor.c
new file mode 100644
index 0000000000..6791a60103
--- /dev/null
+++ b/capture/iface_monitor.c
@@ -0,0 +1,398 @@
+/* iface_monitor.c
+ * interface monitor by Pontus Fuchs <pontus.fuchs@gmail.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <config.h>
+
+#ifdef HAVE_LIBPCAP
+
+#include <capture/iface_monitor.h>
+#include "ws_attributes.h"
+
+#if defined(HAVE_LIBNL)
+
+/*
+ * Linux with libnl.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+DIAG_OFF_PEDANTIC
+#include <netlink/msg.h>
+DIAG_ON_PEDANTIC
+#include <netlink/attr.h>
+DIAG_OFF_PEDANTIC
+#include <netlink/route/link.h>
+DIAG_ON_PEDANTIC
+
+#ifndef IFF_UP
+/*
+ * Apparently, some versions of libnl drag in headers that define IFF_UP
+ * and others don't. Include <net/if.h> iff IFF_UP isn't already defined,
+ * so that if <linux/if.h> has been included by some or all of the
+ * netlink headers, we don't include <net/if.h> and get a bunch of
+ * complaints about various structures being redefined.
+ */
+#include <net/if.h>
+#endif
+
+/* libnl 1.x compatibility code */
+#ifdef HAVE_LIBNL1
+#define nl_sock nl_handle
+#define nl_socket_disable_seq_check nl_disable_sequence_check
+
+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 */
+
+static struct nl_sock *iface_mon_sock;
+
+static void
+iface_mon_handler2(struct nl_object *obj, void *arg)
+{
+ struct rtnl_link *filter;
+ struct rtnl_link *link_obj;
+ int flags, up;
+ char *ifname;
+ iface_mon_cb cb = (iface_mon_cb)arg;
+
+ filter = rtnl_link_alloc();
+ if (!filter) {
+ fprintf(stderr, "error allocating filter\n");
+ return;
+ }
+
+ if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) {
+ rtnl_link_put(filter);
+ return;
+ }
+
+ link_obj = (struct rtnl_link *) obj;
+ flags = rtnl_link_get_flags (link_obj);
+ ifname = rtnl_link_get_name(link_obj);
+
+ /*
+ * You can't bind a PF_PACKET socket to an interface that's not
+ * up, so an interface going down is an "interface should be
+ * removed" indication.
+ *
+ * XXX - what indication, if any, do we get if the interface
+ * *completely goes away*?
+ *
+ * XXX - can we get events if an interface's link-layer or
+ * network addresses change?
+ */
+ up = (flags & IFF_UP) ? 1 : 0;
+
+#ifdef HAVE_LIBNL1
+ cb(ifname, 0, up);
+#else
+ int msg_type = nl_object_get_msgtype(obj);
+
+ switch (msg_type) {
+ case RTM_NEWLINK:
+ cb(ifname, 1, up);
+ break;
+ case RTM_DELLINK:
+ cb(ifname, 0, 0);
+ break;
+ default:
+ /* Ignore other events */
+ break;
+ }
+#endif
+
+ rtnl_link_put(filter);
+
+ return;
+}
+
+static int
+iface_mon_handler(struct nl_msg *msg, void *arg)
+{
+ nl_msg_parse (msg, &iface_mon_handler2, arg);
+ return 0;
+}
+
+void
+iface_mon_event(void)
+{
+ nl_recvmsgs_default(iface_mon_sock);
+}
+
+int
+iface_mon_get_sock(void)
+{
+ return nl_socket_get_fd(iface_mon_sock);
+}
+
+int
+iface_mon_start(iface_mon_cb cb)
+{
+ int err;
+
+ iface_mon_sock = nl_socket_alloc();
+ if (!iface_mon_sock) {
+ fprintf(stderr, "Failed to allocate netlink socket.\n");
+ return -ENOMEM;
+ }
+
+ nl_socket_disable_seq_check(iface_mon_sock);
+
+ nl_socket_modify_cb(iface_mon_sock, NL_CB_VALID, NL_CB_CUSTOM, iface_mon_handler, (void *)cb);
+
+ if (nl_connect(iface_mon_sock, NETLINK_ROUTE)) {
+ fprintf(stderr, "Failed to connect to generic netlink.\n");
+ err = -ENOLINK;
+ goto out_handle_destroy;
+ }
+
+ nl_socket_add_membership(iface_mon_sock, RTNLGRP_LINK);
+
+ return 0;
+
+out_handle_destroy:
+ nl_socket_free(iface_mon_sock);
+ return err;
+}
+
+void
+iface_mon_stop(void)
+{
+ if(iface_mon_sock)
+ nl_socket_free(iface_mon_sock);
+ iface_mon_sock = NULL;
+}
+
+#elif defined(__APPLE__)
+
+/*
+ * macOS.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <sys/kern_event.h>
+
+#include <glib.h>
+
+static int s;
+static iface_mon_cb callback;
+
+int
+iface_mon_start(iface_mon_cb cb)
+{
+ int ret;
+ struct kev_request key;
+
+ /* Create a socket of type PF_SYSTEM to listen for events. */
+ s = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
+ if (s == -1)
+ return -errno;
+
+ /*
+ * Ask for DLIL messages.
+ *
+ * XXX - also ask for KEV_INET_SUBCLASS and KEV_INET6_SUBCLASS,
+ * to detect new or changed network addresses, so those can be
+ * updated as well? Can we specify multiple filters on a socket,
+ * or must we specify KEV_ANY_SUBCLASS and filter the events after
+ * receiving them?
+ */
+ key.vendor_code = KEV_VENDOR_APPLE;
+ key.kev_class = KEV_NETWORK_CLASS;
+ key.kev_subclass = KEV_DL_SUBCLASS;
+ if (ioctl(s, SIOCSKEVFILT, &key) == -1) {
+ ret = -errno;
+ close(s);
+ return ret;
+ }
+
+ callback = cb;
+ return 0;
+}
+
+void
+iface_mon_stop(void)
+{
+ close(s);
+}
+
+int
+iface_mon_get_sock(void)
+{
+ return s;
+}
+
+/*
+ * Size of buffer for kernel network event.
+ */
+#define NET_EVENT_DATA_SIZE (KEV_MSG_HEADER_SIZE + sizeof (struct net_event_data))
+
+void
+iface_mon_event(void)
+{
+ char msg[NET_EVENT_DATA_SIZE];
+ ssize_t received;
+ struct kern_event_msg *kem;
+ struct net_event_data *evd;
+ size_t evd_len;
+ char ifr_name[IFNAMSIZ];
+
+ received = recv(s, msg, sizeof msg, 0);
+ if (received < 0) {
+ /* Error - ignore. */
+ return;
+ }
+ if ((size_t)received < sizeof msg) {
+ /* Short read - ignore. */
+ return;
+ }
+ kem = (struct kern_event_msg *)msg;
+ evd_len = kem->total_size - KEV_MSG_HEADER_SIZE;
+ if (evd_len != sizeof (struct net_event_data)) {
+ /* Length of the message is bogus. */
+ return;
+ }
+ evd = (struct net_event_data *)&kem->event_data[0];
+ g_snprintf(ifr_name, IFNAMSIZ, "%s%u", evd->if_name, evd->if_unit);
+
+ /*
+ * Check type of event.
+ *
+ * Note: if we also ask for KEV_INET_SUBCLASS, we will get
+ * events with keys
+ *
+ * KEV_INET_NEW_ADDR
+ * KEV_INET_CHANGED_ADDR
+ * KEV_INET_CHANGED_ADDR
+ * KEV_INET_SIFDSTADDR
+ * KEV_INET_SIFBRDADDR
+ * KEV_INET_SIFNETMASK
+ *
+ * reflecting network address changes, with the data being a
+ * struct kev_in_data rather than struct net_event_data, and
+ * if we also ask for KEV_INET6_SUBCLASS, we will get events
+ * with keys
+ *
+ * KEV_INET6_NEW_LL_ADDR
+ * KEV_INET6_NEW_USER_ADDR
+ * KEV_INET6_NEW_RTADV_ADDR
+ * KEV_INET6_ADDR_DELETED
+ *
+ * with the data being a struct kev_in6_data.
+ */
+ switch (kem->event_code) {
+
+ case KEV_DL_IF_ATTACHED:
+ /*
+ * A new interface has arrived.
+ *
+ * XXX - what we really want is "a new BPFable interface
+ * has arrived", but that's not available. While we're
+ * asking for additional help from BPF, it'd also be
+ * nice if we could ask it for a list of all interfaces
+ * that have had bpfattach()/bpf_attach() done on them,
+ * so we don't have to try to open the device in order
+ * to see whether we should show it as something on
+ * which we can capture.
+ */
+ callback(ifr_name, 1, 1);
+ break;
+
+ case KEV_DL_IF_DETACHED:
+ /*
+ * An existing interface has been removed.
+ *
+ * XXX - use KEV_DL_IF_DETACHING instead, as that's
+ * called shortly after bpfdetach() is called, and
+ * bpfdetach() makes an interface no longer BPFable,
+ * and that's what we *really* care about.
+ */
+ callback(ifr_name, 0, 0);
+ break;
+
+ default:
+ /*
+ * Is there any reason to care about:
+ *
+ * KEV_DL_LINK_ON
+ * KEV_DL_LINK_OFF
+ * KEV_DL_SIFFLAGS
+ * KEV_DL_LINK_ADDRESS_CHANGED
+ * KEV_DL_IFCAP_CHANGED
+ *
+ * or any of the other events? On Snow Leopard and, I think,
+ * earlier releases, you can't attach a BPF device to an
+ * interface that's not up, so KEV_DL_SIFFLAGS might be
+ * worth listening to so that we only say "here's a new
+ * interface" when it goes up; on Lion (and possibly Mountain
+ * Lion), an interface doesn't have to be up in order to
+ * have a BPF device attached to it.
+ */
+ break;
+ }
+}
+
+#else /* don't have something we support */
+
+int
+iface_mon_start(iface_mon_cb cb _U_)
+{
+ return -1;
+}
+
+void
+iface_mon_stop(void)
+{
+}
+
+int
+iface_mon_get_sock(void)
+{
+ return -1;
+}
+
+void
+iface_mon_event(void)
+{
+}
+
+#endif /* HAVE_LIBNL */
+
+#endif /* HAVE_LIBPCAP */
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/capture/iface_monitor.h b/capture/iface_monitor.h
new file mode 100644
index 0000000000..785ab34a63
--- /dev/null
+++ b/capture/iface_monitor.h
@@ -0,0 +1,71 @@
+/* iface_monitor.h
+ * interface monitor by Pontus Fuchs <pontus.fuchs@gmail.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef IFACE_MONITOR_H
+#define IFACE_MONITOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef HAVE_LIBPCAP
+
+/*
+ * Callback for interface changes.
+ *
+ * iface is a pointer to the name of the interface.
+ *
+ * up is 1 if the interface is up, 0 if it's down.
+ *
+ * XXX - we really want "gone", not "down", where "gone" may include
+ * "down" if the OS requires an interface to be up in order to start
+ * a capture on it (as is the case in Linux and in macOS prior to
+ * Lion), but should also include *gone*, as in "there is no longer
+ * an interface with this name, so it's neither down nor up".
+ *
+ * We also may want other events, such as address changes, so what
+ * we might want is "add", "remove", and "modify" as the events.
+ */
+typedef void (*iface_mon_cb)(const char *iface, int added, int up);
+
+/*
+ * Start watching for interface changes.
+ */
+int
+iface_mon_start(iface_mon_cb cb);
+
+/*
+ * Stop watching for interface changes.
+ */
+void
+iface_mon_stop(void);
+
+/*
+ * Get the socket on which interface changes are delivered, so that
+ * we can add it to the event loop.
+ *
+ * XXX - what if it's not a socket or other file descriptor?
+ */
+int
+iface_mon_get_sock(void);
+
+/*
+ * Call this if something is readable from the interface change socket.
+ * It will call the callback as appropriate.
+ */
+void
+iface_mon_event(void);
+
+#endif /* HAVE_LIBPCAP */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* IFACE_MONITOR_H */
diff --git a/capture/ws80211_utils.c b/capture/ws80211_utils.c
new file mode 100644
index 0000000000..6c34b8e929
--- /dev/null
+++ b/capture/ws80211_utils.c
@@ -0,0 +1,1275 @@
+/*
+ * 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
+
+SPDX-License-Identifier: ISC
+*/
+
+#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>
+
+DIAG_OFF_PEDANTIC
+#include <netlink/genl/genl.h>
+DIAG_ON_PEDANTIC
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+DIAG_OFF_PEDANTIC
+#include <netlink/msg.h>
+DIAG_ON_PEDANTIC
+#include <netlink/attr.h>
+
+#include <linux/nl80211.h>
+
+#include <wsutil/netlink.h>
+
+#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
+static int ws80211_get_protocol_features(int* features);
+#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
+
+/* 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;
+ int have_split_wiphy;
+};
+
+static struct nl80211_state nl_state;
+
+int ws80211_init(void)
+{
+ int err;
+#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
+ int features = 0;
+#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
+
+ 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;
+ }
+#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
+ ws80211_get_protocol_features(&features);
+ if (features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ state->have_split_wiphy = TRUE;
+#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
+
+ return WS80211_INIT_OK;
+
+ 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)
+{
+ /*
+ * XXX - Coverity doesn't understand how libnl works, so it
+ * doesn't know that nl_recvmsgs() calls the callback, and
+ * that the callback has had a pointer to err registered
+ * with it, and therefore that nl_recvmsgs() can change
+ * err as a side-effect, so it thinks this can loop
+ * infinitely.
+ *
+ * The proper way to address this is to help Coverity to
+ * understand the behaviour of nl_recvmsgs(), in that it
+ * does call the callback, setting err. This help would be
+ * provided through a so called 'model' of this function.
+ * We declare err to be volatile to work around it.
+ *
+ * XXX - that workaround provokes a compiler complaint that
+ * casting a pointer to it to "void *" discards the
+ * volatile qualifier. Perhaps we should just re-close
+ * Coverity CID 997052 as "false positive".
+ */
+ 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;
+};
+
+static struct ws80211_interface *
+ get_interface_by_name(GArray *interfaces,
+ char* ifname)
+{
+ unsigned int i;
+ struct ws80211_interface *iface;
+
+ for (i = 0; i < interfaces->len; i++) {
+ iface = g_array_index(interfaces, struct ws80211_interface *, i);
+ if (!strcmp(iface->ifname, ifname))
+ return iface;
+ }
+ return NULL;
+}
+
+#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
+static int get_features_handler(struct nl_msg *msg, void *arg)
+{
+ int *feat = (int*) arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
+ *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+ return NL_SKIP;
+}
+
+static int ws80211_get_protocol_features(int* features)
+{
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ fprintf(stderr, "failed to allocate netlink message\n");
+ return 2;
+ }
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+
+ genlmsg_put(msg, 0, 0, nl_state.nl80211_id, 0, 0,
+ NL80211_CMD_GET_PROTOCOL_FEATURES, 0);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_features_handler, features);
+
+ ret = nl80211_do_cmd(msg, cb);
+ nlmsg_free(msg);
+ return ret;
+}
+#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
+
+#ifdef NL80211_BAND_ATTR_HT_CAPA
+static void parse_band_ht_capa(struct ws80211_interface *iface,
+ struct nlattr *tb)
+{
+ gboolean ht40;
+
+ if (!tb) return;
+
+ iface->channel_types |= 1 << WS80211_CHAN_HT20;
+ ht40 = !!(nla_get_u16(tb) & 0x02);
+ if (ht40) {
+ iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
+ iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
+ }
+}
+#endif /* NL80211_BAND_ATTR_HT_CAPA */
+
+#ifdef HAVE_NL80211_VHT_CAPABILITY
+static void parse_band_vht_capa(struct ws80211_interface *iface,
+ struct nlattr *tb)
+{
+ guint32 chan_capa;
+ if (!tb) return;
+
+ chan_capa = (nla_get_u32(tb) >> 2) & 3;
+ if (chan_capa == 1) {
+ iface->channel_types |= 1 << WS80211_CHAN_VHT160;
+ }
+ if (chan_capa == 2) {
+ iface->channel_types |= 1 << WS80211_CHAN_VHT160;
+ iface->channel_types |= 1 << WS80211_CHAN_VHT80P80;
+ }
+ iface->channel_types |= 1 << WS80211_CHAN_VHT80;
+}
+#endif /* HAVE_NL80211_VHT_CAPABILITY */
+
+static void parse_supported_iftypes(struct ws80211_interface *iface,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_mode;
+ int rem_mode;
+
+ if (!tb) return;
+
+ nla_for_each_nested(nl_mode, tb, rem_mode) {
+ if (nla_type(nl_mode) == NL80211_IFTYPE_MONITOR)
+ iface->cap_monitor = 1;
+ }
+}
+
+static void parse_band_freqs(struct ws80211_interface *iface,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_freq;
+ 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 */
+ };
+ int rem_freq;
+
+ if (!tb) return;
+
+ nla_for_each_nested(nl_freq, tb, 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);
+ }
+}
+
+static void parse_wiphy_bands(struct ws80211_interface *iface,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_band;
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+ int bandidx = 1;
+ int rem_band;
+
+ if (!tb) return;
+
+ nla_for_each_nested(nl_band, tb, 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
+ parse_band_ht_capa(iface, tb_band[NL80211_BAND_ATTR_HT_CAPA]);
+#endif /* NL80211_BAND_ATTR_HT_CAPA */
+#ifdef HAVE_NL80211_VHT_CAPABILITY
+ parse_band_vht_capa(iface, tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
+#endif /* HAVE_NL80211_VHT_CAPABILITY */
+ parse_band_freqs(iface, tb_band[NL80211_BAND_ATTR_FREQS]);
+ }
+}
+
+static void parse_supported_commands(struct ws80211_interface *iface,
+ struct nlattr *tb)
+{
+ /* Can frequency be set? Only newer versions of cfg80211 supports this */
+#ifdef HAVE_NL80211_CMD_SET_CHANNEL
+ int cmd;
+ struct nlattr *nl_cmd;
+
+ if (!tb) return;
+
+ nla_for_each_nested(nl_cmd, tb, cmd) {
+ if(nla_get_u32(nl_cmd) == NL80211_CMD_SET_CHANNEL)
+ iface->can_set_freq = TRUE;
+ }
+#else
+ iface->can_set_freq = TRUE;
+#endif
+}
+
+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 ws80211_interface *iface;
+ char* ifname;
+ int added = 0;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_NAME])
+ return NL_SKIP;
+
+ ifname = g_strdup_printf("%s.mon", nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]));
+ iface = get_interface_by_name(cookie->interfaces, ifname);
+
+ if (!iface) {
+ iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
+ if (!iface) {
+ g_free(ifname);
+ return NL_SKIP;
+ }
+ added = 1;
+ iface->ifname = ifname;
+ iface->frequencies = g_array_new(FALSE, FALSE, sizeof(uint32_t));
+ iface->channel_types = 1 << WS80211_CHAN_NO_HT;
+ } else {
+ g_free(ifname);
+ }
+
+ parse_supported_iftypes(iface, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]);
+ parse_wiphy_bands(iface, tb_msg[NL80211_ATTR_WIPHY_BANDS]);
+ parse_supported_commands(iface, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]);
+
+ if (added)
+ 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;
+ int ret;
+ 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);
+
+#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
+ if (nl_state.have_split_wiphy) {
+ NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
+ }
+#endif /* #ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP */
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_phys_handler, &cookie);
+
+ ret = nl80211_do_cmd(msg, cb);
+ nlmsg_free(msg);
+ return ret;
+
+#ifdef HAVE_NL80211_SPLIT_WIPHY_DUMP
+nla_put_failure:
+ nlmsg_free(msg);
+ fprintf(stderr, "building message failed\n");
+ return -1;
+#endif /* HAVE_NL80211_SPLIT_WIPHY_DUMP */
+}
+
+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]) {
+ gboolean found_ch_width = FALSE;
+ iface_info->pub->current_freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]);
+ iface_info->pub->current_chan_type = WS80211_CHAN_NO_HT;
+#ifdef HAVE_NL80211_VHT_CAPABILITY
+ if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) {
+ switch (nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH])) {
+ case NL80211_CHAN_WIDTH_80:
+ iface_info->pub->current_chan_type = WS80211_CHAN_VHT80;
+ found_ch_width = TRUE;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ iface_info->pub->current_chan_type = WS80211_CHAN_VHT80P80;
+ found_ch_width = TRUE;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ iface_info->pub->current_chan_type = WS80211_CHAN_VHT160;
+ found_ch_width = TRUE;
+ break;
+ }
+ }
+ if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) {
+ iface_info->pub->current_center_freq1 =
+ nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1]);
+ }
+ if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) {
+ iface_info->pub->current_center_freq2 =
+ nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2]);
+ }
+#endif
+ if (!found_ch_width && 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)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ /* Old kernels can't 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);
+ nlmsg_free(msg);
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ 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_keep_only_monitor(GArray *interfaces)
+{
+ unsigned int j;
+ struct ws80211_interface *iface;
+restart:
+ for (j = 0; j < interfaces->len; j++) {
+ iface = g_array_index(interfaces, struct ws80211_interface *, j);
+ if (!iface->cap_monitor) {
+ g_array_remove_index(interfaces, j);
+ g_array_free(iface->frequencies, TRUE);
+ g_free(iface->ifname);
+ g_free(iface);
+ goto restart;
+ }
+ }
+ return 0;
+}
+
+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, -1, -1, WS80211_FCS_ALL};
+ struct __iface_info iface_info;
+ struct ws80211_interface *iface;
+
+ /* Get a list of phy's that can handle monitor mode */
+ ws80211_get_phys(interfaces);
+ ws80211_keep_only_monitor(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++;
+ 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;
+}
+
+/* Needed for NLA_PUT_STRING, which passes strlen as an int */
+DIAG_OFF_CLANG(shorten-64-to-32)
+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);
+ nlmsg_free(msg);
+ if (err)
+ return err;
+ return ws80211_iface_up(name);
+
+nla_put_failure:
+ nlmsg_free(msg);
+ fprintf(stderr, "building message failed\n");
+ return 2;
+}
+DIAG_ON_CLANG(shorten-64-to-32)
+
+int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
+{
+ 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
+#ifdef HAVE_NL80211_VHT_CAPABILITY
+ case WS80211_CHAN_VHT80:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
+ break;
+
+ case WS80211_CHAN_VHT80P80:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_80P80);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, center_freq2);
+ break;
+
+ case WS80211_CHAN_VHT160:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_WIDTH_160);
+ NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, center_freq);
+ break;
+#endif
+ default:
+ break;
+ }
+ err = nl80211_do_cmd(msg, cb);
+ nlmsg_free(msg);
+ return err;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ fprintf(stderr, "building message failed\n");
+ return 2;
+
+}
+
+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_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;
+ if (!strcmp(s, CHAN_VHT80))
+ ret = WS80211_CHAN_VHT80;
+ if (!strcmp(s, CHAN_VHT80P80))
+ ret = WS80211_CHAN_VHT80P80;
+ if (!strcmp(s, CHAN_VHT160))
+ ret = WS80211_CHAN_VHT160;
+
+ 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;
+ case WS80211_CHAN_VHT80:
+ return CHAN_VHT80;
+ case WS80211_CHAN_VHT80P80:
+ return CHAN_VHT80P80;
+ case WS80211_CHAN_VHT160:
+ return CHAN_VHT160;
+ }
+ return NULL;
+}
+
+gboolean ws80211_has_fcs_filter(void)
+{
+ return FALSE;
+}
+
+int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
+{
+ return -1;
+}
+
+const char *network_manager_path = "/usr/sbin/NetworkManager"; /* Is this correct? */
+const char *ws80211_get_helper_path(void) {
+ if (g_file_test(network_manager_path, G_FILE_TEST_IS_EXECUTABLE)) {
+ return network_manager_path;
+ }
+ return NULL;
+}
+
+#elif defined(HAVE_AIRPCAP)
+
+#include <wsutil/unicode-utils.h>
+
+#include "airpcap.h"
+#include "airpcap_loader.h"
+
+int ws80211_init(void)
+{
+ if (airpcap_get_dll_state() == AIRPCAP_DLL_OK) {
+ return WS80211_INIT_OK;
+ }
+ return WS80211_INIT_NOT_SUPPORTED;
+}
+
+static const char *airpcap_dev_prefix_ = "\\\\.\\";
+
+GArray* ws80211_find_interfaces(void)
+{
+ GArray *interfaces;
+ GList *airpcap_if_list, *cur_if;
+ int err;
+ gchar *err_str = NULL;
+
+ interfaces = g_array_new(FALSE, FALSE, sizeof(struct ws80211_interface *));
+ if (!interfaces)
+ return NULL;
+
+ airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
+
+ if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
+ g_free(err_str);
+ g_array_free(interfaces, TRUE);
+ return NULL;
+ }
+
+ for (cur_if = airpcap_if_list; cur_if; cur_if = g_list_next(cur_if)) {
+ struct ws80211_interface *iface;
+ airpcap_if_info_t *airpcap_if_info = (airpcap_if_info_t *) cur_if->data;
+ char *ifname;
+ guint32 chan;
+ guint32 i;
+
+ if (!airpcap_if_info) continue;
+ ifname = airpcap_if_info->name;
+ if (strlen(ifname) > 4 && g_str_has_prefix(ifname, airpcap_dev_prefix_)) ifname += 4;
+
+ iface = (struct ws80211_interface *)g_malloc0(sizeof(*iface));
+ iface->ifname = g_strdup(ifname);
+ iface->can_set_freq = TRUE;
+ iface->frequencies = g_array_new(FALSE, FALSE, sizeof(guint32));
+
+ iface->channel_types = 1 << WS80211_CHAN_NO_HT;
+ /*
+ * AirPcap stores per-channel capabilities. We should probably
+ * do the same. */
+ for (i = 0; i < airpcap_if_info->numSupportedChannels; i++) {
+ if (airpcap_if_info->pSupportedChannels[i].Flags & FLAG_CAN_BE_HIGH) {
+ iface->channel_types |= 1 << WS80211_CHAN_HT40MINUS;
+ iface->channel_types |= 1 << WS80211_CHAN_HT40PLUS;
+ break;
+ }
+ }
+
+ iface->cap_monitor = 1;
+
+ for (chan = 0; chan < airpcap_if_info->numSupportedChannels; chan++) {
+ g_array_append_val(iface->frequencies, airpcap_if_info->pSupportedChannels[chan].Frequency);
+ }
+
+ g_array_append_val(interfaces, iface);
+ }
+
+ return interfaces;
+}
+
+int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info)
+{
+ GList *airpcap_if_list;
+ int err;
+ gchar *err_str = NULL;
+ airpcap_if_info_t *airpcap_if_info;
+
+ if (!iface_info) return -1;
+
+ airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
+
+ if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
+ g_free(err_str);
+ return -1;
+ }
+
+ airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
+
+ if (!airpcap_if_info) {
+ free_airpcap_interface_list(airpcap_if_list);
+ return -1;
+ }
+
+ memset(iface_info, 0, sizeof(*iface_info));
+ iface_info->current_freq = airpcap_if_info->channelInfo.Frequency;
+ switch (airpcap_if_info->channelInfo.ExtChannel) {
+ case 0:
+ iface_info->current_chan_type = WS80211_CHAN_NO_HT;
+ break;
+ case -1:
+ iface_info->current_chan_type = WS80211_CHAN_HT40MINUS;
+ break;
+ case 1:
+ iface_info->current_chan_type = WS80211_CHAN_HT40PLUS;
+ break;
+ default:
+ return -1;
+ }
+
+ switch (airpcap_if_info->CrcValidationOn) {
+ case AIRPCAP_VT_ACCEPT_CORRECT_FRAMES:
+ iface_info->current_fcs_validation = WS80211_FCS_VALID;
+ break;
+ case AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES:
+ iface_info->current_fcs_validation = WS80211_FCS_INVALID;
+ break;
+ default:
+ iface_info->current_fcs_validation = WS80211_FCS_ALL;
+ break;
+ }
+
+ return 0;
+}
+
+int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
+{
+ GList *airpcap_if_list;
+ int err;
+ gchar *err_str = NULL;
+ airpcap_if_info_t *airpcap_if_info;
+ gchar err_buf[AIRPCAP_ERRBUF_SIZE];
+ PAirpcapHandle adapter;
+ int ret_val = -1;
+
+ airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
+
+ if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
+ g_free(err_str);
+ return ret_val;
+ }
+
+ airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
+
+ if (!airpcap_if_info) {
+ free_airpcap_interface_list(airpcap_if_list);
+ return ret_val;
+ }
+
+ adapter = airpcap_if_open(airpcap_if_info->name, err_buf);
+ if (adapter) {
+ airpcap_if_info->channelInfo.Frequency = freq;
+ switch (chan_type) {
+ case WS80211_CHAN_HT40MINUS:
+ airpcap_if_info->channelInfo.ExtChannel = -1;
+ break;
+ case WS80211_CHAN_HT40PLUS:
+ airpcap_if_info->channelInfo.ExtChannel = 1;
+ break;
+ default:
+ airpcap_if_info->channelInfo.ExtChannel = 0;
+ break;
+ }
+
+ if (airpcap_if_set_device_channel_ex(adapter, airpcap_if_info->channelInfo)) {
+ ret_val = 0;
+ }
+ airpcap_if_close(adapter);
+ }
+
+ free_airpcap_interface_list(airpcap_if_list);
+ return ret_val;
+}
+
+int ws80211_str_to_chan_type(const gchar *s _U_)
+{
+ return -1;
+}
+
+const gchar *ws80211_chan_type_to_str(int type _U_)
+{
+ return NULL;
+}
+
+gboolean ws80211_has_fcs_filter(void)
+{
+ return TRUE;
+}
+
+int ws80211_set_fcs_validation(const char *name, enum ws80211_fcs_validation fcs_validation)
+{
+ GList *airpcap_if_list;
+ int err;
+ gchar *err_str = NULL;
+ airpcap_if_info_t *airpcap_if_info;
+ gchar err_buf[AIRPCAP_ERRBUF_SIZE];
+ PAirpcapHandle adapter;
+ int ret_val = -1;
+
+ airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
+
+ if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
+ g_free(err_str);
+ return ret_val;
+ }
+
+ airpcap_if_info = get_airpcap_if_from_name(airpcap_if_list, name);
+
+ if (!airpcap_if_info) {
+ free_airpcap_interface_list(airpcap_if_list);
+ return ret_val;
+ }
+
+ adapter = airpcap_if_open(airpcap_if_info->name, err_buf);
+ if (adapter) {
+ AirpcapValidationType val_type = AIRPCAP_VT_ACCEPT_EVERYTHING;
+ switch (fcs_validation) {
+ case WS80211_FCS_VALID:
+ val_type = AIRPCAP_VT_ACCEPT_CORRECT_FRAMES;
+ break;
+ case WS80211_FCS_INVALID:
+ val_type = AIRPCAP_VT_ACCEPT_CORRUPT_FRAMES;
+ break;
+ default:
+ break;
+ }
+
+ if (airpcap_if_set_fcs_validation(adapter, val_type)) {
+ /* Appears to be necessary for this to take effect. */
+ airpcap_if_store_cur_config_as_adapter_default(adapter);
+ ret_val = 0;
+ }
+ airpcap_if_close(adapter);
+ }
+
+ free_airpcap_interface_list(airpcap_if_list);
+ return ret_val;
+}
+
+static char *airpcap_conf_path = NULL;
+const char *ws80211_get_helper_path(void)
+{
+ HKEY h_key = NULL;
+
+ if (!airpcap_conf_path && RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\AirPcap"), 0, KEY_QUERY_VALUE|KEY_WOW64_32KEY, &h_key) == ERROR_SUCCESS) {
+ DWORD reg_ret;
+ TCHAR airpcap_dir_utf16[MAX_PATH];
+ DWORD ad_size = sizeof(airpcap_dir_utf16)/sizeof(TCHAR);
+
+ reg_ret = RegQueryValueEx(h_key, NULL, NULL, NULL,
+ (LPBYTE) &airpcap_dir_utf16, &ad_size);
+
+ if (reg_ret == ERROR_SUCCESS) {
+ airpcap_dir_utf16[ad_size-1] = L'\0';
+ g_free(airpcap_conf_path);
+ airpcap_conf_path = g_strdup_printf("%s\\AirpcapConf.exe", utf_16to8(airpcap_dir_utf16));
+
+ if (!g_file_test(airpcap_conf_path, G_FILE_TEST_IS_EXECUTABLE)) {
+ g_free(airpcap_conf_path);
+ airpcap_conf_path = NULL;
+ }
+ }
+ }
+
+ return airpcap_conf_path;
+}
+
+#else /* Everyone else. */
+int ws80211_init(void)
+{
+ return WS80211_INIT_NOT_SUPPORTED;
+}
+
+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;
+}
+
+int ws80211_set_freq(const char *name _U_, guint32 freq _U_, int _U_ chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2)
+{
+ 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;
+}
+
+gboolean ws80211_has_fcs_filter(void)
+{
+ return FALSE;
+}
+
+int ws80211_set_fcs_validation(const char *name _U_, enum ws80211_fcs_validation fcs_validation _U_)
+{
+ return -1;
+}
+
+const char *ws80211_get_helper_path(void) {
+ return NULL;
+}
+
+#endif /* HAVE_LIBNL && HAVE_NL80211 */
+
+/* Common to everyone */
+
+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);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */
diff --git a/capture/ws80211_utils.h b/capture/ws80211_utils.h
new file mode 100644
index 0000000000..cc945ce69a
--- /dev/null
+++ b/capture/ws80211_utils.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012, Pontus Fuchs <pontus.fuchs@gmail.com>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __WS80211_UTILS_H__
+#define __WS80211_UTILS_H__
+
+#include "ws_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+enum ws80211_channel_type {
+ WS80211_CHAN_NO_HT,
+ WS80211_CHAN_HT20,
+ WS80211_CHAN_HT40MINUS,
+ WS80211_CHAN_HT40PLUS,
+ WS80211_CHAN_VHT80,
+ WS80211_CHAN_VHT80P80,
+ WS80211_CHAN_VHT160
+};
+
+#define CHAN_NO_HT "NOHT"
+#define CHAN_HT20 "HT20"
+#define CHAN_HT40MINUS "HT40-"
+#define CHAN_HT40PLUS "HT40+"
+#define CHAN_VHT80 "VHT80"
+#define CHAN_VHT80P80 "VHT80+80"
+#define CHAN_VHT160 "VHT160"
+
+/* XXX This doesn't match AirpcapValidationType. Should it? */
+enum ws80211_fcs_validation {
+ WS80211_FCS_ALL,
+ WS80211_FCS_VALID,
+ WS80211_FCS_INVALID
+};
+
+struct ws80211_interface
+{
+ char *ifname;
+ gboolean can_set_freq;
+ gboolean can_check_fcs;
+ GArray *frequencies; /* Array of guint32? */
+ int channel_types; /* Union for all bands */
+ int cap_monitor;
+};
+
+struct ws80211_iface_info {
+ int current_freq;
+ enum ws80211_channel_type current_chan_type;
+ int current_center_freq1;
+ int current_center_freq2;
+ enum ws80211_fcs_validation current_fcs_validation;
+};
+
+/** Initialize the 802.11 environment.
+ * On Linux this initializes an nl80211_state struct.
+ * On Windows this checks the AirPcap status. It does *not* load the
+ * AirPcap DLL. That happens when the program starts.
+ *
+ * @return WS80211_INIT_OK on success, WS80211_INIT_NOT_SUPPORTED if the
+ * 802.11 environment isn't supported, or the negative of an errno value
+ * on failure.
+ */
+#define WS80211_INIT_OK 0
+#define WS80211_INIT_NOT_SUPPORTED 1
+
+int ws80211_init(void);
+
+/** Build a list of 802.11 interfaces.
+ *
+ * @return A GArray of pointers to struct ws80211_interface on success, NULL on failure.
+ */
+/* XXX Should we make this an array of structs instead of an array of struct pointers?
+ * It'd save a bit of mallocing and freeing. */
+GArray* ws80211_find_interfaces(void);
+
+int ws80211_get_iface_info(const char *name, struct ws80211_iface_info *iface_info);
+
+/** Free an interface list.
+ *
+ * @param interfaces A list of interfaces created with ws80211_find_interfaces().
+ */
+void ws80211_free_interfaces(GArray *interfaces);
+
+/** Set the frequency and channel width for an interface.
+ *
+ * @param name The interface name.
+ * @param freq The frequency in MHz.
+ * @param chan_type The HT channel type (no, 20Mhz, 40Mhz...).
+ * @param center_freq The center frequency in MHz (if 80MHz, 80+80MHz or 160MHz).
+ * @param center_freq2 The 2nd center frequency in MHz (if 80+80MHz).
+ * @return Zero on success, nonzero on failure.
+ */
+int ws80211_set_freq(const char *name, guint32 freq, int chan_type, guint32 _U_ center_freq, guint32 _U_ center_freq2);
+
+int ws80211_str_to_chan_type(const gchar *s);
+const gchar *ws80211_chan_type_to_str(int type);
+
+/** Check to see if we have FCS filtering.
+ *
+ * @return TRUE if FCS filtering is supported on this platform.
+ */
+gboolean ws80211_has_fcs_filter(void);
+
+/** Set the FCS validation behavior for an interface.
+ *
+ * @param name The interface name.
+ * @param fcs_validation The desired validation behavior.
+ * @return Zero on success, nonzero on failure.
+ */
+int ws80211_set_fcs_validation(const char *name, enum ws80211_fcs_validation fcs_validation);
+
+
+/** Get the path to a helper application.
+ * Return the path to a separate 802.11 helper application, e.g.
+ * the AirPcap control panel or the GNOME Network Manager.
+ *
+ * @return The path to the helper on success, NULL on failure.
+ */
+const char *ws80211_get_helper_path(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __WS80211_UTILS_H__ */