X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/1cf1e6d8ddd27c768e35d7e646b31ec11f43cddf..09b51d326c38ea8e10ce4da09c09d50e08c5aeb8:/pcap-npf.c diff --git a/pcap-npf.c b/pcap-npf.c index 9a90455b..99b5981e 100644 --- a/pcap-npf.c +++ b/pcap-npf.c @@ -36,11 +36,23 @@ #endif #include +#include /* for INT_MAX */ #define PCAP_DONT_INCLUDE_PCAP_BPF_H #include #include #include +/* + * XXX - Packet32.h defines bpf_program, so we can't include + * , 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) @@ -55,6 +67,10 @@ #include #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 *); @@ -70,7 +86,7 @@ static int pcap_setnonblock_npf(pcap_t *, int); #define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) /* - * Private data for capturing on WinPcap devices. + * Private data for capturing on WinPcap/Npcap devices. */ struct pcap_win { ADAPTER *adapter; /* the packet32 ADAPTER for the device */ @@ -155,7 +171,7 @@ oid_get_request(ADAPTER *adapter, bpf_u_int32 oid, void *data, size_t *lenp, */ 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); } @@ -166,11 +182,8 @@ oid_get_request(ADAPTER *adapter, bpf_u_int32 oid, void *data, size_t *lenp, oid_data_arg->Oid = oid; oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ if (!PacketRequest(adapter, FALSE, oid_data_arg)) { - char errmsgbuf[PCAP_ERRBUF_SIZE+1]; - - pcap_win32_err_to_str(GetLastError(), errmsgbuf); - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "Error calling PacketRequest: %s", errmsgbuf); + pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error calling PacketRequest"); free(oid_data_arg); return (-1); } @@ -193,7 +206,6 @@ pcap_stats_npf(pcap_t *p, struct pcap_stat *ps) { struct pcap_win *pw = p->priv; struct bpf_stat bstats; - char errbuf[PCAP_ERRBUF_SIZE+1]; /* * Try to get statistics. @@ -209,9 +221,8 @@ pcap_stats_npf(pcap_t *p, struct pcap_stat *ps) * to us. */ if (!PacketGetStats(pw->adapter, &bstats)) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "PacketGetStats error: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetStats error"); return (-1); } ps->ps_recv = bstats.bs_recv; @@ -245,18 +256,17 @@ pcap_stats_npf(pcap_t *p, struct pcap_stat *ps) * 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; struct bpf_stat bstats; - char errbuf[PCAP_ERRBUF_SIZE+1]; *pcap_stat_size = sizeof (p->stat); @@ -268,15 +278,19 @@ pcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size) * same layout, but let's not cheat.) */ if (!PacketGetStatsEx(pw->adapter, &bstats)) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "PacketGetStatsEx error: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetStatsEx error"); return (NULL); } 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); @@ -290,7 +304,7 @@ pcap_setbuff_npf(pcap_t *p, int dim) 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); @@ -304,7 +318,7 @@ pcap_setmode_npf(pcap_t *p, int mode) 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); } @@ -319,7 +333,7 @@ pcap_setmintocopy_npf(pcap_t *p, int size) 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); @@ -347,7 +361,6 @@ pcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data, { struct pcap_win *pw = p->priv; PACKET_OID_DATA *oid_data_arg; - char errbuf[PCAP_ERRBUF_SIZE+1]; /* * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). @@ -358,7 +371,7 @@ pcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data, */ 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); } @@ -367,9 +380,8 @@ pcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data, oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ memcpy(oid_data_arg->Data, data, *lenp); if (!PacketRequest(pw->adapter, TRUE, oid_data_arg)) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error calling PacketRequest: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error calling PacketRequest"); free(oid_data_arg); return (PCAP_ERROR); } @@ -391,13 +403,6 @@ pcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync) { struct pcap_win *pw = p->priv; u_int res; - char errbuf[PCAP_ERRBUF_SIZE+1]; - - 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, @@ -405,9 +410,8 @@ pcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync) (BOOLEAN)sync); if(res != queue->len){ - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error opening adapter: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Error queueing packets"); } return (res); @@ -420,7 +424,7 @@ pcap_setuserbuffer_npf(pcap_t *p, int size) 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); } @@ -429,7 +433,7 @@ pcap_setuserbuffer_npf(pcap_t *p, int size) 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); } @@ -442,6 +446,31 @@ pcap_setuserbuffer_npf(pcap_t *p, int size) 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) { @@ -451,7 +480,7 @@ 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); } @@ -459,7 +488,7 @@ pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks) /* 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); } @@ -467,8 +496,8 @@ pcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks) /* 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); } @@ -482,31 +511,36 @@ pcap_live_dump_ended_npf(pcap_t *p, int sync) 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? */ @@ -534,7 +568,60 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) */ PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); + /* + * Did the device go away? + * If so, the error we get can either be + * ERROR_GEN_FAILURE or ERROR_DEVICE_REMOVED. + */ + DWORD errcode = GetLastError(); + + 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. + */ + 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, + "PacketReceivePacket error"); + } return (PCAP_ERROR); } @@ -547,11 +634,15 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) /* * 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? @@ -690,7 +781,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) */ 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); } @@ -705,6 +796,21 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 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 */ @@ -795,7 +901,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } } - /* 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) @@ -806,7 +912,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } } - /* 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; @@ -839,7 +945,8 @@ pcap_inject_npf(pcap_t *p, const void *buf, int size) 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); } @@ -877,13 +984,47 @@ pcap_breakloop_npf(pcap_t *p) 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) { struct pcap_win *pw = p->priv; NetType type; int res; - char errbuf[PCAP_ERRBUF_SIZE+1]; + int status = 0; + struct bpf_insn total_insn; + struct bpf_program total_prog; if (p->opt.rfmon) { /* @@ -915,40 +1056,69 @@ pcap_activate_npf(pcap_t *p) } } - /* 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_win32_err_to_str(GetLastError(), errbuf); - 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); } - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error opening adapter: %s", errbuf); - return (PCAP_ERROR); } /*get network type*/ if(PacketGetNetType (pw->adapter,&type) == FALSE) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Cannot determine the network type: %s", errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "Cannot determine the network type"); goto bad; } /*Set the linktype*/ switch (type.LinkType) { - case NdisMediumWan: - p->linktype = DLT_EN10MB; - break; - + /* + * NDIS-defined medium types. + */ case NdisMedium802_3: p->linktype = DLT_EN10MB; /* @@ -972,12 +1142,19 @@ pcap_activate_npf(pcap_t *p) } 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: @@ -992,18 +1169,29 @@ pcap_activate_npf(pcap_t *p) 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; @@ -1017,10 +1205,84 @@ pcap_activate_npf(pcap_t *p) break; default: - p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/ + /* + * An unknown medium type is assumed to supply Ethernet + * headers; if not, the user will have to report it, + * so that the medium type and link-layer header type + * can be determined. If we were to fail here, we + * might get the link-layer type in the error, but + * the user wouldn't get a capture, so we wouldn't + * be able to determine the link-layer type; we report + * a warning with the link-layer type, so at least + * some programs will report the warning. + */ + p->linktype = DLT_EN10MB; + 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 @@ -1038,17 +1300,66 @@ pcap_activate_npf(pcap_t *p) 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 | @@ -1056,8 +1367,19 @@ pcap_activate_npf(pcap_t *p) 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; + } } } @@ -1073,12 +1395,12 @@ pcap_activate_npf(pcap_t *p) * 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; } @@ -1095,10 +1417,9 @@ pcap_activate_npf(pcap_t *p) /* tell the driver to copy the buffer as soon as data arrives */ if(PacketSetMinToCopy(pw->adapter,0)==FALSE) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error calling PacketSetMinToCopy: %s", - errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, GetLastError(), + "Error calling PacketSetMinToCopy"); goto bad; } } @@ -1107,10 +1428,9 @@ pcap_activate_npf(pcap_t *p) /* tell the driver to copy the buffer only if it contains at least 16K */ if(PacketSetMinToCopy(pw->adapter,16000)==FALSE) { - pcap_win32_err_to_str(GetLastError(), errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "Error calling PacketSetMinToCopy: %s", - errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, + PCAP_ERRBUF_SIZE, GetLastError(), + "Error calling PacketSetMinToCopy"); goto bad; } } @@ -1129,7 +1449,7 @@ pcap_activate_npf(pcap_t *p) 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 @@ -1168,6 +1488,29 @@ pcap_activate_npf(pcap_t *p) #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 */ @@ -1175,7 +1518,7 @@ pcap_activate_npf(pcap_t *p) { 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; } @@ -1232,7 +1575,7 @@ pcap_activate_npf(pcap_t *p) */ p->handle = pw->adapter->hFile; - return (0); + return (status); bad: pcap_cleanup_npf(p); return (PCAP_ERROR); @@ -1247,17 +1590,295 @@ pcap_can_set_rfmon_npf(pcap_t *p) 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 " 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); } @@ -1320,7 +1941,7 @@ pcap_setfilter_npf(pcap_t *p, struct bpf_program *fp) } /* - * 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) { @@ -1356,7 +1977,6 @@ pcap_setnonblock_npf(pcap_t *p, int nonblock) { struct pcap_win *pw = p->priv; int newtimeout; - char win_errbuf[PCAP_ERRBUF_SIZE+1]; if (nonblock) { /* @@ -1376,9 +1996,8 @@ pcap_setnonblock_npf(pcap_t *p, int nonblock) newtimeout = p->opt.timeout; } if (!PacketSetReadTimeout(pw->adapter, newtimeout)) { - pcap_win32_err_to_str(GetLastError(), win_errbuf); - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "PacketSetReadTimeout: %s", win_errbuf); + pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketSetReadTimeout"); return (-1); } pw->nonblock = (newtimeout == -1); @@ -1466,8 +2085,8 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) #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 */ @@ -1520,7 +2139,7 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) *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); @@ -1562,6 +2181,12 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) * running. */ break; + + default: + /* + * Unknown. + */ + break; } } else { /* @@ -1598,7 +2223,13 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) 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: @@ -1615,10 +2246,11 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) default: /* - * Not wireless. + * Not wireless or unknown */ break; } +DIAG_ON_ENUM_SWITCH } #endif @@ -1649,6 +2281,13 @@ get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) */ *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; break; + + case MediaConnectStateUnknown: + default: + /* + * It's unknown whether it's connected or not. + */ + break; } } #else @@ -1695,7 +2334,6 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) char *AdaptersName; ULONG NameLength; char *name; - char our_errbuf[PCAP_ERRBUF_SIZE+1]; /* * Find out how big a buffer we need. @@ -1721,9 +2359,8 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) if (last_error != ERROR_INSUFFICIENT_BUFFER) { - pcap_win32_err_to_str(last_error, our_errbuf); - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "PacketGetAdapterNames: %s", our_errbuf); + pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + last_error, "PacketGetAdapterNames"); return (-1); } } @@ -1733,14 +2370,13 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 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); } if (!PacketGetAdapterNames(AdaptersName, &NameLength)) { - pcap_win32_err_to_str(GetLastError(), our_errbuf); - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "PacketGetAdapterNames: %s", - our_errbuf); + pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetAdapterNames"); free(AdaptersName); return (-1); } @@ -1762,7 +2398,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 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. @@ -1775,6 +2411,20 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 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? @@ -1829,12 +2479,27 @@ pcap_lookupdev(char *errbuf) { DWORD dwVersion; DWORD dwWindowsMajorVersion; - char our_errbuf[PCAP_ERRBUF_SIZE+1]; -#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) { @@ -1865,15 +2530,14 @@ pcap_lookupdev(char *errbuf) if(TAdaptersName == NULL) { - (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); + (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); return NULL; } if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) { - pcap_win32_err_to_str(GetLastError(), our_errbuf); - (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, - "PacketGetAdapterNames: %s", our_errbuf); + pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, + GetLastError(), "PacketGetAdapterNames"); free(TAdaptersName); return NULL; } @@ -2011,9 +2675,9 @@ static const char *pcap_lib_version_string; * tree. Include version.h from that source tree to get the WinPcap/Npcap * version. * - * XXX - it'd be nice if we could somehow generate the WinPcap version number - * when building WinPcap. (It'd be nice to do so for the packet.dll version - * number as well.) + * XXX - it'd be nice if we could somehow generate the WinPcap/Npcap version + * number when building as part of WinPcap/Npcap. (It'd be nice to do so + * for the packet.dll version number as well.) */ #include "../../version.h" @@ -2027,21 +2691,21 @@ pcap_lib_version(void) /* * Generate the version string. */ - char *packet_version_string = PacketGetVersion(); + const char *packet_version_string = PacketGetVersion(); if (strcmp(WINPCAP_VER_STRING, packet_version_string) == 0) { /* - * WinPcap version string and packet.dll version - * string are the same; just report the WinPcap + * WinPcap/Npcap version string and packet.dll version + * string are the same; just report the WinPcap/Npcap * version. */ pcap_lib_version_string = pcap_version_string; } else { /* - * WinPcap version string and packet.dll version + * WinPcap/Npcap version string and packet.dll version * string are different; that shouldn't be the * case (the two libraries should come from the - * same version of WinPcap), so we report both + * same version of WinPcap/Npcap), so we report both * versions. */ char *full_pcap_version_string;