1335640Shselasky/* 2335640Shselasky * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) 3335640Shselasky * Copyright (c) 2005 - 2010 CACE Technologies, Davis (California) 4335640Shselasky * All rights reserved. 5335640Shselasky * 6335640Shselasky * Redistribution and use in source and binary forms, with or without 7335640Shselasky * modification, are permitted provided that the following conditions 8335640Shselasky * are met: 9335640Shselasky * 10335640Shselasky * 1. Redistributions of source code must retain the above copyright 11335640Shselasky * notice, this list of conditions and the following disclaimer. 12335640Shselasky * 2. Redistributions in binary form must reproduce the above copyright 13335640Shselasky * notice, this list of conditions and the following disclaimer in the 14335640Shselasky * documentation and/or other materials provided with the distribution. 15335640Shselasky * 3. Neither the name of the Politecnico di Torino, CACE Technologies 16335640Shselasky * nor the names of its contributors may be used to endorse or promote 17335640Shselasky * products derived from this software without specific prior written 18335640Shselasky * permission. 19335640Shselasky * 20335640Shselasky * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21335640Shselasky * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22335640Shselasky * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23335640Shselasky * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24335640Shselasky * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25335640Shselasky * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26335640Shselasky * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27335640Shselasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28335640Shselasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29335640Shselasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30335640Shselasky * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31335640Shselasky * 32335640Shselasky */ 33335640Shselasky 34335640Shselasky#ifdef HAVE_CONFIG_H 35335640Shselasky#include <config.h> 36335640Shselasky#endif 37335640Shselasky 38335640Shselasky#include <errno.h> 39335640Shselasky#define PCAP_DONT_INCLUDE_PCAP_BPF_H 40335640Shselasky#include <Packet32.h> 41335640Shselasky#include <pcap-int.h> 42335640Shselasky#include <pcap/dlt.h> 43335640Shselasky 44335640Shselasky/* Old-school MinGW have these headers in a different place. 45335640Shselasky */ 46335640Shselasky#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) 47335640Shselasky #include <ddk/ntddndis.h> 48335640Shselasky #include <ddk/ndis.h> 49335640Shselasky#else 50335640Shselasky #include <ntddndis.h> /* MSVC/TDM-MinGW/MinGW64 */ 51335640Shselasky#endif 52335640Shselasky 53335640Shselasky#ifdef HAVE_DAG_API 54335640Shselasky #include <dagnew.h> 55335640Shselasky #include <dagapi.h> 56335640Shselasky#endif /* HAVE_DAG_API */ 57335640Shselasky 58335640Shselaskystatic int pcap_setfilter_npf(pcap_t *, struct bpf_program *); 59335640Shselaskystatic int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *); 60335640Shselaskystatic int pcap_getnonblock_npf(pcap_t *); 61335640Shselaskystatic int pcap_setnonblock_npf(pcap_t *, int); 62335640Shselasky 63335640Shselasky/*dimension of the buffer in the pcap_t structure*/ 64335640Shselasky#define WIN32_DEFAULT_USER_BUFFER_SIZE 256000 65335640Shselasky 66335640Shselasky/*dimension of the buffer in the kernel driver NPF */ 67335640Shselasky#define WIN32_DEFAULT_KERNEL_BUFFER_SIZE 1000000 68335640Shselasky 69335640Shselasky/* Equivalent to ntohs(), but a lot faster under Windows */ 70335640Shselasky#define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) 71335640Shselasky 72335640Shselasky/* 73356341Scy * Private data for capturing on WinPcap/Npcap devices. 74335640Shselasky */ 75335640Shselaskystruct pcap_win { 76335640Shselasky ADAPTER *adapter; /* the packet32 ADAPTER for the device */ 77335640Shselasky int nonblock; 78335640Shselasky int rfmon_selfstart; /* a flag tells whether the monitor mode is set by itself */ 79335640Shselasky int filtering_in_kernel; /* using kernel filter */ 80335640Shselasky 81335640Shselasky#ifdef HAVE_DAG_API 82335640Shselasky int dag_fcs_bits; /* Number of checksum bits from link layer */ 83335640Shselasky#endif 84335640Shselasky 85335640Shselasky#ifdef ENABLE_REMOTE 86335640Shselasky int samp_npkt; /* parameter needed for sampling, with '1 out of N' method has been requested */ 87335640Shselasky struct timeval samp_time; /* parameter needed for sampling, with '1 every N ms' method has been requested */ 88335640Shselasky#endif 89335640Shselasky}; 90335640Shselasky 91335640Shselasky/* 92335640Shselasky * Define stub versions of the monitor-mode support routines if this 93335640Shselasky * isn't Npcap. HAVE_NPCAP_PACKET_API is defined by Npcap but not 94335640Shselasky * WinPcap. 95335640Shselasky */ 96335640Shselasky#ifndef HAVE_NPCAP_PACKET_API 97335640Shselaskystatic int 98335640ShselaskyPacketIsMonitorModeSupported(PCHAR AdapterName _U_) 99335640Shselasky{ 100335640Shselasky /* 101335640Shselasky * We don't support monitor mode. 102335640Shselasky */ 103335640Shselasky return (0); 104335640Shselasky} 105335640Shselasky 106335640Shselaskystatic int 107335640ShselaskyPacketSetMonitorMode(PCHAR AdapterName _U_, int mode _U_) 108335640Shselasky{ 109335640Shselasky /* 110335640Shselasky * This should never be called, as PacketIsMonitorModeSupported() 111335640Shselasky * will return 0, meaning "we don't support monitor mode, so 112335640Shselasky * don't try to turn it on or off". 113335640Shselasky */ 114335640Shselasky return (0); 115335640Shselasky} 116335640Shselasky 117335640Shselaskystatic int 118335640ShselaskyPacketGetMonitorMode(PCHAR AdapterName _U_) 119335640Shselasky{ 120335640Shselasky /* 121335640Shselasky * This should fail, so that pcap_activate_npf() returns 122335640Shselasky * PCAP_ERROR_RFMON_NOTSUP if our caller requested monitor 123335640Shselasky * mode. 124335640Shselasky */ 125335640Shselasky return (-1); 126335640Shselasky} 127335640Shselasky#endif 128335640Shselasky 129335640Shselasky/* 130335640Shselasky * Sigh. PacketRequest() will have made a DeviceIoControl() 131335640Shselasky * call to the NPF driver to perform the OID request, with a 132335640Shselasky * BIOCQUERYOID ioctl. The kernel code should get back one 133335640Shselasky * of NDIS_STATUS_INVALID_OID, NDIS_STATUS_NOT_SUPPORTED, 134335640Shselasky * or NDIS_STATUS_NOT_RECOGNIZED if the OID request isn't 135335640Shselasky * supported by the OS or the driver, but that doesn't seem 136335640Shselasky * to make it to the caller of PacketRequest() in a 137356341Scy * reliable fashion. 138335640Shselasky */ 139335640Shselasky#define NDIS_STATUS_INVALID_OID 0xc0010017 140335640Shselasky#define NDIS_STATUS_NOT_SUPPORTED 0xc00000bb /* STATUS_NOT_SUPPORTED */ 141335640Shselasky#define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 142335640Shselasky 143335640Shselaskystatic int 144335640Shselaskyoid_get_request(ADAPTER *adapter, bpf_u_int32 oid, void *data, size_t *lenp, 145335640Shselasky char *errbuf) 146335640Shselasky{ 147335640Shselasky PACKET_OID_DATA *oid_data_arg; 148335640Shselasky 149335640Shselasky /* 150335640Shselasky * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). 151335640Shselasky * It should be big enough to hold "*lenp" bytes of data; it 152335640Shselasky * will actually be slightly larger, as PACKET_OID_DATA has a 153335640Shselasky * 1-byte data array at the end, standing in for the variable-length 154335640Shselasky * data that's actually there. 155335640Shselasky */ 156335640Shselasky oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp); 157335640Shselasky if (oid_data_arg == NULL) { 158335640Shselasky pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 159335640Shselasky "Couldn't allocate argument buffer for PacketRequest"); 160335640Shselasky return (PCAP_ERROR); 161335640Shselasky } 162335640Shselasky 163335640Shselasky /* 164335640Shselasky * No need to copy the data - we're doing a fetch. 165335640Shselasky */ 166335640Shselasky oid_data_arg->Oid = oid; 167335640Shselasky oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ 168335640Shselasky if (!PacketRequest(adapter, FALSE, oid_data_arg)) { 169356341Scy pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, 170356341Scy GetLastError(), "Error calling PacketRequest"); 171335640Shselasky free(oid_data_arg); 172335640Shselasky return (-1); 173335640Shselasky } 174335640Shselasky 175335640Shselasky /* 176335640Shselasky * Get the length actually supplied. 177335640Shselasky */ 178335640Shselasky *lenp = oid_data_arg->Length; 179335640Shselasky 180335640Shselasky /* 181335640Shselasky * Copy back the data we fetched. 182335640Shselasky */ 183335640Shselasky memcpy(data, oid_data_arg->Data, *lenp); 184335640Shselasky free(oid_data_arg); 185335640Shselasky return (0); 186335640Shselasky} 187335640Shselasky 188335640Shselaskystatic int 189335640Shselaskypcap_stats_npf(pcap_t *p, struct pcap_stat *ps) 190335640Shselasky{ 191335640Shselasky struct pcap_win *pw = p->priv; 192335640Shselasky struct bpf_stat bstats; 193335640Shselasky 194335640Shselasky /* 195335640Shselasky * Try to get statistics. 196335640Shselasky * 197335640Shselasky * (Please note - "struct pcap_stat" is *not* the same as 198335640Shselasky * WinPcap's "struct bpf_stat". It might currently have the 199335640Shselasky * same layout, but let's not cheat. 200335640Shselasky * 201335640Shselasky * Note also that we don't fill in ps_capt, as we might have 202335640Shselasky * been called by code compiled against an earlier version of 203335640Shselasky * WinPcap that didn't have ps_capt, in which case filling it 204335640Shselasky * in would stomp on whatever comes after the structure passed 205335640Shselasky * to us. 206335640Shselasky */ 207335640Shselasky if (!PacketGetStats(pw->adapter, &bstats)) { 208356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, 209356341Scy GetLastError(), "PacketGetStats error"); 210335640Shselasky return (-1); 211335640Shselasky } 212335640Shselasky ps->ps_recv = bstats.bs_recv; 213335640Shselasky ps->ps_drop = bstats.bs_drop; 214335640Shselasky 215335640Shselasky /* 216335640Shselasky * XXX - PacketGetStats() doesn't fill this in, so we just 217335640Shselasky * return 0. 218335640Shselasky */ 219335640Shselasky#if 0 220335640Shselasky ps->ps_ifdrop = bstats.ps_ifdrop; 221335640Shselasky#else 222335640Shselasky ps->ps_ifdrop = 0; 223335640Shselasky#endif 224335640Shselasky 225335640Shselasky return (0); 226335640Shselasky} 227335640Shselasky 228335640Shselasky/* 229335640Shselasky * Win32-only routine for getting statistics. 230335640Shselasky * 231335640Shselasky * This way is definitely safer than passing the pcap_stat * from the userland. 232335640Shselasky * In fact, there could happen than the user allocates a variable which is not 233335640Shselasky * big enough for the new structure, and the library will write in a zone 234335640Shselasky * which is not allocated to this variable. 235335640Shselasky * 236335640Shselasky * In this way, we're pretty sure we are writing on memory allocated to this 237335640Shselasky * variable. 238335640Shselasky * 239335640Shselasky * XXX - but this is the wrong way to handle statistics. Instead, we should 240335640Shselasky * have an API that returns data in a form like the Options section of a 241335640Shselasky * pcapng Interface Statistics Block: 242335640Shselasky * 243335640Shselasky * 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 244335640Shselasky * 245335640Shselasky * which would let us add new statistics straightforwardly and indicate which 246335640Shselasky * statistics we are and are *not* providing, rather than having to provide 247335640Shselasky * possibly-bogus values for statistics we can't provide. 248335640Shselasky */ 249335640Shselaskystruct pcap_stat * 250335640Shselaskypcap_stats_ex_npf(pcap_t *p, int *pcap_stat_size) 251335640Shselasky{ 252335640Shselasky struct pcap_win *pw = p->priv; 253335640Shselasky struct bpf_stat bstats; 254335640Shselasky 255335640Shselasky *pcap_stat_size = sizeof (p->stat); 256335640Shselasky 257335640Shselasky /* 258335640Shselasky * Try to get statistics. 259335640Shselasky * 260335640Shselasky * (Please note - "struct pcap_stat" is *not* the same as 261335640Shselasky * WinPcap's "struct bpf_stat". It might currently have the 262335640Shselasky * same layout, but let's not cheat.) 263335640Shselasky */ 264335640Shselasky if (!PacketGetStatsEx(pw->adapter, &bstats)) { 265356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, 266356341Scy GetLastError(), "PacketGetStatsEx error"); 267335640Shselasky return (NULL); 268335640Shselasky } 269335640Shselasky p->stat.ps_recv = bstats.bs_recv; 270335640Shselasky p->stat.ps_drop = bstats.bs_drop; 271335640Shselasky p->stat.ps_ifdrop = bstats.ps_ifdrop; 272335640Shselasky#ifdef ENABLE_REMOTE 273335640Shselasky p->stat.ps_capt = bstats.bs_capt; 274335640Shselasky#endif 275335640Shselasky return (&p->stat); 276335640Shselasky} 277335640Shselasky 278335640Shselasky/* Set the dimension of the kernel-level capture buffer */ 279335640Shselaskystatic int 280335640Shselaskypcap_setbuff_npf(pcap_t *p, int dim) 281335640Shselasky{ 282335640Shselasky struct pcap_win *pw = p->priv; 283335640Shselasky 284335640Shselasky if(PacketSetBuff(pw->adapter,dim)==FALSE) 285335640Shselasky { 286335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); 287335640Shselasky return (-1); 288335640Shselasky } 289335640Shselasky return (0); 290335640Shselasky} 291335640Shselasky 292335640Shselasky/* Set the driver working mode */ 293335640Shselaskystatic int 294335640Shselaskypcap_setmode_npf(pcap_t *p, int mode) 295335640Shselasky{ 296335640Shselasky struct pcap_win *pw = p->priv; 297335640Shselasky 298335640Shselasky if(PacketSetMode(pw->adapter,mode)==FALSE) 299335640Shselasky { 300335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized"); 301335640Shselasky return (-1); 302335640Shselasky } 303335640Shselasky 304335640Shselasky return (0); 305335640Shselasky} 306335640Shselasky 307335640Shselasky/*set the minimum amount of data that will release a read call*/ 308335640Shselaskystatic int 309335640Shselaskypcap_setmintocopy_npf(pcap_t *p, int size) 310335640Shselasky{ 311335640Shselasky struct pcap_win *pw = p->priv; 312335640Shselasky 313335640Shselasky if(PacketSetMinToCopy(pw->adapter, size)==FALSE) 314335640Shselasky { 315335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size"); 316335640Shselasky return (-1); 317335640Shselasky } 318335640Shselasky return (0); 319335640Shselasky} 320335640Shselasky 321335640Shselaskystatic HANDLE 322335640Shselaskypcap_getevent_npf(pcap_t *p) 323335640Shselasky{ 324335640Shselasky struct pcap_win *pw = p->priv; 325335640Shselasky 326335640Shselasky return (PacketGetReadEvent(pw->adapter)); 327335640Shselasky} 328335640Shselasky 329335640Shselaskystatic int 330335640Shselaskypcap_oid_get_request_npf(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp) 331335640Shselasky{ 332335640Shselasky struct pcap_win *pw = p->priv; 333335640Shselasky 334335640Shselasky return (oid_get_request(pw->adapter, oid, data, lenp, p->errbuf)); 335335640Shselasky} 336335640Shselasky 337335640Shselaskystatic int 338335640Shselaskypcap_oid_set_request_npf(pcap_t *p, bpf_u_int32 oid, const void *data, 339335640Shselasky size_t *lenp) 340335640Shselasky{ 341335640Shselasky struct pcap_win *pw = p->priv; 342335640Shselasky PACKET_OID_DATA *oid_data_arg; 343335640Shselasky 344335640Shselasky /* 345335640Shselasky * Allocate a PACKET_OID_DATA structure to hand to PacketRequest(). 346335640Shselasky * It should be big enough to hold "*lenp" bytes of data; it 347335640Shselasky * will actually be slightly larger, as PACKET_OID_DATA has a 348335640Shselasky * 1-byte data array at the end, standing in for the variable-length 349335640Shselasky * data that's actually there. 350335640Shselasky */ 351335640Shselasky oid_data_arg = malloc(sizeof (PACKET_OID_DATA) + *lenp); 352335640Shselasky if (oid_data_arg == NULL) { 353335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 354335640Shselasky "Couldn't allocate argument buffer for PacketRequest"); 355335640Shselasky return (PCAP_ERROR); 356335640Shselasky } 357335640Shselasky 358335640Shselasky oid_data_arg->Oid = oid; 359335640Shselasky oid_data_arg->Length = (ULONG)(*lenp); /* XXX - check for ridiculously large value? */ 360335640Shselasky memcpy(oid_data_arg->Data, data, *lenp); 361335640Shselasky if (!PacketRequest(pw->adapter, TRUE, oid_data_arg)) { 362356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, 363356341Scy GetLastError(), "Error calling PacketRequest"); 364335640Shselasky free(oid_data_arg); 365335640Shselasky return (PCAP_ERROR); 366335640Shselasky } 367335640Shselasky 368335640Shselasky /* 369335640Shselasky * Get the length actually copied. 370335640Shselasky */ 371335640Shselasky *lenp = oid_data_arg->Length; 372335640Shselasky 373335640Shselasky /* 374335640Shselasky * No need to copy the data - we're doing a set. 375335640Shselasky */ 376335640Shselasky free(oid_data_arg); 377335640Shselasky return (0); 378335640Shselasky} 379335640Shselasky 380335640Shselaskystatic u_int 381335640Shselaskypcap_sendqueue_transmit_npf(pcap_t *p, pcap_send_queue *queue, int sync) 382335640Shselasky{ 383335640Shselasky struct pcap_win *pw = p->priv; 384335640Shselasky u_int res; 385335640Shselasky 386335640Shselasky if (pw->adapter==NULL) { 387335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 388335640Shselasky "Cannot transmit a queue to an offline capture or to a TurboCap port"); 389335640Shselasky return (0); 390335640Shselasky } 391335640Shselasky 392335640Shselasky res = PacketSendPackets(pw->adapter, 393335640Shselasky queue->buffer, 394335640Shselasky queue->len, 395335640Shselasky (BOOLEAN)sync); 396335640Shselasky 397335640Shselasky if(res != queue->len){ 398356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, 399356341Scy GetLastError(), "Error opening adapter"); 400335640Shselasky } 401335640Shselasky 402335640Shselasky return (res); 403335640Shselasky} 404335640Shselasky 405335640Shselaskystatic int 406335640Shselaskypcap_setuserbuffer_npf(pcap_t *p, int size) 407335640Shselasky{ 408335640Shselasky unsigned char *new_buff; 409335640Shselasky 410335640Shselasky if (size<=0) { 411335640Shselasky /* Bogus parameter */ 412335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 413335640Shselasky "Error: invalid size %d",size); 414335640Shselasky return (-1); 415335640Shselasky } 416335640Shselasky 417335640Shselasky /* Allocate the buffer */ 418335640Shselasky new_buff=(unsigned char*)malloc(sizeof(char)*size); 419335640Shselasky 420335640Shselasky if (!new_buff) { 421335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 422335640Shselasky "Error: not enough memory"); 423335640Shselasky return (-1); 424335640Shselasky } 425335640Shselasky 426335640Shselasky free(p->buffer); 427335640Shselasky 428335640Shselasky p->buffer=new_buff; 429335640Shselasky p->bufsize=size; 430335640Shselasky 431335640Shselasky return (0); 432335640Shselasky} 433335640Shselasky 434335640Shselaskystatic int 435335640Shselaskypcap_live_dump_npf(pcap_t *p, char *filename, int maxsize, int maxpacks) 436335640Shselasky{ 437335640Shselasky struct pcap_win *pw = p->priv; 438335640Shselasky BOOLEAN res; 439335640Shselasky 440335640Shselasky /* Set the packet driver in dump mode */ 441335640Shselasky res = PacketSetMode(pw->adapter, PACKET_MODE_DUMP); 442335640Shselasky if(res == FALSE){ 443335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 444335640Shselasky "Error setting dump mode"); 445335640Shselasky return (-1); 446335640Shselasky } 447335640Shselasky 448335640Shselasky /* Set the name of the dump file */ 449335640Shselasky res = PacketSetDumpName(pw->adapter, filename, (int)strlen(filename)); 450335640Shselasky if(res == FALSE){ 451335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 452335640Shselasky "Error setting kernel dump file name"); 453335640Shselasky return (-1); 454335640Shselasky } 455335640Shselasky 456335640Shselasky /* Set the limits of the dump file */ 457335640Shselasky res = PacketSetDumpLimits(pw->adapter, maxsize, maxpacks); 458335640Shselasky if(res == FALSE) { 459335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 460335640Shselasky "Error setting dump limit"); 461335640Shselasky return (-1); 462335640Shselasky } 463335640Shselasky 464335640Shselasky return (0); 465335640Shselasky} 466335640Shselasky 467335640Shselaskystatic int 468335640Shselaskypcap_live_dump_ended_npf(pcap_t *p, int sync) 469335640Shselasky{ 470335640Shselasky struct pcap_win *pw = p->priv; 471335640Shselasky 472335640Shselasky return (PacketIsDumpEnded(pw->adapter, (BOOLEAN)sync)); 473335640Shselasky} 474335640Shselasky 475335640Shselaskystatic PAirpcapHandle 476335640Shselaskypcap_get_airpcap_handle_npf(pcap_t *p) 477335640Shselasky{ 478335640Shselasky#ifdef HAVE_AIRPCAP_API 479335640Shselasky struct pcap_win *pw = p->priv; 480335640Shselasky 481335640Shselasky return (PacketGetAirPcapHandle(pw->adapter)); 482335640Shselasky#else 483335640Shselasky return (NULL); 484335640Shselasky#endif /* HAVE_AIRPCAP_API */ 485335640Shselasky} 486335640Shselasky 487335640Shselaskystatic int 488335640Shselaskypcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 489335640Shselasky{ 490335640Shselasky PACKET Packet; 491335640Shselasky int cc; 492335640Shselasky int n = 0; 493335640Shselasky register u_char *bp, *ep; 494335640Shselasky u_char *datap; 495335640Shselasky struct pcap_win *pw = p->priv; 496335640Shselasky 497335640Shselasky cc = p->cc; 498335640Shselasky if (p->cc == 0) { 499335640Shselasky /* 500335640Shselasky * Has "pcap_breakloop()" been called? 501335640Shselasky */ 502335640Shselasky if (p->break_loop) { 503335640Shselasky /* 504335640Shselasky * Yes - clear the flag that indicates that it 505335640Shselasky * has, and return PCAP_ERROR_BREAK to indicate 506335640Shselasky * that we were told to break out of the loop. 507335640Shselasky */ 508335640Shselasky p->break_loop = 0; 509335640Shselasky return (PCAP_ERROR_BREAK); 510335640Shselasky } 511335640Shselasky 512335640Shselasky /* 513335640Shselasky * Capture the packets. 514335640Shselasky * 515335640Shselasky * The PACKET structure had a bunch of extra stuff for 516335640Shselasky * Windows 9x/Me, but the only interesting data in it 517335640Shselasky * in the versions of Windows that we support is just 518335640Shselasky * a copy of p->buffer, a copy of p->buflen, and the 519335640Shselasky * actual number of bytes read returned from 520335640Shselasky * PacketReceivePacket(), none of which has to be 521335640Shselasky * retained from call to call, so we just keep one on 522335640Shselasky * the stack. 523335640Shselasky */ 524335640Shselasky PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); 525335640Shselasky if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) { 526356341Scy /* 527356341Scy * Did the device go away? 528356341Scy * If so, the error we get is ERROR_GEN_FAILURE. 529356341Scy */ 530356341Scy DWORD errcode = GetLastError(); 531356341Scy 532356341Scy if (errcode == ERROR_GEN_FAILURE) { 533356341Scy /* 534356341Scy * The device on which we're capturing 535356341Scy * went away, or it became unusable 536356341Scy * by NPF due to a suspend/resume. 537356341Scy * 538356341Scy * XXX - hopefully no other error 539356341Scy * conditions are indicated by this. 540356341Scy * 541356341Scy * XXX - we really should return an 542356341Scy * appropriate error for that, but 543356341Scy * pcap_dispatch() etc. aren't 544356341Scy * documented as having error returns 545356341Scy * other than PCAP_ERROR or PCAP_ERROR_BREAK. 546356341Scy */ 547356341Scy pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 548356341Scy "The interface disappeared"); 549356341Scy } else { 550356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, 551356341Scy PCAP_ERRBUF_SIZE, errcode, 552356341Scy "PacketReceivePacket error"); 553356341Scy } 554335640Shselasky return (PCAP_ERROR); 555335640Shselasky } 556335640Shselasky 557335640Shselasky cc = Packet.ulBytesReceived; 558335640Shselasky 559335640Shselasky bp = p->buffer; 560335640Shselasky } 561335640Shselasky else 562335640Shselasky bp = p->bp; 563335640Shselasky 564335640Shselasky /* 565335640Shselasky * Loop through each packet. 566335640Shselasky */ 567335640Shselasky#define bhp ((struct bpf_hdr *)bp) 568335640Shselasky ep = bp + cc; 569335640Shselasky for (;;) { 570335640Shselasky register int caplen, hdrlen; 571335640Shselasky 572335640Shselasky /* 573335640Shselasky * Has "pcap_breakloop()" been called? 574335640Shselasky * If so, return immediately - if we haven't read any 575335640Shselasky * packets, clear the flag and return PCAP_ERROR_BREAK 576335640Shselasky * to indicate that we were told to break out of the loop, 577335640Shselasky * otherwise leave the flag set, so that the *next* call 578335640Shselasky * will break out of the loop without having read any 579335640Shselasky * packets, and return the number of packets we've 580335640Shselasky * processed so far. 581335640Shselasky */ 582335640Shselasky if (p->break_loop) { 583335640Shselasky if (n == 0) { 584335640Shselasky p->break_loop = 0; 585335640Shselasky return (PCAP_ERROR_BREAK); 586335640Shselasky } else { 587335640Shselasky p->bp = bp; 588335640Shselasky p->cc = (int) (ep - bp); 589335640Shselasky return (n); 590335640Shselasky } 591335640Shselasky } 592335640Shselasky if (bp >= ep) 593335640Shselasky break; 594335640Shselasky 595335640Shselasky caplen = bhp->bh_caplen; 596335640Shselasky hdrlen = bhp->bh_hdrlen; 597335640Shselasky datap = bp + hdrlen; 598335640Shselasky 599335640Shselasky /* 600335640Shselasky * Short-circuit evaluation: if using BPF filter 601335640Shselasky * in kernel, no need to do it now - we already know 602335640Shselasky * the packet passed the filter. 603335640Shselasky * 604335640Shselasky * XXX - bpf_filter() should always return TRUE if 605335640Shselasky * handed a null pointer for the program, but it might 606335640Shselasky * just try to "run" the filter, so we check here. 607335640Shselasky */ 608335640Shselasky if (pw->filtering_in_kernel || 609335640Shselasky p->fcode.bf_insns == NULL || 610335640Shselasky bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { 611335640Shselasky#ifdef ENABLE_REMOTE 612335640Shselasky switch (p->rmt_samp.method) { 613335640Shselasky 614335640Shselasky case PCAP_SAMP_1_EVERY_N: 615335640Shselasky pw->samp_npkt = (pw->samp_npkt + 1) % p->rmt_samp.value; 616335640Shselasky 617335640Shselasky /* Discard all packets that are not '1 out of N' */ 618335640Shselasky if (pw->samp_npkt != 0) { 619335640Shselasky bp += Packet_WORDALIGN(caplen + hdrlen); 620335640Shselasky continue; 621335640Shselasky } 622335640Shselasky break; 623335640Shselasky 624335640Shselasky case PCAP_SAMP_FIRST_AFTER_N_MS: 625335640Shselasky { 626335640Shselasky struct pcap_pkthdr *pkt_header = (struct pcap_pkthdr*) bp; 627335640Shselasky 628335640Shselasky /* 629335640Shselasky * Check if the timestamp of the arrived 630335640Shselasky * packet is smaller than our target time. 631335640Shselasky */ 632335640Shselasky if (pkt_header->ts.tv_sec < pw->samp_time.tv_sec || 633335640Shselasky (pkt_header->ts.tv_sec == pw->samp_time.tv_sec && pkt_header->ts.tv_usec < pw->samp_time.tv_usec)) { 634335640Shselasky bp += Packet_WORDALIGN(caplen + hdrlen); 635335640Shselasky continue; 636335640Shselasky } 637335640Shselasky 638335640Shselasky /* 639335640Shselasky * The arrived packet is suitable for being 640335640Shselasky * delivered to our caller, so let's update 641335640Shselasky * the target time. 642335640Shselasky */ 643335640Shselasky pw->samp_time.tv_usec = pkt_header->ts.tv_usec + p->rmt_samp.value * 1000; 644335640Shselasky if (pw->samp_time.tv_usec > 1000000) { 645335640Shselasky pw->samp_time.tv_sec = pkt_header->ts.tv_sec + pw->samp_time.tv_usec / 1000000; 646335640Shselasky pw->samp_time.tv_usec = pw->samp_time.tv_usec % 1000000; 647335640Shselasky } 648335640Shselasky } 649335640Shselasky } 650335640Shselasky#endif /* ENABLE_REMOTE */ 651335640Shselasky 652335640Shselasky /* 653335640Shselasky * XXX A bpf_hdr matches a pcap_pkthdr. 654335640Shselasky */ 655335640Shselasky (*callback)(user, (struct pcap_pkthdr*)bp, datap); 656335640Shselasky bp += Packet_WORDALIGN(caplen + hdrlen); 657335640Shselasky if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { 658335640Shselasky p->bp = bp; 659335640Shselasky p->cc = (int) (ep - bp); 660335640Shselasky return (n); 661335640Shselasky } 662335640Shselasky } else { 663335640Shselasky /* 664335640Shselasky * Skip this packet. 665335640Shselasky */ 666335640Shselasky bp += Packet_WORDALIGN(caplen + hdrlen); 667335640Shselasky } 668335640Shselasky } 669335640Shselasky#undef bhp 670335640Shselasky p->cc = 0; 671335640Shselasky return (n); 672335640Shselasky} 673335640Shselasky 674335640Shselasky#ifdef HAVE_DAG_API 675335640Shselaskystatic int 676335640Shselaskypcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 677335640Shselasky{ 678335640Shselasky struct pcap_win *pw = p->priv; 679335640Shselasky PACKET Packet; 680335640Shselasky u_char *dp = NULL; 681335640Shselasky int packet_len = 0, caplen = 0; 682335640Shselasky struct pcap_pkthdr pcap_header; 683335640Shselasky u_char *endofbuf; 684335640Shselasky int n = 0; 685335640Shselasky dag_record_t *header; 686335640Shselasky unsigned erf_record_len; 687335640Shselasky ULONGLONG ts; 688335640Shselasky int cc; 689335640Shselasky unsigned swt; 690335640Shselasky unsigned dfp = pw->adapter->DagFastProcess; 691335640Shselasky 692335640Shselasky cc = p->cc; 693335640Shselasky if (cc == 0) /* Get new packets only if we have processed all the ones of the previous read */ 694335640Shselasky { 695335640Shselasky /* 696335640Shselasky * Get new packets from the network. 697335640Shselasky * 698335640Shselasky * The PACKET structure had a bunch of extra stuff for 699335640Shselasky * Windows 9x/Me, but the only interesting data in it 700335640Shselasky * in the versions of Windows that we support is just 701335640Shselasky * a copy of p->buffer, a copy of p->buflen, and the 702335640Shselasky * actual number of bytes read returned from 703335640Shselasky * PacketReceivePacket(), none of which has to be 704335640Shselasky * retained from call to call, so we just keep one on 705335640Shselasky * the stack. 706335640Shselasky */ 707335640Shselasky PacketInitPacket(&Packet, (BYTE *)p->buffer, p->bufsize); 708335640Shselasky if (!PacketReceivePacket(pw->adapter, &Packet, TRUE)) { 709335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); 710335640Shselasky return (-1); 711335640Shselasky } 712335640Shselasky 713335640Shselasky cc = Packet.ulBytesReceived; 714335640Shselasky if(cc == 0) 715335640Shselasky /* The timeout has expired but we no packets arrived */ 716335640Shselasky return (0); 717335640Shselasky header = (dag_record_t*)pw->adapter->DagBuffer; 718335640Shselasky } 719335640Shselasky else 720335640Shselasky header = (dag_record_t*)p->bp; 721335640Shselasky 722335640Shselasky endofbuf = (char*)header + cc; 723335640Shselasky 724335640Shselasky /* 725335640Shselasky * Cycle through the packets 726335640Shselasky */ 727335640Shselasky do 728335640Shselasky { 729335640Shselasky erf_record_len = SWAPS(header->rlen); 730335640Shselasky if((char*)header + erf_record_len > endofbuf) 731335640Shselasky break; 732335640Shselasky 733335640Shselasky /* Increase the number of captured packets */ 734335640Shselasky p->stat.ps_recv++; 735335640Shselasky 736335640Shselasky /* Find the beginning of the packet */ 737335640Shselasky dp = ((u_char *)header) + dag_record_size; 738335640Shselasky 739335640Shselasky /* Determine actual packet len */ 740335640Shselasky switch(header->type) 741335640Shselasky { 742335640Shselasky case TYPE_ATM: 743335640Shselasky packet_len = ATM_SNAPLEN; 744335640Shselasky caplen = ATM_SNAPLEN; 745335640Shselasky dp += 4; 746335640Shselasky 747335640Shselasky break; 748335640Shselasky 749335640Shselasky case TYPE_ETH: 750335640Shselasky swt = SWAPS(header->wlen); 751335640Shselasky packet_len = swt - (pw->dag_fcs_bits); 752335640Shselasky caplen = erf_record_len - dag_record_size - 2; 753335640Shselasky if (caplen > packet_len) 754335640Shselasky { 755335640Shselasky caplen = packet_len; 756335640Shselasky } 757335640Shselasky dp += 2; 758335640Shselasky 759335640Shselasky break; 760335640Shselasky 761335640Shselasky case TYPE_HDLC_POS: 762335640Shselasky swt = SWAPS(header->wlen); 763335640Shselasky packet_len = swt - (pw->dag_fcs_bits); 764335640Shselasky caplen = erf_record_len - dag_record_size; 765335640Shselasky if (caplen > packet_len) 766335640Shselasky { 767335640Shselasky caplen = packet_len; 768335640Shselasky } 769335640Shselasky 770335640Shselasky break; 771335640Shselasky } 772335640Shselasky 773335640Shselasky if(caplen > p->snapshot) 774335640Shselasky caplen = p->snapshot; 775335640Shselasky 776335640Shselasky /* 777335640Shselasky * Has "pcap_breakloop()" been called? 778335640Shselasky * If so, return immediately - if we haven't read any 779335640Shselasky * packets, clear the flag and return -2 to indicate 780335640Shselasky * that we were told to break out of the loop, otherwise 781335640Shselasky * leave the flag set, so that the *next* call will break 782335640Shselasky * out of the loop without having read any packets, and 783335640Shselasky * return the number of packets we've processed so far. 784335640Shselasky */ 785335640Shselasky if (p->break_loop) 786335640Shselasky { 787335640Shselasky if (n == 0) 788335640Shselasky { 789335640Shselasky p->break_loop = 0; 790335640Shselasky return (-2); 791335640Shselasky } 792335640Shselasky else 793335640Shselasky { 794335640Shselasky p->bp = (char*)header; 795335640Shselasky p->cc = endofbuf - (char*)header; 796335640Shselasky return (n); 797335640Shselasky } 798335640Shselasky } 799335640Shselasky 800335640Shselasky if(!dfp) 801335640Shselasky { 802335640Shselasky /* convert between timestamp formats */ 803335640Shselasky ts = header->ts; 804335640Shselasky pcap_header.ts.tv_sec = (int)(ts >> 32); 805335640Shselasky ts = (ts & 0xffffffffi64) * 1000000; 806335640Shselasky ts += 0x80000000; /* rounding */ 807335640Shselasky pcap_header.ts.tv_usec = (int)(ts >> 32); 808335640Shselasky if (pcap_header.ts.tv_usec >= 1000000) { 809335640Shselasky pcap_header.ts.tv_usec -= 1000000; 810335640Shselasky pcap_header.ts.tv_sec++; 811335640Shselasky } 812335640Shselasky } 813335640Shselasky 814335640Shselasky /* No underlaying filtering system. We need to filter on our own */ 815335640Shselasky if (p->fcode.bf_insns) 816335640Shselasky { 817335640Shselasky if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0) 818335640Shselasky { 819335640Shselasky /* Move to next packet */ 820335640Shselasky header = (dag_record_t*)((char*)header + erf_record_len); 821335640Shselasky continue; 822335640Shselasky } 823335640Shselasky } 824335640Shselasky 825335640Shselasky /* Fill the header for the user suppplied callback function */ 826335640Shselasky pcap_header.caplen = caplen; 827335640Shselasky pcap_header.len = packet_len; 828335640Shselasky 829335640Shselasky /* Call the callback function */ 830335640Shselasky (*callback)(user, &pcap_header, dp); 831335640Shselasky 832335640Shselasky /* Move to next packet */ 833335640Shselasky header = (dag_record_t*)((char*)header + erf_record_len); 834335640Shselasky 835335640Shselasky /* Stop if the number of packets requested by user has been reached*/ 836335640Shselasky if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) 837335640Shselasky { 838335640Shselasky p->bp = (char*)header; 839335640Shselasky p->cc = endofbuf - (char*)header; 840335640Shselasky return (n); 841335640Shselasky } 842335640Shselasky } 843335640Shselasky while((u_char*)header < endofbuf); 844335640Shselasky 845335640Shselasky return (1); 846335640Shselasky} 847335640Shselasky#endif /* HAVE_DAG_API */ 848335640Shselasky 849335640Shselasky/* Send a packet to the network */ 850335640Shselaskystatic int 851335640Shselaskypcap_inject_npf(pcap_t *p, const void *buf, size_t size) 852335640Shselasky{ 853335640Shselasky struct pcap_win *pw = p->priv; 854335640Shselasky PACKET pkt; 855335640Shselasky 856335640Shselasky PacketInitPacket(&pkt, (PVOID)buf, size); 857335640Shselasky if(PacketSendPacket(pw->adapter,&pkt,TRUE) == FALSE) { 858335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed"); 859335640Shselasky return (-1); 860335640Shselasky } 861335640Shselasky 862335640Shselasky /* 863335640Shselasky * We assume it all got sent if "PacketSendPacket()" succeeded. 864335640Shselasky * "pcap_inject()" is expected to return the number of bytes 865335640Shselasky * sent. 866335640Shselasky */ 867335640Shselasky return ((int)size); 868335640Shselasky} 869335640Shselasky 870335640Shselaskystatic void 871335640Shselaskypcap_cleanup_npf(pcap_t *p) 872335640Shselasky{ 873335640Shselasky struct pcap_win *pw = p->priv; 874335640Shselasky 875335640Shselasky if (pw->adapter != NULL) { 876335640Shselasky PacketCloseAdapter(pw->adapter); 877335640Shselasky pw->adapter = NULL; 878335640Shselasky } 879335640Shselasky if (pw->rfmon_selfstart) 880335640Shselasky { 881335640Shselasky PacketSetMonitorMode(p->opt.device, 0); 882335640Shselasky } 883335640Shselasky pcap_cleanup_live_common(p); 884335640Shselasky} 885335640Shselasky 886335640Shselaskystatic int 887335640Shselaskypcap_activate_npf(pcap_t *p) 888335640Shselasky{ 889335640Shselasky struct pcap_win *pw = p->priv; 890335640Shselasky NetType type; 891335640Shselasky int res; 892356341Scy int status = 0; 893335640Shselasky 894335640Shselasky if (p->opt.rfmon) { 895335640Shselasky /* 896335640Shselasky * Monitor mode is supported on Windows Vista and later. 897335640Shselasky */ 898335640Shselasky if (PacketGetMonitorMode(p->opt.device) == 1) 899335640Shselasky { 900335640Shselasky pw->rfmon_selfstart = 0; 901335640Shselasky } 902335640Shselasky else 903335640Shselasky { 904335640Shselasky if ((res = PacketSetMonitorMode(p->opt.device, 1)) != 1) 905335640Shselasky { 906335640Shselasky pw->rfmon_selfstart = 0; 907335640Shselasky // Monitor mode is not supported. 908335640Shselasky if (res == 0) 909335640Shselasky { 910335640Shselasky return PCAP_ERROR_RFMON_NOTSUP; 911335640Shselasky } 912335640Shselasky else 913335640Shselasky { 914335640Shselasky return PCAP_ERROR; 915335640Shselasky } 916335640Shselasky } 917335640Shselasky else 918335640Shselasky { 919335640Shselasky pw->rfmon_selfstart = 1; 920335640Shselasky } 921335640Shselasky } 922335640Shselasky } 923335640Shselasky 924335640Shselasky /* Init WinSock */ 925335640Shselasky pcap_wsockinit(); 926335640Shselasky 927335640Shselasky pw->adapter = PacketOpenAdapter(p->opt.device); 928335640Shselasky 929335640Shselasky if (pw->adapter == NULL) 930335640Shselasky { 931356341Scy DWORD errcode = GetLastError(); 932356341Scy 933356341Scy /* 934356341Scy * What error did we get when trying to open the adapter? 935356341Scy */ 936356341Scy if (errcode == ERROR_BAD_UNIT) { 937356341Scy /* 938356341Scy * There's no such device. 939356341Scy */ 940356341Scy return (PCAP_ERROR_NO_SUCH_DEVICE); 941356341Scy } else { 942356341Scy /* 943356341Scy * Unknown - report details. 944356341Scy */ 945356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, 946356341Scy errcode, "Error opening adapter"); 947356341Scy if (pw->rfmon_selfstart) 948356341Scy { 949356341Scy PacketSetMonitorMode(p->opt.device, 0); 950356341Scy } 951356341Scy return (PCAP_ERROR); 952335640Shselasky } 953335640Shselasky } 954335640Shselasky 955335640Shselasky /*get network type*/ 956335640Shselasky if(PacketGetNetType (pw->adapter,&type) == FALSE) 957335640Shselasky { 958356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, 959356341Scy GetLastError(), "Cannot determine the network type"); 960335640Shselasky goto bad; 961335640Shselasky } 962335640Shselasky 963335640Shselasky /*Set the linktype*/ 964335640Shselasky switch (type.LinkType) 965335640Shselasky { 966335640Shselasky case NdisMediumWan: 967335640Shselasky p->linktype = DLT_EN10MB; 968335640Shselasky break; 969335640Shselasky 970335640Shselasky case NdisMedium802_3: 971335640Shselasky p->linktype = DLT_EN10MB; 972335640Shselasky /* 973335640Shselasky * This is (presumably) a real Ethernet capture; give it a 974335640Shselasky * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 975335640Shselasky * that an application can let you choose it, in case you're 976335640Shselasky * capturing DOCSIS traffic that a Cisco Cable Modem 977335640Shselasky * Termination System is putting out onto an Ethernet (it 978335640Shselasky * doesn't put an Ethernet header onto the wire, it puts raw 979335640Shselasky * DOCSIS frames out on the wire inside the low-level 980335640Shselasky * Ethernet framing). 981335640Shselasky */ 982335640Shselasky p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); 983335640Shselasky /* 984335640Shselasky * If that fails, just leave the list empty. 985335640Shselasky */ 986335640Shselasky if (p->dlt_list != NULL) { 987335640Shselasky p->dlt_list[0] = DLT_EN10MB; 988335640Shselasky p->dlt_list[1] = DLT_DOCSIS; 989335640Shselasky p->dlt_count = 2; 990335640Shselasky } 991335640Shselasky break; 992335640Shselasky 993335640Shselasky case NdisMediumFddi: 994335640Shselasky p->linktype = DLT_FDDI; 995335640Shselasky break; 996335640Shselasky 997335640Shselasky case NdisMedium802_5: 998335640Shselasky p->linktype = DLT_IEEE802; 999335640Shselasky break; 1000335640Shselasky 1001335640Shselasky case NdisMediumArcnetRaw: 1002335640Shselasky p->linktype = DLT_ARCNET; 1003335640Shselasky break; 1004335640Shselasky 1005335640Shselasky case NdisMediumArcnet878_2: 1006335640Shselasky p->linktype = DLT_ARCNET; 1007335640Shselasky break; 1008335640Shselasky 1009335640Shselasky case NdisMediumAtm: 1010335640Shselasky p->linktype = DLT_ATM_RFC1483; 1011335640Shselasky break; 1012335640Shselasky 1013335640Shselasky case NdisMediumCHDLC: 1014335640Shselasky p->linktype = DLT_CHDLC; 1015335640Shselasky break; 1016335640Shselasky 1017335640Shselasky case NdisMediumPPPSerial: 1018335640Shselasky p->linktype = DLT_PPP_SERIAL; 1019335640Shselasky break; 1020335640Shselasky 1021335640Shselasky case NdisMediumNull: 1022335640Shselasky p->linktype = DLT_NULL; 1023335640Shselasky break; 1024335640Shselasky 1025335640Shselasky case NdisMediumBare80211: 1026335640Shselasky p->linktype = DLT_IEEE802_11; 1027335640Shselasky break; 1028335640Shselasky 1029335640Shselasky case NdisMediumRadio80211: 1030335640Shselasky p->linktype = DLT_IEEE802_11_RADIO; 1031335640Shselasky break; 1032335640Shselasky 1033335640Shselasky case NdisMediumPpi: 1034335640Shselasky p->linktype = DLT_PPI; 1035335640Shselasky break; 1036335640Shselasky 1037356341Scy#ifdef NdisMediumWirelessWan 1038356341Scy case NdisMediumWirelessWan: 1039356341Scy p->linktype = DLT_RAW; 1040356341Scy break; 1041356341Scy#endif 1042356341Scy 1043335640Shselasky default: 1044356341Scy /* 1045356341Scy * An unknown medium type is assumed to supply Ethernet 1046356341Scy * headers; if not, the user will have to report it, 1047356341Scy * so that the medium type and link-layer header type 1048356341Scy * can be determined. If we were to fail here, we 1049356341Scy * might get the link-layer type in the error, but 1050356341Scy * the user wouldn't get a capture, so we wouldn't 1051356341Scy * be able to determine the link-layer type; we report 1052356341Scy * a warning with the link-layer type, so at least 1053356341Scy * some programs will report the warning. 1054356341Scy */ 1055356341Scy p->linktype = DLT_EN10MB; 1056356341Scy pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 1057356341Scy "Unknown NdisMedium value %d, defaulting to DLT_EN10MB", 1058356341Scy type.LinkType); 1059356341Scy status = PCAP_WARNING; 1060335640Shselasky break; 1061335640Shselasky } 1062335640Shselasky 1063335640Shselasky /* 1064335640Shselasky * Turn a negative snapshot value (invalid), a snapshot value of 1065335640Shselasky * 0 (unspecified), or a value bigger than the normal maximum 1066335640Shselasky * value, into the maximum allowed value. 1067335640Shselasky * 1068335640Shselasky * If some application really *needs* a bigger snapshot 1069335640Shselasky * length, we should just increase MAXIMUM_SNAPLEN. 1070335640Shselasky */ 1071335640Shselasky if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 1072335640Shselasky p->snapshot = MAXIMUM_SNAPLEN; 1073335640Shselasky 1074335640Shselasky /* Set promiscuous mode */ 1075335640Shselasky if (p->opt.promisc) 1076335640Shselasky { 1077335640Shselasky 1078335640Shselasky if (PacketSetHwFilter(pw->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE) 1079335640Shselasky { 1080335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode"); 1081335640Shselasky goto bad; 1082335640Shselasky } 1083335640Shselasky } 1084335640Shselasky else 1085335640Shselasky { 1086335640Shselasky /* NDIS_PACKET_TYPE_ALL_LOCAL selects "All packets sent by installed 1087335640Shselasky * protocols and all packets indicated by the NIC" but if no protocol 1088335640Shselasky * drivers (like TCP/IP) are installed, NDIS_PACKET_TYPE_DIRECTED, 1089335640Shselasky * NDIS_PACKET_TYPE_BROADCAST, and NDIS_PACKET_TYPE_MULTICAST are needed to 1090335640Shselasky * capture incoming frames. 1091335640Shselasky */ 1092335640Shselasky if (PacketSetHwFilter(pw->adapter, 1093335640Shselasky NDIS_PACKET_TYPE_ALL_LOCAL | 1094335640Shselasky NDIS_PACKET_TYPE_DIRECTED | 1095335640Shselasky NDIS_PACKET_TYPE_BROADCAST | 1096335640Shselasky NDIS_PACKET_TYPE_MULTICAST) == FALSE) 1097335640Shselasky { 1098335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode"); 1099335640Shselasky goto bad; 1100335640Shselasky } 1101335640Shselasky } 1102335640Shselasky 1103335640Shselasky /* Set the buffer size */ 1104335640Shselasky p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE; 1105335640Shselasky 1106335640Shselasky if(!(pw->adapter->Flags & INFO_FLAG_DAG_CARD)) 1107335640Shselasky { 1108335640Shselasky /* 1109335640Shselasky * Traditional Adapter 1110335640Shselasky */ 1111335640Shselasky /* 1112335640Shselasky * If the buffer size wasn't explicitly set, default to 1113335640Shselasky * WIN32_DEFAULT_KERNEL_BUFFER_SIZE. 1114335640Shselasky */ 1115335640Shselasky if (p->opt.buffer_size == 0) 1116335640Shselasky p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE; 1117335640Shselasky 1118335640Shselasky if(PacketSetBuff(pw->adapter,p->opt.buffer_size)==FALSE) 1119335640Shselasky { 1120335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); 1121335640Shselasky goto bad; 1122335640Shselasky } 1123335640Shselasky 1124335640Shselasky p->buffer = malloc(p->bufsize); 1125335640Shselasky if (p->buffer == NULL) 1126335640Shselasky { 1127335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 1128335640Shselasky errno, "malloc"); 1129335640Shselasky goto bad; 1130335640Shselasky } 1131335640Shselasky 1132335640Shselasky if (p->opt.immediate) 1133335640Shselasky { 1134335640Shselasky /* tell the driver to copy the buffer as soon as data arrives */ 1135335640Shselasky if(PacketSetMinToCopy(pw->adapter,0)==FALSE) 1136335640Shselasky { 1137356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, 1138356341Scy PCAP_ERRBUF_SIZE, GetLastError(), 1139356341Scy "Error calling PacketSetMinToCopy"); 1140335640Shselasky goto bad; 1141335640Shselasky } 1142335640Shselasky } 1143335640Shselasky else 1144335640Shselasky { 1145335640Shselasky /* tell the driver to copy the buffer only if it contains at least 16K */ 1146335640Shselasky if(PacketSetMinToCopy(pw->adapter,16000)==FALSE) 1147335640Shselasky { 1148356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, 1149356341Scy PCAP_ERRBUF_SIZE, GetLastError(), 1150356341Scy "Error calling PacketSetMinToCopy"); 1151335640Shselasky goto bad; 1152335640Shselasky } 1153335640Shselasky } 1154335640Shselasky } else { 1155335640Shselasky /* 1156335640Shselasky * Dag Card 1157335640Shselasky */ 1158335640Shselasky#ifdef HAVE_DAG_API 1159335640Shselasky /* 1160335640Shselasky * We have DAG support. 1161335640Shselasky */ 1162335640Shselasky LONG status; 1163335640Shselasky HKEY dagkey; 1164335640Shselasky DWORD lptype; 1165335640Shselasky DWORD lpcbdata; 1166335640Shselasky int postype = 0; 1167335640Shselasky char keyname[512]; 1168335640Shselasky 1169335640Shselasky pcap_snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s", 1170335640Shselasky "SYSTEM\\CurrentControlSet\\Services\\DAG", 1171335640Shselasky strstr(_strlwr(p->opt.device), "dag")); 1172335640Shselasky do 1173335640Shselasky { 1174335640Shselasky status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey); 1175335640Shselasky if(status != ERROR_SUCCESS) 1176335640Shselasky break; 1177335640Shselasky 1178335640Shselasky status = RegQueryValueEx(dagkey, 1179335640Shselasky "PosType", 1180335640Shselasky NULL, 1181335640Shselasky &lptype, 1182335640Shselasky (char*)&postype, 1183335640Shselasky &lpcbdata); 1184335640Shselasky 1185335640Shselasky if(status != ERROR_SUCCESS) 1186335640Shselasky { 1187335640Shselasky postype = 0; 1188335640Shselasky } 1189335640Shselasky 1190335640Shselasky RegCloseKey(dagkey); 1191335640Shselasky } 1192335640Shselasky while(FALSE); 1193335640Shselasky 1194335640Shselasky 1195335640Shselasky p->snapshot = PacketSetSnapLen(pw->adapter, p->snapshot); 1196335640Shselasky 1197335640Shselasky /* Set the length of the FCS associated to any packet. This value 1198335640Shselasky * will be subtracted to the packet length */ 1199335640Shselasky pw->dag_fcs_bits = pw->adapter->DagFcsLen; 1200335640Shselasky#else /* HAVE_DAG_API */ 1201335640Shselasky /* 1202335640Shselasky * No DAG support. 1203335640Shselasky */ 1204335640Shselasky goto bad; 1205335640Shselasky#endif /* HAVE_DAG_API */ 1206335640Shselasky } 1207335640Shselasky 1208335640Shselasky PacketSetReadTimeout(pw->adapter, p->opt.timeout); 1209335640Shselasky 1210335640Shselasky /* disable loopback capture if requested */ 1211335640Shselasky if (p->opt.nocapture_local) 1212335640Shselasky { 1213335640Shselasky if (!PacketSetLoopbackBehavior(pw->adapter, NPF_DISABLE_LOOPBACK)) 1214335640Shselasky { 1215335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 1216335640Shselasky "Unable to disable the capture of loopback packets."); 1217335640Shselasky goto bad; 1218335640Shselasky } 1219335640Shselasky } 1220335640Shselasky 1221335640Shselasky#ifdef HAVE_DAG_API 1222335640Shselasky if(pw->adapter->Flags & INFO_FLAG_DAG_CARD) 1223335640Shselasky { 1224335640Shselasky /* install dag specific handlers for read and setfilter */ 1225335640Shselasky p->read_op = pcap_read_win32_dag; 1226335640Shselasky p->setfilter_op = pcap_setfilter_win32_dag; 1227335640Shselasky } 1228335640Shselasky else 1229335640Shselasky { 1230335640Shselasky#endif /* HAVE_DAG_API */ 1231335640Shselasky /* install traditional npf handlers for read and setfilter */ 1232335640Shselasky p->read_op = pcap_read_npf; 1233335640Shselasky p->setfilter_op = pcap_setfilter_npf; 1234335640Shselasky#ifdef HAVE_DAG_API 1235335640Shselasky } 1236335640Shselasky#endif /* HAVE_DAG_API */ 1237335640Shselasky p->setdirection_op = NULL; /* Not implemented. */ 1238335640Shselasky /* XXX - can this be implemented on some versions of Windows? */ 1239335640Shselasky p->inject_op = pcap_inject_npf; 1240335640Shselasky p->set_datalink_op = NULL; /* can't change data link type */ 1241335640Shselasky p->getnonblock_op = pcap_getnonblock_npf; 1242335640Shselasky p->setnonblock_op = pcap_setnonblock_npf; 1243335640Shselasky p->stats_op = pcap_stats_npf; 1244335640Shselasky p->stats_ex_op = pcap_stats_ex_npf; 1245335640Shselasky p->setbuff_op = pcap_setbuff_npf; 1246335640Shselasky p->setmode_op = pcap_setmode_npf; 1247335640Shselasky p->setmintocopy_op = pcap_setmintocopy_npf; 1248335640Shselasky p->getevent_op = pcap_getevent_npf; 1249335640Shselasky p->oid_get_request_op = pcap_oid_get_request_npf; 1250335640Shselasky p->oid_set_request_op = pcap_oid_set_request_npf; 1251335640Shselasky p->sendqueue_transmit_op = pcap_sendqueue_transmit_npf; 1252335640Shselasky p->setuserbuffer_op = pcap_setuserbuffer_npf; 1253335640Shselasky p->live_dump_op = pcap_live_dump_npf; 1254335640Shselasky p->live_dump_ended_op = pcap_live_dump_ended_npf; 1255335640Shselasky p->get_airpcap_handle_op = pcap_get_airpcap_handle_npf; 1256335640Shselasky p->cleanup_op = pcap_cleanup_npf; 1257335640Shselasky 1258335640Shselasky /* 1259335640Shselasky * XXX - this is only done because WinPcap supported 1260335640Shselasky * pcap_fileno() returning the hFile HANDLE from the 1261335640Shselasky * ADAPTER structure. We make no general guarantees 1262335640Shselasky * that the caller can do anything useful with it. 1263335640Shselasky * 1264335640Shselasky * (Not that we make any general guarantee of that 1265335640Shselasky * sort on UN*X, either, any more, given that not 1266335640Shselasky * all capture devices are regular OS network 1267335640Shselasky * interfaces.) 1268335640Shselasky */ 1269335640Shselasky p->handle = pw->adapter->hFile; 1270335640Shselasky 1271356341Scy return (status); 1272335640Shselaskybad: 1273335640Shselasky pcap_cleanup_npf(p); 1274335640Shselasky return (PCAP_ERROR); 1275335640Shselasky} 1276335640Shselasky 1277335640Shselasky/* 1278335640Shselasky* Check if rfmon mode is supported on the pcap_t for Windows systems. 1279335640Shselasky*/ 1280335640Shselaskystatic int 1281335640Shselaskypcap_can_set_rfmon_npf(pcap_t *p) 1282335640Shselasky{ 1283335640Shselasky return (PacketIsMonitorModeSupported(p->opt.device) == 1); 1284335640Shselasky} 1285335640Shselasky 1286335640Shselaskypcap_t * 1287335640Shselaskypcap_create_interface(const char *device _U_, char *ebuf) 1288335640Shselasky{ 1289335640Shselasky pcap_t *p; 1290335640Shselasky 1291335640Shselasky p = pcap_create_common(ebuf, sizeof(struct pcap_win)); 1292335640Shselasky if (p == NULL) 1293335640Shselasky return (NULL); 1294335640Shselasky 1295335640Shselasky p->activate_op = pcap_activate_npf; 1296335640Shselasky p->can_set_rfmon_op = pcap_can_set_rfmon_npf; 1297335640Shselasky return (p); 1298335640Shselasky} 1299335640Shselasky 1300335640Shselaskystatic int 1301335640Shselaskypcap_setfilter_npf(pcap_t *p, struct bpf_program *fp) 1302335640Shselasky{ 1303335640Shselasky struct pcap_win *pw = p->priv; 1304335640Shselasky 1305335640Shselasky if(PacketSetBpf(pw->adapter,fp)==FALSE){ 1306335640Shselasky /* 1307335640Shselasky * Kernel filter not installed. 1308335640Shselasky * 1309335640Shselasky * XXX - we don't know whether this failed because: 1310335640Shselasky * 1311335640Shselasky * the kernel rejected the filter program as invalid, 1312335640Shselasky * in which case we should fall back on userland 1313335640Shselasky * filtering; 1314335640Shselasky * 1315335640Shselasky * the kernel rejected the filter program as too big, 1316335640Shselasky * in which case we should again fall back on 1317335640Shselasky * userland filtering; 1318335640Shselasky * 1319335640Shselasky * there was some other problem, in which case we 1320335640Shselasky * should probably report an error. 1321335640Shselasky * 1322335640Shselasky * For NPF devices, the Win32 status will be 1323335640Shselasky * STATUS_INVALID_DEVICE_REQUEST for invalid 1324335640Shselasky * filters, but I don't know what it'd be for 1325335640Shselasky * other problems, and for some other devices 1326335640Shselasky * it might not be set at all. 1327335640Shselasky * 1328335640Shselasky * So we just fall back on userland filtering in 1329335640Shselasky * all cases. 1330335640Shselasky */ 1331335640Shselasky 1332335640Shselasky /* 1333335640Shselasky * install_bpf_program() validates the program. 1334335640Shselasky * 1335335640Shselasky * XXX - what if we already have a filter in the kernel? 1336335640Shselasky */ 1337335640Shselasky if (install_bpf_program(p, fp) < 0) 1338335640Shselasky return (-1); 1339335640Shselasky pw->filtering_in_kernel = 0; /* filtering in userland */ 1340335640Shselasky return (0); 1341335640Shselasky } 1342335640Shselasky 1343335640Shselasky /* 1344335640Shselasky * It worked. 1345335640Shselasky */ 1346335640Shselasky pw->filtering_in_kernel = 1; /* filtering in the kernel */ 1347335640Shselasky 1348335640Shselasky /* 1349335640Shselasky * Discard any previously-received packets, as they might have 1350335640Shselasky * passed whatever filter was formerly in effect, but might 1351335640Shselasky * not pass this filter (BIOCSETF discards packets buffered 1352335640Shselasky * in the kernel, so you can lose packets in any case). 1353335640Shselasky */ 1354335640Shselasky p->cc = 0; 1355335640Shselasky return (0); 1356335640Shselasky} 1357335640Shselasky 1358335640Shselasky/* 1359335640Shselasky * We filter at user level, since the kernel driver does't process the packets 1360335640Shselasky */ 1361335640Shselaskystatic int 1362335640Shselaskypcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) { 1363335640Shselasky 1364335640Shselasky if(!fp) 1365335640Shselasky { 1366356341Scy pcap_strlcpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); 1367335640Shselasky return (-1); 1368335640Shselasky } 1369335640Shselasky 1370335640Shselasky /* Install a user level filter */ 1371335640Shselasky if (install_bpf_program(p, fp) < 0) 1372335640Shselasky return (-1); 1373335640Shselasky 1374335640Shselasky return (0); 1375335640Shselasky} 1376335640Shselasky 1377335640Shselaskystatic int 1378335640Shselaskypcap_getnonblock_npf(pcap_t *p) 1379335640Shselasky{ 1380335640Shselasky struct pcap_win *pw = p->priv; 1381335640Shselasky 1382335640Shselasky /* 1383335640Shselasky * XXX - if there were a PacketGetReadTimeout() call, we 1384335640Shselasky * would use it, and return 1 if the timeout is -1 1385335640Shselasky * and 0 otherwise. 1386335640Shselasky */ 1387335640Shselasky return (pw->nonblock); 1388335640Shselasky} 1389335640Shselasky 1390335640Shselaskystatic int 1391335640Shselaskypcap_setnonblock_npf(pcap_t *p, int nonblock) 1392335640Shselasky{ 1393335640Shselasky struct pcap_win *pw = p->priv; 1394335640Shselasky int newtimeout; 1395335640Shselasky 1396335640Shselasky if (nonblock) { 1397335640Shselasky /* 1398335640Shselasky * Set the packet buffer timeout to -1 for non-blocking 1399335640Shselasky * mode. 1400335640Shselasky */ 1401335640Shselasky newtimeout = -1; 1402335640Shselasky } else { 1403335640Shselasky /* 1404335640Shselasky * Restore the timeout set when the device was opened. 1405335640Shselasky * (Note that this may be -1, in which case we're not 1406335640Shselasky * really leaving non-blocking mode. However, although 1407335640Shselasky * the timeout argument to pcap_set_timeout() and 1408335640Shselasky * pcap_open_live() is an int, you're not supposed to 1409335640Shselasky * supply a negative value, so that "shouldn't happen".) 1410335640Shselasky */ 1411335640Shselasky newtimeout = p->opt.timeout; 1412335640Shselasky } 1413335640Shselasky if (!PacketSetReadTimeout(pw->adapter, newtimeout)) { 1414356341Scy pcap_fmt_errmsg_for_win32_err(p->errbuf, PCAP_ERRBUF_SIZE, 1415356341Scy GetLastError(), "PacketSetReadTimeout"); 1416335640Shselasky return (-1); 1417335640Shselasky } 1418335640Shselasky pw->nonblock = (newtimeout == -1); 1419335640Shselasky return (0); 1420335640Shselasky} 1421335640Shselasky 1422335640Shselaskystatic int 1423335640Shselaskypcap_add_if_npf(pcap_if_list_t *devlistp, char *name, bpf_u_int32 flags, 1424335640Shselasky const char *description, char *errbuf) 1425335640Shselasky{ 1426335640Shselasky pcap_if_t *curdev; 1427335640Shselasky npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; 1428335640Shselasky LONG if_addr_size; 1429335640Shselasky int res = 0; 1430335640Shselasky 1431335640Shselasky if_addr_size = MAX_NETWORK_ADDRESSES; 1432335640Shselasky 1433335640Shselasky /* 1434335640Shselasky * Add an entry for this interface, with no addresses. 1435335640Shselasky */ 1436335640Shselasky curdev = add_dev(devlistp, name, flags, description, errbuf); 1437335640Shselasky if (curdev == NULL) { 1438335640Shselasky /* 1439335640Shselasky * Failure. 1440335640Shselasky */ 1441335640Shselasky return (-1); 1442335640Shselasky } 1443335640Shselasky 1444335640Shselasky /* 1445335640Shselasky * Get the list of addresses for the interface. 1446335640Shselasky */ 1447335640Shselasky if (!PacketGetNetInfoEx((void *)name, if_addrs, &if_addr_size)) { 1448335640Shselasky /* 1449335640Shselasky * Failure. 1450335640Shselasky * 1451335640Shselasky * We don't return an error, because this can happen with 1452335640Shselasky * NdisWan interfaces, and we want to supply them even 1453335640Shselasky * if we can't supply their addresses. 1454335640Shselasky * 1455335640Shselasky * We return an entry with an empty address list. 1456335640Shselasky */ 1457335640Shselasky return (0); 1458335640Shselasky } 1459335640Shselasky 1460335640Shselasky /* 1461335640Shselasky * Now add the addresses. 1462335640Shselasky */ 1463335640Shselasky while (if_addr_size-- > 0) { 1464335640Shselasky /* 1465335640Shselasky * "curdev" is an entry for this interface; add an entry for 1466335640Shselasky * this address to its list of addresses. 1467335640Shselasky */ 1468335640Shselasky res = add_addr_to_dev(curdev, 1469335640Shselasky (struct sockaddr *)&if_addrs[if_addr_size].IPAddress, 1470335640Shselasky sizeof (struct sockaddr_storage), 1471335640Shselasky (struct sockaddr *)&if_addrs[if_addr_size].SubnetMask, 1472335640Shselasky sizeof (struct sockaddr_storage), 1473335640Shselasky (struct sockaddr *)&if_addrs[if_addr_size].Broadcast, 1474335640Shselasky sizeof (struct sockaddr_storage), 1475335640Shselasky NULL, 1476335640Shselasky 0, 1477335640Shselasky errbuf); 1478335640Shselasky if (res == -1) { 1479335640Shselasky /* 1480335640Shselasky * Failure. 1481335640Shselasky */ 1482335640Shselasky break; 1483335640Shselasky } 1484335640Shselasky } 1485335640Shselasky 1486335640Shselasky return (res); 1487335640Shselasky} 1488335640Shselasky 1489335640Shselaskystatic int 1490335640Shselaskyget_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) 1491335640Shselasky{ 1492335640Shselasky char *name_copy; 1493335640Shselasky ADAPTER *adapter; 1494335640Shselasky int status; 1495335640Shselasky size_t len; 1496335640Shselasky NDIS_HARDWARE_STATUS hardware_status; 1497335640Shselasky#ifdef OID_GEN_PHYSICAL_MEDIUM 1498335640Shselasky NDIS_PHYSICAL_MEDIUM phys_medium; 1499335640Shselasky bpf_u_int32 gen_physical_medium_oids[] = { 1500335640Shselasky #ifdef OID_GEN_PHYSICAL_MEDIUM_EX 1501335640Shselasky OID_GEN_PHYSICAL_MEDIUM_EX, 1502335640Shselasky #endif 1503335640Shselasky OID_GEN_PHYSICAL_MEDIUM 1504335640Shselasky }; 1505335640Shselasky#define N_GEN_PHYSICAL_MEDIUM_OIDS (sizeof gen_physical_medium_oids / sizeof gen_physical_medium_oids[0]) 1506335640Shselasky size_t i; 1507335640Shselasky#endif /* OID_GEN_PHYSICAL_MEDIUM */ 1508335640Shselasky#ifdef OID_GEN_LINK_STATE 1509335640Shselasky NDIS_LINK_STATE link_state; 1510335640Shselasky#endif 1511335640Shselasky int connect_status; 1512335640Shselasky 1513335640Shselasky if (*flags & PCAP_IF_LOOPBACK) { 1514335640Shselasky /* 1515335640Shselasky * Loopback interface, so the connection status doesn't 1516335640Shselasky * apply. and it's not wireless (or wired, for that 1517335640Shselasky * matter...). We presume it's up and running. 1518335640Shselasky */ 1519335640Shselasky *flags |= PCAP_IF_UP | PCAP_IF_RUNNING | PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; 1520335640Shselasky return (0); 1521335640Shselasky } 1522335640Shselasky 1523335640Shselasky /* 1524335640Shselasky * We need to open the adapter to get this information. 1525335640Shselasky * 1526335640Shselasky * XXX - PacketOpenAdapter() takes a non-const pointer 1527335640Shselasky * as an argument, so we make a copy of the argument and 1528335640Shselasky * pass that to it. 1529335640Shselasky */ 1530335640Shselasky name_copy = strdup(name); 1531335640Shselasky adapter = PacketOpenAdapter(name_copy); 1532335640Shselasky free(name_copy); 1533335640Shselasky if (adapter == NULL) { 1534335640Shselasky /* 1535335640Shselasky * Give up; if they try to open this device, it'll fail. 1536335640Shselasky */ 1537335640Shselasky return (0); 1538335640Shselasky } 1539335640Shselasky 1540335640Shselasky#ifdef HAVE_AIRPCAP_API 1541335640Shselasky /* 1542335640Shselasky * Airpcap.sys do not support the below 'OID_GEN_x' values. 1543335640Shselasky * Just set these flags (and none of the '*flags' entered with). 1544335640Shselasky */ 1545335640Shselasky if (PacketGetAirPcapHandle(adapter)) { 1546335640Shselasky /* 1547335640Shselasky * Must be "up" and "running" if the above if succeeded. 1548335640Shselasky */ 1549335640Shselasky *flags = PCAP_IF_UP | PCAP_IF_RUNNING; 1550335640Shselasky 1551335640Shselasky /* 1552335640Shselasky * An airpcap device is a wireless device (duh!) 1553335640Shselasky */ 1554335640Shselasky *flags |= PCAP_IF_WIRELESS; 1555335640Shselasky 1556335640Shselasky /* 1557335640Shselasky * A "network assosiation state" makes no sense for airpcap. 1558335640Shselasky */ 1559335640Shselasky *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; 1560335640Shselasky PacketCloseAdapter(adapter); 1561335640Shselasky return (0); 1562335640Shselasky } 1563335640Shselasky#endif 1564335640Shselasky 1565335640Shselasky /* 1566335640Shselasky * Get the hardware status, and derive "up" and "running" from 1567335640Shselasky * that. 1568335640Shselasky */ 1569335640Shselasky len = sizeof (hardware_status); 1570335640Shselasky status = oid_get_request(adapter, OID_GEN_HARDWARE_STATUS, 1571335640Shselasky &hardware_status, &len, errbuf); 1572335640Shselasky if (status == 0) { 1573335640Shselasky switch (hardware_status) { 1574335640Shselasky 1575335640Shselasky case NdisHardwareStatusReady: 1576335640Shselasky /* 1577335640Shselasky * "Available and capable of sending and receiving 1578335640Shselasky * data over the wire", so up and running. 1579335640Shselasky */ 1580335640Shselasky *flags |= PCAP_IF_UP | PCAP_IF_RUNNING; 1581335640Shselasky break; 1582335640Shselasky 1583335640Shselasky case NdisHardwareStatusInitializing: 1584335640Shselasky case NdisHardwareStatusReset: 1585335640Shselasky /* 1586335640Shselasky * "Initializing" or "Resetting", so up, but 1587335640Shselasky * not running. 1588335640Shselasky */ 1589335640Shselasky *flags |= PCAP_IF_UP; 1590335640Shselasky break; 1591335640Shselasky 1592335640Shselasky case NdisHardwareStatusClosing: 1593335640Shselasky case NdisHardwareStatusNotReady: 1594335640Shselasky /* 1595335640Shselasky * "Closing" or "Not ready", so neither up nor 1596335640Shselasky * running. 1597335640Shselasky */ 1598335640Shselasky break; 1599335640Shselasky } 1600335640Shselasky } else { 1601335640Shselasky /* 1602335640Shselasky * Can't get the hardware status, so assume both up and 1603335640Shselasky * running. 1604335640Shselasky */ 1605335640Shselasky *flags |= PCAP_IF_UP | PCAP_IF_RUNNING; 1606335640Shselasky } 1607335640Shselasky 1608335640Shselasky /* 1609335640Shselasky * Get the network type. 1610335640Shselasky */ 1611335640Shselasky#ifdef OID_GEN_PHYSICAL_MEDIUM 1612335640Shselasky /* 1613335640Shselasky * Try the OIDs we have for this, in order. 1614335640Shselasky */ 1615335640Shselasky for (i = 0; i < N_GEN_PHYSICAL_MEDIUM_OIDS; i++) { 1616335640Shselasky len = sizeof (phys_medium); 1617335640Shselasky status = oid_get_request(adapter, gen_physical_medium_oids[i], 1618335640Shselasky &phys_medium, &len, errbuf); 1619335640Shselasky if (status == 0) { 1620335640Shselasky /* 1621335640Shselasky * Success. 1622335640Shselasky */ 1623335640Shselasky break; 1624335640Shselasky } 1625335640Shselasky /* 1626335640Shselasky * Failed. We can't determine whether it failed 1627335640Shselasky * because that particular OID isn't supported 1628335640Shselasky * or because some other problem occurred, so we 1629335640Shselasky * just drive on and try the next OID. 1630335640Shselasky */ 1631335640Shselasky } 1632335640Shselasky if (status == 0) { 1633335640Shselasky /* 1634335640Shselasky * We got the physical medium. 1635335640Shselasky */ 1636335640Shselasky switch (phys_medium) { 1637335640Shselasky 1638335640Shselasky case NdisPhysicalMediumWirelessLan: 1639335640Shselasky case NdisPhysicalMediumWirelessWan: 1640335640Shselasky case NdisPhysicalMediumNative802_11: 1641335640Shselasky case NdisPhysicalMediumBluetooth: 1642335640Shselasky case NdisPhysicalMediumUWB: 1643335640Shselasky case NdisPhysicalMediumIrda: 1644335640Shselasky /* 1645335640Shselasky * Wireless. 1646335640Shselasky */ 1647335640Shselasky *flags |= PCAP_IF_WIRELESS; 1648335640Shselasky break; 1649335640Shselasky 1650335640Shselasky default: 1651335640Shselasky /* 1652335640Shselasky * Not wireless. 1653335640Shselasky */ 1654335640Shselasky break; 1655335640Shselasky } 1656335640Shselasky } 1657335640Shselasky#endif 1658335640Shselasky 1659335640Shselasky /* 1660335640Shselasky * Get the connection status. 1661335640Shselasky */ 1662335640Shselasky#ifdef OID_GEN_LINK_STATE 1663335640Shselasky len = sizeof(link_state); 1664335640Shselasky status = oid_get_request(adapter, OID_GEN_LINK_STATE, &link_state, 1665335640Shselasky &len, errbuf); 1666335640Shselasky if (status == 0) { 1667335640Shselasky /* 1668335640Shselasky * NOTE: this also gives us the receive and transmit 1669335640Shselasky * link state. 1670335640Shselasky */ 1671335640Shselasky switch (link_state.MediaConnectState) { 1672335640Shselasky 1673335640Shselasky case MediaConnectStateConnected: 1674335640Shselasky /* 1675335640Shselasky * It's connected. 1676335640Shselasky */ 1677335640Shselasky *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; 1678335640Shselasky break; 1679335640Shselasky 1680335640Shselasky case MediaConnectStateDisconnected: 1681335640Shselasky /* 1682335640Shselasky * It's disconnected. 1683335640Shselasky */ 1684335640Shselasky *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; 1685335640Shselasky break; 1686335640Shselasky } 1687335640Shselasky } 1688335640Shselasky#else 1689335640Shselasky /* 1690335640Shselasky * OID_GEN_LINK_STATE isn't supported because it's not in our SDK. 1691335640Shselasky */ 1692335640Shselasky status = -1; 1693335640Shselasky#endif 1694335640Shselasky if (status == -1) { 1695335640Shselasky /* 1696335640Shselasky * OK, OID_GEN_LINK_STATE didn't work, try 1697335640Shselasky * OID_GEN_MEDIA_CONNECT_STATUS. 1698335640Shselasky */ 1699335640Shselasky status = oid_get_request(adapter, OID_GEN_MEDIA_CONNECT_STATUS, 1700335640Shselasky &connect_status, &len, errbuf); 1701335640Shselasky if (status == 0) { 1702335640Shselasky switch (connect_status) { 1703335640Shselasky 1704335640Shselasky case NdisMediaStateConnected: 1705335640Shselasky /* 1706335640Shselasky * It's connected. 1707335640Shselasky */ 1708335640Shselasky *flags |= PCAP_IF_CONNECTION_STATUS_CONNECTED; 1709335640Shselasky break; 1710335640Shselasky 1711335640Shselasky case NdisMediaStateDisconnected: 1712335640Shselasky /* 1713335640Shselasky * It's disconnected. 1714335640Shselasky */ 1715335640Shselasky *flags |= PCAP_IF_CONNECTION_STATUS_DISCONNECTED; 1716335640Shselasky break; 1717335640Shselasky } 1718335640Shselasky } 1719335640Shselasky } 1720335640Shselasky PacketCloseAdapter(adapter); 1721335640Shselasky return (0); 1722335640Shselasky} 1723335640Shselasky 1724335640Shselaskyint 1725335640Shselaskypcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 1726335640Shselasky{ 1727335640Shselasky int ret = 0; 1728335640Shselasky const char *desc; 1729335640Shselasky char *AdaptersName; 1730335640Shselasky ULONG NameLength; 1731335640Shselasky char *name; 1732335640Shselasky 1733335640Shselasky /* 1734335640Shselasky * Find out how big a buffer we need. 1735335640Shselasky * 1736335640Shselasky * This call should always return FALSE; if the error is 1737335640Shselasky * ERROR_INSUFFICIENT_BUFFER, NameLength will be set to 1738335640Shselasky * the size of the buffer we need, otherwise there's a 1739335640Shselasky * problem, and NameLength should be set to 0. 1740335640Shselasky * 1741335640Shselasky * It shouldn't require NameLength to be set, but, 1742335640Shselasky * at least as of WinPcap 4.1.3, it checks whether 1743335640Shselasky * NameLength is big enough before it checks for a 1744335640Shselasky * NULL buffer argument, so, while it'll still do 1745335640Shselasky * the right thing if NameLength is uninitialized and 1746335640Shselasky * whatever junk happens to be there is big enough 1747335640Shselasky * (because the pointer argument will be null), it's 1748335640Shselasky * still reading an uninitialized variable. 1749335640Shselasky */ 1750335640Shselasky NameLength = 0; 1751335640Shselasky if (!PacketGetAdapterNames(NULL, &NameLength)) 1752335640Shselasky { 1753335640Shselasky DWORD last_error = GetLastError(); 1754335640Shselasky 1755335640Shselasky if (last_error != ERROR_INSUFFICIENT_BUFFER) 1756335640Shselasky { 1757356341Scy pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, 1758356341Scy last_error, "PacketGetAdapterNames"); 1759335640Shselasky return (-1); 1760335640Shselasky } 1761335640Shselasky } 1762335640Shselasky 1763335640Shselasky if (NameLength <= 0) 1764335640Shselasky return 0; 1765335640Shselasky AdaptersName = (char*) malloc(NameLength); 1766335640Shselasky if (AdaptersName == NULL) 1767335640Shselasky { 1768335640Shselasky pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters."); 1769335640Shselasky return (-1); 1770335640Shselasky } 1771335640Shselasky 1772335640Shselasky if (!PacketGetAdapterNames(AdaptersName, &NameLength)) { 1773356341Scy pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, 1774356341Scy GetLastError(), "PacketGetAdapterNames"); 1775335640Shselasky free(AdaptersName); 1776335640Shselasky return (-1); 1777335640Shselasky } 1778335640Shselasky 1779335640Shselasky /* 1780335640Shselasky * "PacketGetAdapterNames()" returned a list of 1781335640Shselasky * null-terminated ASCII interface name strings, 1782335640Shselasky * terminated by a null string, followed by a list 1783335640Shselasky * of null-terminated ASCII interface description 1784335640Shselasky * strings, terminated by a null string. 1785335640Shselasky * This means there are two ASCII nulls at the end 1786335640Shselasky * of the first list. 1787335640Shselasky * 1788335640Shselasky * Find the end of the first list; that's the 1789335640Shselasky * beginning of the second list. 1790335640Shselasky */ 1791335640Shselasky desc = &AdaptersName[0]; 1792335640Shselasky while (*desc != '\0' || *(desc + 1) != '\0') 1793335640Shselasky desc++; 1794335640Shselasky 1795335640Shselasky /* 1796335640Shselasky * Found it - "desc" points to the first of the two 1797335640Shselasky * nulls at the end of the list of names, so the 1798335640Shselasky * first byte of the list of descriptions is two bytes 1799335640Shselasky * after it. 1800335640Shselasky */ 1801335640Shselasky desc += 2; 1802335640Shselasky 1803335640Shselasky /* 1804335640Shselasky * Loop over the elements in the first list. 1805335640Shselasky */ 1806335640Shselasky name = &AdaptersName[0]; 1807335640Shselasky while (*name != '\0') { 1808335640Shselasky bpf_u_int32 flags = 0; 1809335640Shselasky#ifdef HAVE_PACKET_IS_LOOPBACK_ADAPTER 1810335640Shselasky /* 1811335640Shselasky * Is this a loopback interface? 1812335640Shselasky */ 1813335640Shselasky if (PacketIsLoopbackAdapter(name)) { 1814335640Shselasky /* Yes */ 1815335640Shselasky flags |= PCAP_IF_LOOPBACK; 1816335640Shselasky } 1817335640Shselasky#endif 1818335640Shselasky /* 1819335640Shselasky * Get additional flags. 1820335640Shselasky */ 1821335640Shselasky if (get_if_flags(name, &flags, errbuf) == -1) { 1822335640Shselasky /* 1823335640Shselasky * Failure. 1824335640Shselasky */ 1825335640Shselasky ret = -1; 1826335640Shselasky break; 1827335640Shselasky } 1828335640Shselasky 1829335640Shselasky /* 1830335640Shselasky * Add an entry for this interface. 1831335640Shselasky */ 1832335640Shselasky if (pcap_add_if_npf(devlistp, name, flags, desc, 1833335640Shselasky errbuf) == -1) { 1834335640Shselasky /* 1835335640Shselasky * Failure. 1836335640Shselasky */ 1837335640Shselasky ret = -1; 1838335640Shselasky break; 1839335640Shselasky } 1840335640Shselasky name += strlen(name) + 1; 1841335640Shselasky desc += strlen(desc) + 1; 1842335640Shselasky } 1843335640Shselasky 1844335640Shselasky free(AdaptersName); 1845335640Shselasky return (ret); 1846335640Shselasky} 1847335640Shselasky 1848335640Shselasky/* 1849335640Shselasky * Return the name of a network interface attached to the system, or NULL 1850335640Shselasky * if none can be found. The interface must be configured up; the 1851335640Shselasky * lowest unit number is preferred; loopback is ignored. 1852335640Shselasky * 1853335640Shselasky * In the best of all possible worlds, this would be the same as on 1854335640Shselasky * UN*X, but there may be software that expects this to return a 1855335640Shselasky * full list of devices after the first device. 1856335640Shselasky */ 1857335640Shselasky#define ADAPTERSNAME_LEN 8192 1858335640Shselaskychar * 1859335640Shselaskypcap_lookupdev(char *errbuf) 1860335640Shselasky{ 1861335640Shselasky DWORD dwVersion; 1862335640Shselasky DWORD dwWindowsMajorVersion; 1863335640Shselasky 1864335640Shselasky#pragma warning (push) 1865335640Shselasky#pragma warning (disable: 4996) /* disable MSVC's GetVersion() deprecated warning here */ 1866335640Shselasky dwVersion = GetVersion(); /* get the OS version */ 1867335640Shselasky#pragma warning (pop) 1868335640Shselasky dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); 1869335640Shselasky 1870335640Shselasky if (dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4) { 1871335640Shselasky /* 1872335640Shselasky * Windows 95, 98, ME. 1873335640Shselasky */ 1874335640Shselasky ULONG NameLength = ADAPTERSNAME_LEN; 1875335640Shselasky static char AdaptersName[ADAPTERSNAME_LEN]; 1876335640Shselasky 1877335640Shselasky if (PacketGetAdapterNames(AdaptersName,&NameLength) ) 1878335640Shselasky return (AdaptersName); 1879335640Shselasky else 1880335640Shselasky return NULL; 1881335640Shselasky } else { 1882335640Shselasky /* 1883335640Shselasky * Windows NT (NT 4.0 and later). 1884335640Shselasky * Convert the names to Unicode for backward compatibility. 1885335640Shselasky */ 1886335640Shselasky ULONG NameLength = ADAPTERSNAME_LEN; 1887335640Shselasky static WCHAR AdaptersName[ADAPTERSNAME_LEN]; 1888335640Shselasky size_t BufferSpaceLeft; 1889335640Shselasky char *tAstr; 1890335640Shselasky WCHAR *Unameptr; 1891335640Shselasky char *Adescptr; 1892335640Shselasky size_t namelen, i; 1893335640Shselasky WCHAR *TAdaptersName = (WCHAR*)malloc(ADAPTERSNAME_LEN * sizeof(WCHAR)); 1894335640Shselasky int NAdapts = 0; 1895335640Shselasky 1896335640Shselasky if(TAdaptersName == NULL) 1897335640Shselasky { 1898335640Shselasky (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "memory allocation failure"); 1899335640Shselasky return NULL; 1900335640Shselasky } 1901335640Shselasky 1902335640Shselasky if ( !PacketGetAdapterNames((PTSTR)TAdaptersName,&NameLength) ) 1903335640Shselasky { 1904356341Scy pcap_fmt_errmsg_for_win32_err(errbuf, PCAP_ERRBUF_SIZE, 1905356341Scy GetLastError(), "PacketGetAdapterNames"); 1906335640Shselasky free(TAdaptersName); 1907335640Shselasky return NULL; 1908335640Shselasky } 1909335640Shselasky 1910335640Shselasky 1911335640Shselasky BufferSpaceLeft = ADAPTERSNAME_LEN * sizeof(WCHAR); 1912335640Shselasky tAstr = (char*)TAdaptersName; 1913335640Shselasky Unameptr = AdaptersName; 1914335640Shselasky 1915335640Shselasky /* 1916335640Shselasky * Convert the device names to Unicode into AdapterName. 1917335640Shselasky */ 1918335640Shselasky do { 1919335640Shselasky /* 1920335640Shselasky * Length of the name, including the terminating 1921335640Shselasky * NUL. 1922335640Shselasky */ 1923335640Shselasky namelen = strlen(tAstr) + 1; 1924335640Shselasky 1925335640Shselasky /* 1926335640Shselasky * Do we have room for the name in the Unicode 1927335640Shselasky * buffer? 1928335640Shselasky */ 1929335640Shselasky if (BufferSpaceLeft < namelen * sizeof(WCHAR)) { 1930335640Shselasky /* 1931335640Shselasky * No. 1932335640Shselasky */ 1933335640Shselasky goto quit; 1934335640Shselasky } 1935335640Shselasky BufferSpaceLeft -= namelen * sizeof(WCHAR); 1936335640Shselasky 1937335640Shselasky /* 1938335640Shselasky * Copy the name, converting ASCII to Unicode. 1939335640Shselasky * namelen includes the NUL, so we copy it as 1940335640Shselasky * well. 1941335640Shselasky */ 1942335640Shselasky for (i = 0; i < namelen; i++) 1943335640Shselasky *Unameptr++ = *tAstr++; 1944335640Shselasky 1945335640Shselasky /* 1946335640Shselasky * Count this adapter. 1947335640Shselasky */ 1948335640Shselasky NAdapts++; 1949335640Shselasky } while (namelen != 1); 1950335640Shselasky 1951335640Shselasky /* 1952335640Shselasky * Copy the descriptions, but don't convert them from 1953335640Shselasky * ASCII to Unicode. 1954335640Shselasky */ 1955335640Shselasky Adescptr = (char *)Unameptr; 1956335640Shselasky while(NAdapts--) 1957335640Shselasky { 1958335640Shselasky size_t desclen; 1959335640Shselasky 1960335640Shselasky desclen = strlen(tAstr) + 1; 1961335640Shselasky 1962335640Shselasky /* 1963335640Shselasky * Do we have room for the name in the Unicode 1964335640Shselasky * buffer? 1965335640Shselasky */ 1966335640Shselasky if (BufferSpaceLeft < desclen) { 1967335640Shselasky /* 1968335640Shselasky * No. 1969335640Shselasky */ 1970335640Shselasky goto quit; 1971335640Shselasky } 1972335640Shselasky 1973335640Shselasky /* 1974335640Shselasky * Just copy the ASCII string. 1975335640Shselasky * namelen includes the NUL, so we copy it as 1976335640Shselasky * well. 1977335640Shselasky */ 1978335640Shselasky memcpy(Adescptr, tAstr, desclen); 1979335640Shselasky Adescptr += desclen; 1980335640Shselasky tAstr += desclen; 1981335640Shselasky BufferSpaceLeft -= desclen; 1982335640Shselasky } 1983335640Shselasky 1984335640Shselasky quit: 1985335640Shselasky free(TAdaptersName); 1986335640Shselasky return (char *)(AdaptersName); 1987335640Shselasky } 1988335640Shselasky} 1989335640Shselasky 1990335640Shselasky/* 1991335640Shselasky * We can't use the same code that we use on UN*X, as that's doing 1992335640Shselasky * UN*X-specific calls. 1993335640Shselasky * 1994335640Shselasky * We don't just fetch the entire list of devices, search for the 1995335640Shselasky * particular device, and use its first IPv4 address, as that's too 1996335640Shselasky * much work to get just one device's netmask. 1997335640Shselasky */ 1998335640Shselaskyint 1999335640Shselaskypcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp, 2000335640Shselasky char *errbuf) 2001335640Shselasky{ 2002335640Shselasky /* 2003335640Shselasky * We need only the first IPv4 address, so we must scan the array returned by PacketGetNetInfo() 2004335640Shselasky * in order to skip non IPv4 (i.e. IPv6 addresses) 2005335640Shselasky */ 2006335640Shselasky npf_if_addr if_addrs[MAX_NETWORK_ADDRESSES]; 2007335640Shselasky LONG if_addr_size = MAX_NETWORK_ADDRESSES; 2008335640Shselasky struct sockaddr_in *t_addr; 2009335640Shselasky LONG i; 2010335640Shselasky 2011335640Shselasky if (!PacketGetNetInfoEx((void *)device, if_addrs, &if_addr_size)) { 2012335640Shselasky *netp = *maskp = 0; 2013335640Shselasky return (0); 2014335640Shselasky } 2015335640Shselasky 2016335640Shselasky for(i = 0; i < if_addr_size; i++) 2017335640Shselasky { 2018335640Shselasky if(if_addrs[i].IPAddress.ss_family == AF_INET) 2019335640Shselasky { 2020335640Shselasky t_addr = (struct sockaddr_in *) &(if_addrs[i].IPAddress); 2021335640Shselasky *netp = t_addr->sin_addr.S_un.S_addr; 2022335640Shselasky t_addr = (struct sockaddr_in *) &(if_addrs[i].SubnetMask); 2023335640Shselasky *maskp = t_addr->sin_addr.S_un.S_addr; 2024335640Shselasky 2025335640Shselasky *netp &= *maskp; 2026335640Shselasky return (0); 2027335640Shselasky } 2028335640Shselasky 2029335640Shselasky } 2030335640Shselasky 2031335640Shselasky *netp = *maskp = 0; 2032335640Shselasky return (0); 2033335640Shselasky} 2034335640Shselasky 2035335640Shselaskystatic const char *pcap_lib_version_string; 2036335640Shselasky 2037335640Shselasky#ifdef HAVE_VERSION_H 2038335640Shselasky/* 2039335640Shselasky * libpcap being built for Windows, as part of a WinPcap/Npcap source 2040335640Shselasky * tree. Include version.h from that source tree to get the WinPcap/Npcap 2041335640Shselasky * version. 2042335640Shselasky * 2043356341Scy * XXX - it'd be nice if we could somehow generate the WinPcap/Npcap version 2044356341Scy * number when building as part of WinPcap/Npcap. (It'd be nice to do so 2045356341Scy * for the packet.dll version number as well.) 2046335640Shselasky */ 2047335640Shselasky#include "../../version.h" 2048335640Shselasky 2049335640Shselaskystatic const char pcap_version_string[] = 2050335640Shselasky WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING ", based on " PCAP_VERSION_STRING; 2051335640Shselasky 2052335640Shselaskyconst char * 2053335640Shselaskypcap_lib_version(void) 2054335640Shselasky{ 2055335640Shselasky if (pcap_lib_version_string == NULL) { 2056335640Shselasky /* 2057335640Shselasky * Generate the version string. 2058335640Shselasky */ 2059356341Scy char *packet_version_string = PacketGetVersion(); 2060356341Scy 2061335640Shselasky if (strcmp(WINPCAP_VER_STRING, packet_version_string) == 0) { 2062335640Shselasky /* 2063356341Scy * WinPcap/Npcap version string and packet.dll version 2064356341Scy * string are the same; just report the WinPcap/Npcap 2065335640Shselasky * version. 2066335640Shselasky */ 2067335640Shselasky pcap_lib_version_string = pcap_version_string; 2068335640Shselasky } else { 2069335640Shselasky /* 2070356341Scy * WinPcap/Npcap version string and packet.dll version 2071335640Shselasky * string are different; that shouldn't be the 2072335640Shselasky * case (the two libraries should come from the 2073356341Scy * same version of WinPcap/Npcap), so we report both 2074335640Shselasky * versions. 2075335640Shselasky */ 2076356341Scy char *full_pcap_version_string; 2077356341Scy 2078356341Scy if (pcap_asprintf(&full_pcap_version_string, 2079356341Scy WINPCAP_PRODUCT_NAME " version " WINPCAP_VER_STRING " (packet.dll version %s), based on " PCAP_VERSION_STRING, 2080356341Scy packet_version_string) != -1) { 2081356341Scy /* Success */ 2082356341Scy pcap_lib_version_string = full_pcap_version_string; 2083356341Scy } 2084335640Shselasky } 2085335640Shselasky } 2086335640Shselasky return (pcap_lib_version_string); 2087335640Shselasky} 2088335640Shselasky 2089335640Shselasky#else /* HAVE_VERSION_H */ 2090335640Shselasky 2091335640Shselasky/* 2092335640Shselasky * libpcap being built for Windows, not as part of a WinPcap/Npcap source 2093335640Shselasky * tree. 2094335640Shselasky */ 2095335640Shselaskyconst char * 2096335640Shselaskypcap_lib_version(void) 2097335640Shselasky{ 2098335640Shselasky if (pcap_lib_version_string == NULL) { 2099335640Shselasky /* 2100335640Shselasky * Generate the version string. Report the packet.dll 2101335640Shselasky * version. 2102335640Shselasky */ 2103356341Scy char *full_pcap_version_string; 2104356341Scy 2105356341Scy if (pcap_asprintf(&full_pcap_version_string, 2106356341Scy PCAP_VERSION_STRING " (packet.dll version %s)", 2107356341Scy PacketGetVersion()) != -1) { 2108356341Scy /* Success */ 2109356341Scy pcap_lib_version_string = full_pcap_version_string; 2110356341Scy } 2111335640Shselasky } 2112335640Shselasky return (pcap_lib_version_string); 2113335640Shselasky} 2114335640Shselasky#endif /* HAVE_VERSION_H */ 2115