#endif
#include <errno.h>
+#include <limits.h> /* for INT_MAX */
#define PCAP_DONT_INCLUDE_PCAP_BPF_H
#include <Packet32.h>
#include <pcap-int.h>
#include <pcap/dlt.h>
+/*
+ * XXX - Packet32.h defines bpf_program, so we can't include
+ * <pcap/bpf.h>, which also defines it; that's why we define
+ * PCAP_DONT_INCLUDE_PCAP_BPF_H,
+ *
+ * However, no header in the WinPcap or Npcap SDKs defines the
+ * macros for BPF code, so we have to define them ourselves.
+ */
+#define BPF_RET 0x06
+#define BPF_K 0x00
+
/* Old-school MinGW have these headers in a different place.
*/
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
#include <dagapi.h>
#endif /* HAVE_DAG_API */
+#include "diag-control.h"
+
+#include "pcap-airpcap.h"
+
static int pcap_setfilter_npf(pcap_t *, struct bpf_program *);
static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *);
static int pcap_getnonblock_npf(pcap_t *);
*/
oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp);
if (oid_data_arg == NULL) {
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
"Couldn't allocate argument buffer for PacketRequest");
return (PCAP_ERROR);
}
* have an API that returns data in a form like the Options section of a
* pcapng Interface Statistics Block:
*
- * http://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
+ * https://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi?url=https://raw.githubusercontent.com/pcapng/pcapng/master/draft-tuexen-opsawg-pcapng.xml&modeAsFormat=html/ascii&type=ascii#rfc.section.4.6
*
* which would let us add new statistics straightforwardly and indicate which
* statistics we are and are *not* providing, rather than having to provide
* possibly-bogus values for statistics we can't provide.
*/
-struct pcap_stat *
+static struct pcap_stat *
pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size)
{
struct pcap_win *pw = p->priv;
p->stat.ps_recv = bstats.bs_recv;
p->stat.ps_drop = bstats.bs_drop;
p->stat.ps_ifdrop = bstats.ps_ifdrop;
-#ifdef ENABLE_REMOTE
+ /*
+ * Just in case this is ever compiled for a target other than
+ * Windows, which is somewhere between extremely unlikely and
+ * impossible.
+ */
+#ifdef _WIN32
p->stat.ps_capt = bstats.bs_capt;
#endif
return (&p->stat);
if(PacketSetBuff(pw->adapter,dim)==FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
return (-1);
}
return (0);
if(PacketSetMode(pw->adapter,mode)==FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
return (-1);
}
if(PacketSetMinToCopy(pw->adapter, size)==FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
return (-1);
}
return (0);
*/
oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp);
if (oid_data_arg == NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Couldn't allocate argument buffer for PacketRequest");
return (PCAP_ERROR);
}
struct pcap_win *pw = p->priv;
u_int res;
- if (pw->adapter==NULL) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Cannot transmit a queue to an offline capture or to a TurboCap port");
- return (0);
- }
-
res = PacketSendPackets(pw->adapter,
queue->buffer,
queue->len,
if(res != queue->len){
pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
- GetLastError(), "Error opening adapter");
+ GetLastError(), "Error queueing packets");
}
return (res);
if (size<=0) {
/* Bogus parameter */
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error: invalid size %d",size);
return (-1);
}
new_buff=(unsigned char*)malloc(sizeof(char)*size);
if (!new_buff) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error: not enough memory");
return (-1);
}
return (0);
}
+#ifdef HAVE_NPCAP_PACKET_API
+/*
+ * Kernel dump mode isn't supported in Npcap; calls to PacketSetDumpName(),
+ * PacketSetDumpLimits(), and PacketIsDumpEnded() will get compile-time
+ * deprecation warnings.
+ *
+ * Avoid calling them; just return errors indicating that kernel dump
+ * mode isn't supported in Npcap.
+ */
+static int
+pcap_live_dump_npf(pcap_t *p, char *filename _U_, int maxsize _U_,
+ int maxpacks _U_)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Npcap doesn't support kernel dump mode");
+ return (-1);
+}
+static int
+pcap_live_dump_ended_npf(pcap_t *p, int sync)
+{
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Npcap doesn't support kernel dump mode");
+ return (-1);
+}
+#else /* HAVE_NPCAP_PACKET_API */
static int
pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks)
{
/* Set the packet driver in dump mode */
res = PacketSetMode(pw->adapter, PACKET_MODE_DUMP);
if(res == FALSE){
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error setting dump mode");
return (-1);
}
/* Set the name of the dump file */
res = PacketSetDumpName(pw->adapter, filename, (int)strlen(filename));
if(res == FALSE){
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Error setting kernel dump file name");
return (-1);
}
/* Set the limits of the dump file */
res = PacketSetDumpLimits(pw->adapter, maxsize, maxpacks);
if(res == FALSE) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "Error setting dump limit");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Error setting dump limit");
return (-1);
}
return (PacketIsDumpEnded(pw->adapter, (BOOLEAN)sync));
}
+#endif /* HAVE_NPCAP_PACKET_API */
+#ifdef HAVE_AIRPCAP_API
static PAirpcapHandle
pcap_get_airpcap_handle_npf(pcap_t *p)
{
-#ifdef HAVE_AIRPCAP_API
struct pcap_win *pw = p->priv;
return (PacketGetAirPcapHandle(pw->adapter));
-#else
+}
+#else /* HAVE_AIRPCAP_API */
+static PAirpcapHandle
+pcap_get_airpcap_handle_npf(pcap_t *p _U_)
+{
return (NULL);
-#endif /* HAVE_AIRPCAP_API */
}
+#endif /* HAVE_AIRPCAP_API */
static int
pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
PACKET Packet;
int cc;
- int n = 0;
+ int n;
register u_char *bp, *ep;
u_char *datap;
struct pcap_win *pw = p->priv;
cc = p->cc;
- if (p->cc == 0) {
+ if (cc == 0) {
/*
* Has "pcap_breakloop()" been called?
*/
if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) {
/*
* Did the device go away?
- * If so, the error we get is ERROR_GEN_FAILURE.
+ * If so, the error we get can either be
+ * ERROR_GEN_FAILURE or ERROR_DEVICE_REMOVED.
*/
DWORD errcode = GetLastError();
- if (errcode == ERROR_GEN_FAILURE) {
+ if (errcode == ERROR_GEN_FAILURE ||
+ errcode == ERROR_DEVICE_REMOVED) {
/*
* The device on which we're capturing
* went away, or it became unusable
* by NPF due to a suspend/resume.
*
+ * ERROR_GEN_FAILURE comes from
+ * STATUS_UNSUCCESSFUL, as well as some
+ * other NT status codes that the Npcap
+ * driver is unlikely to return.
* XXX - hopefully no other error
* conditions are indicated by this.
*
+ * ERROR_DEVICE_REMOVED comes from
+ * STATUS_DEVICE_REMOVED.
+ *
+ * We report the Windows status code
+ * name and the corresponding NT status
+ * code name, for the benefit of attempts
+ * to debug cases where this error is
+ * reported when the device *wasn't*
+ * removed, either because it's not
+ * removable, it's removable but wasn't
+ * removed, or it's a device that doesn't
+ * correspond to a physical device.
+ *
* XXX - we really should return an
* appropriate error for that, but
* pcap_dispatch() etc. aren't
* documented as having error returns
* other than PCAP_ERROR or PCAP_ERROR_BREAK.
*/
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
- "The interface disappeared");
+ const char *errcode_msg;
+
+ if (errcode == ERROR_GEN_FAILURE)
+ errcode_msg = "ERROR_GEN_FAILURE/STATUS_UNSUCCESSFUL";
+ else
+ errcode_msg = "ERROR_DEVICE_REMOVED/STATUS_DEVICE_REMOVED";
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The interface disappeared (error code %s)",
+ errcode_msg);
} else {
pcap_fmt_errmsg_for_win32_err(p->errbuf,
PCAP_ERRBUF_SIZE, errcode,
/*
* Loop through each packet.
+ *
+ * This assumes that a single buffer of packets will have
+ * <= INT_MAX packets, so the packet count doesn't overflow.
*/
#define bhp ((struct bpf_hdr *)bp)
+ n = 0;
ep = bp + cc;
for (;;) {
- register int caplen, hdrlen;
+ register u_int caplen, hdrlen;
/*
* Has "pcap_breakloop()" been called?
*/
PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize);
if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
return (-1);
}
endofbuf = (char*)header + cc;
+ /*
+ * This can conceivably process more than INT_MAX packets,
+ * which would overflow the packet count, causing it either
+ * to look like a negative number, and thus cause us to
+ * return a value that looks like an error, or overflow
+ * back into positive territory, and thus cause us to
+ * return a too-low count.
+ *
+ * Therefore, if the packet count is unlimited, we clip
+ * it at INT_MAX; this routine is not expected to
+ * process packets indefinitely, so that's not an issue.
+ */
+ if (PACKET_COUNT_IS_UNLIMITED(cnt))
+ cnt = INT_MAX;
+
/*
* Cycle through the packets
*/
}
}
- /* No underlaying filtering system. We need to filter on our own */
+ /* No underlying filtering system. We need to filter on our own */
if (p->fcode.bf_insns)
{
if (pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0)
}
}
- /* Fill the header for the user suppplied callback function */
+ /* Fill the header for the user supplied callback function */
pcap_header.caplen = caplen;
pcap_header.len = packet_len;
PacketInitPacket(&pkt, (PVOID)buf, size);
if(PacketSendPacket(pw->adapter,&pkt,TRUE) == FALSE) {
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed");
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "send error: PacketSendPacket failed");
return (-1);
}
SetEvent(PacketGetReadEvent(pw->adapter));
}
+/*
+ * These are NTSTATUS values:
+ *
+ * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/87fba13e-bf06-450e-83b1-9241dc81e781
+ *
+ * with the "Customer" bit set. If a driver returns them, they are not
+ * mapped to Windows error values in userland; they're returned by
+ * GetLastError().
+ *
+ * Note that "driver" here includes the Npcap NPF driver, as various
+ * versions would take NT status values and set the "Customer" bit
+ * before returning the status code. The commit message for the
+ * change that started doing that is
+ *
+ * Returned a customer-defined NTSTATUS in OID requests to avoid
+ * NTSTATUS-to-Win32 Error code translation.
+ *
+ * but I don't know why the goal was to avoid that translation.
+ *
+ * Attempting to set the hardware filter on a Microsoft Surface Pro's
+ * Mobile Broadband Adapter returns an error that appears to be
+ * NDIS_STATUS_NOT_SUPPORTED ORed with the "Customer" bit, so it's
+ * probably indicating that it doesn't support that.
+ *
+ * It is likely that there are other devices which throw spurious errors,
+ * at which point this will need refactoring to efficiently check against
+ * a list, but for now we can just check this one value. Perhaps the
+ * right way to do this is compare against various NDIS errors with
+ * the "customer" bit ORed in.
+ */
+#define NT_STATUS_CUSTOMER_DEFINED 0x20000000
+
static int
pcap_activate_npf(pcap_t *p)
{
NetType type;
int res;
int status = 0;
+ struct bpf_insn total_insn;
+ struct bpf_program total_prog;
if (p->opt.rfmon) {
/*
}
}
- /* Init WinSock */
+ /* Init Winsock if it hasn't already been initialized */
pcap_wsockinit();
pw->adapter = PacketOpenAdapter(p->opt.device);
if (pw->adapter == NULL)
{
- /* Adapter detected but we are not able to open it. Return failure. */
- pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
- GetLastError(), "Error opening adapter");
- if (pw->rfmon_selfstart)
- {
- PacketSetMonitorMode(p->opt.device, 0);
+ DWORD errcode = GetLastError();
+
+ /*
+ * What error did we get when trying to open the adapter?
+ */
+ switch (errcode) {
+
+ case ERROR_BAD_UNIT:
+ /*
+ * There's no such device.
+ * There's nothing to add, so clear the error
+ * message.
+ */
+ p->errbuf[0] = '\0';
+ return (PCAP_ERROR_NO_SUCH_DEVICE);
+
+ case ERROR_ACCESS_DENIED:
+ /*
+ * There is, but we don't have permission to
+ * use it.
+ *
+ * XXX - we currently get ERROR_BAD_UNIT if the
+ * user says "no" to the UAC prompt.
+ */
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "The helper program for \"Admin-only Mode\" must be allowed to make changes to your device");
+ return (PCAP_ERROR_PERM_DENIED);
+
+ default:
+ /*
+ * Unknown - report details.
+ */
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ errcode, "Error opening adapter");
+ if (pw->rfmon_selfstart)
+ {
+ PacketSetMonitorMode(p->opt.device, 0);
+ }
+ return (PCAP_ERROR);
}
- return (PCAP_ERROR);
}
/*get network type*/
/*Set the linktype*/
switch (type.LinkType)
{
- case NdisMediumWan:
- p->linktype = DLT_EN10MB;
- break;
-
+ /*
+ * NDIS-defined medium types.
+ */
case NdisMedium802_3:
p->linktype = DLT_EN10MB;
/*
}
break;
+ case NdisMedium802_5:
+ /*
+ * Token Ring.
+ */
+ p->linktype = DLT_IEEE802;
+ break;
+
case NdisMediumFddi:
p->linktype = DLT_FDDI;
break;
- case NdisMedium802_5:
- p->linktype = DLT_IEEE802;
+ case NdisMediumWan:
+ p->linktype = DLT_EN10MB;
break;
case NdisMediumArcnetRaw:
p->linktype = DLT_ATM_RFC1483;
break;
- case NdisMediumCHDLC:
- p->linktype = DLT_CHDLC;
+ case NdisMediumWirelessWan:
+ p->linktype = DLT_RAW;
break;
- case NdisMediumPPPSerial:
- p->linktype = DLT_PPP_SERIAL;
+ case NdisMediumIP:
+ p->linktype = DLT_RAW;
break;
+ /*
+ * Npcap-defined medium types.
+ */
case NdisMediumNull:
p->linktype = DLT_NULL;
break;
+ case NdisMediumCHDLC:
+ p->linktype = DLT_CHDLC;
+ break;
+
+ case NdisMediumPPPSerial:
+ p->linktype = DLT_PPP_SERIAL;
+ break;
+
case NdisMediumBare80211:
p->linktype = DLT_IEEE802_11;
break;
p->linktype = DLT_PPI;
break;
-#ifdef NdisMediumWirelessWan
- case NdisMediumWirelessWan:
- p->linktype = DLT_RAW;
- break;
-#endif
-
default:
/*
* An unknown medium type is assumed to supply Ethernet
* some programs will report the warning.
*/
p->linktype = DLT_EN10MB;
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Unknown NdisMedium value %d, defaulting to DLT_EN10MB",
type.LinkType);
status = PCAP_WARNING;
break;
}
+#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
+ /*
+ * Set the timestamp type.
+ * (Yes, we require PacketGetTimestampModes(), not just
+ * PacketSetTimestampMode(). If we have the former, we
+ * have the latter, unless somebody's using a version
+ * of Npcap that they've hacked to provide the former
+ * but not the latter; if they've done that, either
+ * they're confused or they're trolling us.)
+ */
+ switch (p->opt.tstamp_type) {
+
+ case PCAP_TSTAMP_HOST_HIPREC_UNSYNCED:
+ /*
+ * Better than low-res, but *not* synchronized with
+ * the OS clock.
+ */
+ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_SINGLE_SYNCHRONIZATION))
+ {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_SINGLE_SYNCHRONIZATION");
+ goto bad;
+ }
+ break;
+
+ case PCAP_TSTAMP_HOST_LOWPREC:
+ /*
+ * Low-res, but synchronized with the OS clock.
+ */
+ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME))
+ {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME");
+ goto bad;
+ }
+ break;
+
+ case PCAP_TSTAMP_HOST_HIPREC:
+ /*
+ * High-res, and synchronized with the OS clock.
+ */
+ if (!PacketSetTimestampMode(pw->adapter, TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE))
+ {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "Cannot set the time stamp mode to TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE");
+ goto bad;
+ }
+ break;
+
+ case PCAP_TSTAMP_HOST:
+ /*
+ * XXX - do whatever the default is, for now.
+ * Set to the highest resolution that's synchronized
+ * with the system clock?
+ */
+ break;
+ }
+#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+
/*
* Turn a negative snapshot value (invalid), a snapshot value of
* 0 (unspecified), or a value bigger than the normal maximum
if (PacketSetHwFilter(pw->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode");
- goto bad;
+ DWORD errcode = GetLastError();
+
+ /*
+ * Suppress spurious error generated by non-compiant
+ * MS Surface mobile adapters that appear to
+ * return NDIS_STATUS_NOT_SUPPORTED for attempts
+ * to set the hardware filter.
+ *
+ * It appears to be reporting NDIS_STATUS_NOT_SUPPORTED,
+ * but with the NT status value "Customer" bit set;
+ * the Npcap NPF driver sets that bit in some cases.
+ *
+ * If we knew that this meant "promiscuous mode
+ * isn't supported", we could add a "promiscuous
+ * mode isn't supported" error code and return
+ * that, but:
+ *
+ * 1) we don't know that it means that
+ * rather than meaning "we reject attempts
+ * to set the filter, even though the NDIS
+ * specifications say you shouldn't do that"
+ *
+ * and
+ *
+ * 2) other interface types that don't
+ * support promiscuous mode, at least
+ * on UN*Xes, just silently ignore
+ * attempts to set promiscuous mode
+ *
+ * and rejecting it with an error could disrupt
+ * attempts to capture, as many programs (tcpdump,
+ * *shark) default to promiscuous mode.
+ *
+ * Alternatively, we could return the "promiscuous
+ * mode not supported" *warning* value, so that
+ * correct code will either ignore it or report
+ * it and continue capturing. (This may require
+ * a pcap_init() flag to request that return
+ * value, so that old incorrect programs that
+ * assume a non-zero return from pcap_activate()
+ * is an error don't break.)
+ */
+ if (errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED))
+ {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf,
+ PCAP_ERRBUF_SIZE, errcode,
+ "failed to set hardware filter to promiscuous mode");
+ goto bad;
+ }
}
}
else
{
- /* NDIS_PACKET_TYPE_ALL_LOCAL selects "All packets sent by installed
- * protocols and all packets indicated by the NIC" but if no protocol
- * drivers (like TCP/IP) are installed, NDIS_PACKET_TYPE_DIRECTED,
- * NDIS_PACKET_TYPE_BROADCAST, and NDIS_PACKET_TYPE_MULTICAST are needed to
- * capture incoming frames.
+ /*
+ * NDIS_PACKET_TYPE_ALL_LOCAL selects "All packets sent by
+ * installed protocols and all packets indicated by the NIC",
+ * but if no protocol drivers (like TCP/IP) are installed,
+ * NDIS_PACKET_TYPE_DIRECTED, NDIS_PACKET_TYPE_BROADCAST,
+ * and NDIS_PACKET_TYPE_MULTICAST are needed to capture
+ * incoming frames.
*/
if (PacketSetHwFilter(pw->adapter,
NDIS_PACKET_TYPE_ALL_LOCAL |
NDIS_PACKET_TYPE_BROADCAST |
NDIS_PACKET_TYPE_MULTICAST) == FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode");
- goto bad;
+ DWORD errcode = GetLastError();
+
+ /*
+ * Suppress spurious error generated by non-compiant
+ * MS Surface mobile adapters.
+ */
+ if (errcode != (NDIS_STATUS_NOT_SUPPORTED|NT_STATUS_CUSTOMER_DEFINED))
+ {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf,
+ PCAP_ERRBUF_SIZE, errcode,
+ "failed to set hardware filter to non-promiscuous mode");
+ goto bad;
+ }
}
}
* If the buffer size wasn't explicitly set, default to
* WIN32_DEFAULT_KERNEL_BUFFER_SIZE.
*/
- if (p->opt.buffer_size == 0)
- p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE;
+ if (p->opt.buffer_size == 0)
+ p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE;
if(PacketSetBuff(pw->adapter,p->opt.buffer_size)==FALSE)
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
goto bad;
}
int postype = 0;
char keyname[512];
- pcap_snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s",
+ snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s",
"SYSTEM\\CurrentControlSet\\Services\\DAG",
strstr(_strlwr(p->opt.device), "dag"));
do
#endif /* HAVE_DAG_API */
}
+ /*
+ * If there's no filter program installed, there's
+ * no indication to the kernel of what the snapshot
+ * length should be, so no snapshotting is done.
+ *
+ * Therefore, when we open the device, we install
+ * an "accept everything" filter with the specified
+ * snapshot length.
+ */
+ total_insn.code = (u_short)(BPF_RET | BPF_K);
+ total_insn.jt = 0;
+ total_insn.jf = 0;
+ total_insn.k = p->snapshot;
+
+ total_prog.bf_len = 1;
+ total_prog.bf_insns = &total_insn;
+ if (!PacketSetBpf(pw->adapter, &total_prog)) {
+ pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE,
+ GetLastError(), "PacketSetBpf");
+ status = PCAP_ERROR;
+ goto bad;
+ }
+
PacketSetReadTimeout(pw->adapter, p->opt.timeout);
/* disable loopback capture if requested */
{
if (!PacketSetLoopbackBehavior(pw->adapter, NPF_DISABLE_LOOPBACK))
{
- pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Unable to disable the capture of loopback packets.");
goto bad;
}
return (PacketIsMonitorModeSupported(p->opt.device) == 1);
}
+/*
+ * Get a list of time stamp types.
+ */
+#ifdef HAVE_PACKET_GET_TIMESTAMP_MODES
+static int
+get_ts_types(const char *device, pcap_t *p, char *ebuf)
+{
+ char *device_copy = NULL;
+ ADAPTER *adapter = NULL;
+ ULONG num_ts_modes;
+ BOOL ret;
+ DWORD error = ERROR_SUCCESS;
+ ULONG *modes = NULL;
+ int status = 0;
+
+ do {
+ /*
+ * First, find out how many time stamp modes we have.
+ * To do that, we have to open the adapter.
+ *
+ * XXX - PacketOpenAdapter() takes a non-const pointer
+ * as an argument, so we make a copy of the argument and
+ * pass that to it.
+ */
+ device_copy = strdup(device);
+ if (device_copy == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc");
+ status = -1;
+ break;
+ }
+
+ adapter = PacketOpenAdapter(device_copy);
+ if (adapter == NULL)
+ {
+ error = GetLastError();
+ /*
+ * If we can't open the device now, we won't be
+ * able to later, either.
+ *
+ * If the error is something that indicates
+ * that the device doesn't exist, or that they
+ * don't have permission to open the device - or
+ * perhaps that they don't have permission to get
+ * a list of devices, if PacketOpenAdapter() does
+ * that - the user will find that out when they try
+ * to activate the device; just return an empty
+ * list of time stamp types.
+ *
+ * Treating either of those as errors will, for
+ * example, cause "tcpdump -i <number>" to fail,
+ * because it first tries to pass the interface
+ * name to pcap_create() and pcap_activate(),
+ * in order to handle OSes where interfaces can
+ * have names that are just numbers (stand up
+ * and say hello, Linux!), and, if pcap_activate()
+ * fails with a "no such device" error, checks
+ * whether the interface name is a valid number
+ * and, if so, tries to use it as an index in
+ * the list of interfaces.
+ *
+ * That means pcap_create() must succeed even
+ * for interfaces that don't exist, with the
+ * failure occurring at pcap_activate() time.
+ */
+ if (error == ERROR_BAD_UNIT ||
+ error == ERROR_ACCESS_DENIED) {
+ p->tstamp_type_count = 0;
+ p->tstamp_type_list = NULL;
+ status = 0;
+ } else {
+ pcap_fmt_errmsg_for_win32_err(ebuf,
+ PCAP_ERRBUF_SIZE, error,
+ "Error opening adapter");
+ status = -1;
+ }
+ break;
+ }
+
+ /*
+ * Get the total number of time stamp modes.
+ *
+ * The buffer for PacketGetTimestampModes() is
+ * a sequence of 1 or more ULONGs. What's
+ * passed to PacketGetTimestampModes() should have
+ * the total number of ULONGs in the first ULONG;
+ * what's returned *from* PacketGetTimestampModes()
+ * has the total number of time stamp modes in
+ * the first ULONG.
+ *
+ * Yes, that means if there are N time stamp
+ * modes, the first ULONG should be set to N+1
+ * on input, and will be set to N on output.
+ *
+ * We first make a call to PacketGetTimestampModes()
+ * with a pointer to a single ULONG set to 1; the
+ * call should fail with ERROR_MORE_DATA (unless
+ * there are *no* modes, but that should never
+ * happen), and that ULONG should be set to the
+ * number of modes.
+ */
+ num_ts_modes = 1;
+ ret = PacketGetTimestampModes(adapter, &num_ts_modes);
+ if (!ret) {
+ /*
+ * OK, it failed. Did it fail with
+ * ERROR_MORE_DATA?
+ */
+ error = GetLastError();
+ if (error != ERROR_MORE_DATA) {
+ /*
+ * No, did it fail with ERROR_INVALID_FUNCTION?
+ */
+ if (error == ERROR_INVALID_FUNCTION) {
+ /*
+ * This is probably due to
+ * the driver with which Packet.dll
+ * communicates being older, or
+ * being a WinPcap driver, so
+ * that it doesn't support
+ * BIOCGTIMESTAMPMODES.
+ *
+ * Tell the user to try uninstalling
+ * Npcap - and WinPcap if installed -
+ * and re-installing it, to flush
+ * out all older drivers.
+ */
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "PacketGetTimestampModes() failed with ERROR_INVALID_FUNCTION; try uninstalling Npcap, and WinPcap if installed, and re-installing it from npcap.com");
+ status = -1;
+ break;
+ }
+
+ /*
+ * No, some other error. Fail.
+ */
+ pcap_fmt_errmsg_for_win32_err(ebuf,
+ PCAP_ERRBUF_SIZE, error,
+ "Error calling PacketGetTimestampModes");
+ status = -1;
+ break;
+ }
+ }
+ /* else (ret == TRUE)
+ * Unexpected success. Let's act like we got ERROR_MORE_DATA.
+ * If it doesn't work, we'll hit some other error condition farther on.
+ */
+
+ /* If the driver reports no modes supported *and*
+ * ERROR_MORE_DATA, something is seriously wrong.
+ * We *could* ignore the error and continue without supporting
+ * settable timestamp modes, but that would hide a bug.
+ */
+ if (num_ts_modes == 0) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "PacketGetTimestampModes() reports 0 modes supported.");
+ status = -1;
+ break;
+ }
+
+ /*
+ * Yes, so we now know how many types to fetch.
+ *
+ * The buffer needs to have one ULONG for the
+ * count and num_ts_modes ULONGs for the
+ * num_ts_modes time stamp types.
+ */
+ modes = (ULONG *)malloc((1 + num_ts_modes) * sizeof(ULONG));
+ if (modes == NULL) {
+ /* Out of memory. */
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc");
+ status = -1;
+ break;
+ }
+ modes[0] = 1 + num_ts_modes;
+ if (!PacketGetTimestampModes(adapter, modes)) {
+ pcap_fmt_errmsg_for_win32_err(ebuf,
+ PCAP_ERRBUF_SIZE, GetLastError(),
+ "Error calling PacketGetTimestampModes");
+ status = -1;
+ break;
+ }
+ if (modes[0] != num_ts_modes) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "First PacketGetTimestampModes() call gives %lu modes, second call gives %lu modes",
+ num_ts_modes, modes[0]);
+ status = -1;
+ break;
+ }
+
+ /*
+ * Allocate a buffer big enough for
+ * PCAP_TSTAMP_HOST (default) plus
+ * the explicitly specified modes.
+ */
+ p->tstamp_type_list = malloc((1 + num_ts_modes) * sizeof(u_int));
+ if (p->tstamp_type_list == NULL) {
+ pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, errno, "malloc");
+ status = -1;
+ break;
+ }
+ u_int num_ts_types = 0;
+ p->tstamp_type_list[num_ts_types] =
+ PCAP_TSTAMP_HOST;
+ num_ts_types++;
+ for (ULONG i = 0; i < num_ts_modes; i++) {
+ switch (modes[i + 1]) {
+
+ case TIMESTAMPMODE_SINGLE_SYNCHRONIZATION:
+ /*
+ * Better than low-res,
+ * but *not* synchronized
+ * with the OS clock.
+ */
+ p->tstamp_type_list[num_ts_types] =
+ PCAP_TSTAMP_HOST_HIPREC_UNSYNCED;
+ num_ts_types++;
+ break;
+
+ case TIMESTAMPMODE_QUERYSYSTEMTIME:
+ /*
+ * Low-res, but synchronized
+ * with the OS clock.
+ */
+ p->tstamp_type_list[num_ts_types] =
+ PCAP_TSTAMP_HOST_LOWPREC;
+ num_ts_types++;
+ break;
+
+ case TIMESTAMPMODE_QUERYSYSTEMTIME_PRECISE:
+ /*
+ * High-res, and synchronized
+ * with the OS clock.
+ */
+ p->tstamp_type_list[num_ts_types] =
+ PCAP_TSTAMP_HOST_HIPREC;
+ num_ts_types++;
+ break;
+
+ default:
+ /*
+ * Unknown, so we can't
+ * report it.
+ */
+ break;
+ }
+ }
+ p->tstamp_type_count = num_ts_types;
+ } while (0);
+
+ /* Clean up temporary allocations */
+ if (device_copy != NULL) {
+ free(device_copy);
+ }
+ if (modes != NULL) {
+ free(modes);
+ }
+ if (adapter != NULL) {
+ PacketCloseAdapter(adapter);
+ }
+
+ return status;
+}
+#else /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+static int
+get_ts_types(const char *device _U_, pcap_t *p _U_, char *ebuf _U_)
+{
+ /*
+ * Nothing to fetch, so it always "succeeds".
+ */
+ return 0;
+}
+#endif /* HAVE_PACKET_GET_TIMESTAMP_MODES */
+
pcap_t *
pcap_create_interface(const char *device _U_, char *ebuf)
{
pcap_t *p;
- p = pcap_create_common(ebuf, sizeof(struct pcap_win));
+ p = PCAP_CREATE_COMMON(ebuf, struct pcap_win);
if (p == NULL)
return (NULL);
p->activate_op = pcap_activate_npf;
p->can_set_rfmon_op = pcap_can_set_rfmon_npf;
+
+ if (get_ts_types(device, p, ebuf) == -1) {
+ pcap_close(p);
+ return (NULL);
+ }
return (p);
}
}
/*
- * We filter at user level, since the kernel driver does't process the packets
+ * We filter at user level, since the kernel driver doesn't process the packets
*/
static int
pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) {
#ifdef OID_GEN_PHYSICAL_MEDIUM_EX
OID_GEN_PHYSICAL_MEDIUM_EX,
#endif
- OID_GEN_PHYSICAL_MEDIUM
- };
+ OID_GEN_PHYSICAL_MEDIUM
+ };
#define N_GEN_PHYSICAL_MEDIUM_OIDS (sizeof gen_physical_medium_oids / sizeof gen_physical_medium_oids[0])
size_t i;
#endif /* OID_GEN_PHYSICAL_MEDIUM */
*flags |= PCAP_IF_WIRELESS;
/*
- * A "network assosiation state" makes no sense for airpcap.
+ * A "network association state" makes no sense for airpcap.
*/
*flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
PacketCloseAdapter(adapter);
* running.
*/
break;
+
+ default:
+ /*
+ * Unknown.
+ */
+ break;
}
} else {
/*
if (status == 0) {
/*
* We got the physical medium.
+ *
+ * XXX - we might want to check for NdisPhysicalMediumWiMax
+ * and NdisPhysicalMediumNative802_15_4 being
+ * part of the enum, and check for those in the "wireless"
+ * case.
*/
+DIAG_OFF_ENUM_SWITCH
switch (phys_medium) {
case NdisPhysicalMediumWirelessLan:
default:
/*
- * Not wireless.
+ * Not wireless or unknown
*/
break;
}
+DIAG_ON_ENUM_SWITCH
}
#endif
*/
*flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
break;
+
+ case MediaConnectStateUnknown:
+ default:
+ /*
+ * It's unknown whether it's connected or not.
+ */
+ break;
}
}
#else
AdaptersName = (char*) malloc(NameLength);
if (AdaptersName == NULL)
{
- pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters.");
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters.");
return (-1);
}
desc++;
/*
- * Found it - "desc" points to the first of the two
+ * Found it - "desc" points to the first of the two
* nulls at the end of the list of names, so the
* first byte of the list of descriptions is two bytes
* after it.
name = &AdaptersName[0];
while (*name != '\0') {
bpf_u_int32 flags = 0;
+
+#ifdef HAVE_AIRPCAP_API
+ /*
+ * Is this an AirPcap device?
+ * If so, ignore it; it'll get added later, by the
+ * AirPcap code.
+ */
+ if (device_is_airpcap(name, errbuf) == 1) {
+ name += strlen(name) + 1;
+ desc += strlen(desc) + 1;
+ continue;
+ }
+#endif
+
#ifdef HAVE_PACKET_IS_LOOPBACK_ADAPTER
/*
* Is this a loopback interface?
DWORD dwVersion;
DWORD dwWindowsMajorVersion;
-#pragma warning (push)
-#pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */
+ /*
+ * We disable this in "new API" mode, because 1) in WinPcap/Npcap,
+ * it may return UTF-16 strings, for backwards-compatibility
+ * reasons, and we're also disabling the hack to make that work,
+ * for not-going-past-the-end-of-a-string reasons, and 2) we
+ * want its behavior to be consistent.
+ *
+ * In addition, it's not thread-safe, so we've marked it as
+ * deprecated.
+ */
+ if (pcap_new_api) {
+ snprintf(errbuf, PCAP_ERRBUF_SIZE,
+ "pcap_lookupdev() is deprecated and is not supported in programs calling pcap_init()");
+ return (NULL);
+ }
+
+/* disable MSVC's GetVersion() deprecated warning here */
+DIAG_OFF_DEPRECATION
dwVersion = GetVersion(); /* get the OS version */
-#pragma warning (pop)
+DIAG_ON_DEPRECATION
dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) {
if(TAdaptersName == NULL)
{
- (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
+ (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure");
return NULL;
}
/*
* Generate the version string.
*/
- char *packet_version_string = PacketGetVersion();
+ const char *packet_version_string = PacketGetVersion();
if (strcmp(WINPCAP_VER_STRING, packet_version_string) == 0) {
/*