| /* |
| * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) |
| * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the Politecnico di Torino, CACE Technologies |
| * nor the names of its contributors may be used to endorse or promote |
| * products derived from this software without specific prior written |
| * permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| */ |
| |
| #ifndef lint |
| static const char rcsid[] _U_ = |
| "@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.42 2008-05-21 22:15:25 gianluca Exp $ (LBL)"; |
| #endif |
| |
| #include <pcap-int.h> |
| #include <Packet32.h> |
| #ifdef __MINGW32__ |
| #ifdef __MINGW64__ |
| #include <ntddndis.h> |
| #else /*__MINGW64__*/ |
| #include <ddk/ntddndis.h> |
| #include <ddk/ndis.h> |
| #endif /*__MINGW64__*/ |
| #else /*__MINGW32__*/ |
| #include <ntddndis.h> |
| #endif /*__MINGW32__*/ |
| #ifdef HAVE_DAG_API |
| #include <dagnew.h> |
| #include <dagapi.h> |
| #endif /* HAVE_DAG_API */ |
| #ifdef __MINGW32__ |
| int* _errno(); |
| #define errno (*_errno()) |
| #endif /* __MINGW32__ */ |
| |
| static int pcap_setfilter_win32_npf(pcap_t *, struct bpf_program *); |
| static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *); |
| static int pcap_getnonblock_win32(pcap_t *, char *); |
| static int pcap_setnonblock_win32(pcap_t *, int, char *); |
| |
| /*dimension of the buffer in the pcap_t structure*/ |
| #define WIN32_DEFAULT_USER_BUFFER_SIZE 256000 |
| |
| /*dimension of the buffer in the kernel driver NPF */ |
| #define WIN32_DEFAULT_KERNEL_BUFFER_SIZE 1000000 |
| |
| /* Equivalent to ntohs(), but a lot faster under Windows */ |
| #define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) |
| |
| /* |
| * Header that the WinPcap driver associates to the packets. |
| * Once was in bpf.h |
| */ |
| struct bpf_hdr { |
| struct timeval bh_tstamp; /* time stamp */ |
| bpf_u_int32 bh_caplen; /* length of captured portion */ |
| bpf_u_int32 bh_datalen; /* original length of packet */ |
| u_short bh_hdrlen; /* length of bpf header (this struct |
| plus alignment padding) */ |
| }; |
| |
| CRITICAL_SECTION g_PcapCompileCriticalSection; |
| |
| BOOL WINAPI DllMain( |
| HANDLE hinstDLL, |
| DWORD dwReason, |
| LPVOID lpvReserved |
| ) |
| { |
| if (dwReason == DLL_PROCESS_ATTACH) |
| { |
| InitializeCriticalSection(&g_PcapCompileCriticalSection); |
| } |
| |
| return TRUE; |
| } |
| |
| /* Start winsock */ |
| int |
| wsockinit() |
| { |
| WORD wVersionRequested; |
| WSADATA wsaData; |
| int err; |
| wVersionRequested = MAKEWORD( 1, 1); |
| err = WSAStartup( wVersionRequested, &wsaData ); |
| if ( err != 0 ) |
| { |
| return -1; |
| } |
| return 0; |
| } |
| |
| |
| static int |
| pcap_stats_win32(pcap_t *p, struct pcap_stat *ps) |
| { |
| |
| if(PacketGetStats(p->adapter, (struct bpf_stat*)ps) != TRUE){ |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStats error: %s", pcap_win32strerror()); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /* Set the dimension of the kernel-level capture buffer */ |
| static int |
| pcap_setbuff_win32(pcap_t *p, int dim) |
| { |
| if(PacketSetBuff(p->adapter,dim)==FALSE) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| /* Set the driver working mode */ |
| static int |
| pcap_setmode_win32(pcap_t *p, int mode) |
| { |
| if(PacketSetMode(p->adapter,mode)==FALSE) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| /*set the minimum amount of data that will release a read call*/ |
| static int |
| pcap_setmintocopy_win32(pcap_t *p, int size) |
| { |
| if(PacketSetMinToCopy(p->adapter, size)==FALSE) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| static int |
| pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) |
| { |
| int cc; |
| int n = 0; |
| register u_char *bp, *ep; |
| |
| cc = p->cc; |
| if (p->cc == 0) { |
| /* |
| * Has "pcap_breakloop()" been called? |
| */ |
| if (p->break_loop) { |
| /* |
| * Yes - clear the flag that indicates that it |
| * has, and return -2 to indicate that we were |
| * told to break out of the loop. |
| */ |
| p->break_loop = 0; |
| return (-2); |
| } |
| |
| /* capture the packets */ |
| if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){ |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); |
| return (-1); |
| } |
| |
| cc = p->Packet->ulBytesReceived; |
| |
| bp = p->Packet->Buffer; |
| } |
| else |
| bp = p->bp; |
| |
| /* |
| * Loop through each packet. |
| */ |
| #define bhp ((struct bpf_hdr *)bp) |
| ep = bp + cc; |
| while (1) { |
| register int caplen, hdrlen; |
| |
| /* |
| * Has "pcap_breakloop()" been called? |
| * If so, return immediately - if we haven't read any |
| * packets, clear the flag and return -2 to indicate |
| * that we were told to break out of the loop, otherwise |
| * leave the flag set, so that the *next* call will break |
| * out of the loop without having read any packets, and |
| * return the number of packets we've processed so far. |
| */ |
| if (p->break_loop) { |
| if (n == 0) { |
| p->break_loop = 0; |
| return (-2); |
| } else { |
| p->bp = bp; |
| p->cc = ep - bp; |
| return (n); |
| } |
| } |
| if (bp >= ep) |
| break; |
| |
| caplen = bhp->bh_caplen; |
| hdrlen = bhp->bh_hdrlen; |
| |
| /* |
| * XXX A bpf_hdr matches a pcap_pkthdr. |
| */ |
| (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen); |
| bp += Packet_WORDALIGN(caplen + hdrlen); |
| if (++n >= cnt && cnt > 0) { |
| p->bp = bp; |
| p->cc = ep - bp; |
| return (n); |
| } |
| } |
| #undef bhp |
| p->cc = 0; |
| return (n); |
| } |
| |
| #ifdef HAVE_DAG_API |
| static int |
| pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) |
| { |
| u_char *dp = NULL; |
| int packet_len = 0, caplen = 0; |
| struct pcap_pkthdr pcap_header; |
| u_char *endofbuf; |
| int n = 0; |
| dag_record_t *header; |
| unsigned erf_record_len; |
| ULONGLONG ts; |
| int cc; |
| unsigned swt; |
| unsigned dfp = p->adapter->DagFastProcess; |
| |
| cc = p->cc; |
| if (cc == 0) /* Get new packets only if we have processed all the ones of the previous read */ |
| { |
| /* Get new packets from the network */ |
| if(PacketReceivePacket(p->adapter, p->Packet, TRUE)==FALSE){ |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); |
| return (-1); |
| } |
| |
| cc = p->Packet->ulBytesReceived; |
| if(cc == 0) |
| /* The timeout has expired but we no packets arrived */ |
| return 0; |
| header = (dag_record_t*)p->adapter->DagBuffer; |
| } |
| else |
| header = (dag_record_t*)p->bp; |
| |
| endofbuf = (char*)header + cc; |
| |
| /* |
| * Cycle through the packets |
| */ |
| do |
| { |
| erf_record_len = SWAPS(header->rlen); |
| if((char*)header + erf_record_len > endofbuf) |
| break; |
| |
| /* Increase the number of captured packets */ |
| p->md.stat.ps_recv++; |
| |
| /* Find the beginning of the packet */ |
| dp = ((u_char *)header) + dag_record_size; |
| |
| /* Determine actual packet len */ |
| switch(header->type) |
| { |
| case TYPE_ATM: |
| packet_len = ATM_SNAPLEN; |
| caplen = ATM_SNAPLEN; |
| dp += 4; |
| |
| break; |
| |
| case TYPE_ETH: |
| swt = SWAPS(header->wlen); |
| packet_len = swt - (p->md.dag_fcs_bits); |
| caplen = erf_record_len - dag_record_size - 2; |
| if (caplen > packet_len) |
| { |
| caplen = packet_len; |
| } |
| dp += 2; |
| |
| break; |
| |
| case TYPE_HDLC_POS: |
| swt = SWAPS(header->wlen); |
| packet_len = swt - (p->md.dag_fcs_bits); |
| caplen = erf_record_len - dag_record_size; |
| if (caplen > packet_len) |
| { |
| caplen = packet_len; |
| } |
| |
| break; |
| } |
| |
| if(caplen > p->snapshot) |
| caplen = p->snapshot; |
| |
| /* |
| * Has "pcap_breakloop()" been called? |
| * If so, return immediately - if we haven't read any |
| * packets, clear the flag and return -2 to indicate |
| * that we were told to break out of the loop, otherwise |
| * leave the flag set, so that the *next* call will break |
| * out of the loop without having read any packets, and |
| * return the number of packets we've processed so far. |
| */ |
| if (p->break_loop) |
| { |
| if (n == 0) |
| { |
| p->break_loop = 0; |
| return (-2); |
| } |
| else |
| { |
| p->bp = (char*)header; |
| p->cc = endofbuf - (char*)header; |
| return (n); |
| } |
| } |
| |
| if(!dfp) |
| { |
| /* convert between timestamp formats */ |
| ts = header->ts; |
| pcap_header.ts.tv_sec = (int)(ts >> 32); |
| ts = (ts & 0xffffffffi64) * 1000000; |
| ts += 0x80000000; /* rounding */ |
| pcap_header.ts.tv_usec = (int)(ts >> 32); |
| if (pcap_header.ts.tv_usec >= 1000000) { |
| pcap_header.ts.tv_usec -= 1000000; |
| pcap_header.ts.tv_sec++; |
| } |
| } |
| |
| /* No underlaying filtering system. We need to filter on our own */ |
| if (p->fcode.bf_insns) |
| { |
| if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0) |
| { |
| /* Move to next packet */ |
| header = (dag_record_t*)((char*)header + erf_record_len); |
| continue; |
| } |
| } |
| |
| /* Fill the header for the user suppplied callback function */ |
| pcap_header.caplen = caplen; |
| pcap_header.len = packet_len; |
| |
| /* Call the callback function */ |
| (*callback)(user, &pcap_header, dp); |
| |
| /* Move to next packet */ |
| header = (dag_record_t*)((char*)header + erf_record_len); |
| |
| /* Stop if the number of packets requested by user has been reached*/ |
| if (++n >= cnt && cnt > 0) |
| { |
| p->bp = (char*)header; |
| p->cc = endofbuf - (char*)header; |
| return (n); |
| } |
| } |
| while((u_char*)header < endofbuf); |
| |
| return 1; |
| } |
| #endif /* HAVE_DAG_API */ |
| |
| /* Send a packet to the network */ |
| static int |
| pcap_inject_win32(pcap_t *p, const void *buf, size_t size){ |
| LPPACKET PacketToSend; |
| |
| PacketToSend=PacketAllocatePacket(); |
| |
| if (PacketToSend == NULL) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketAllocatePacket failed"); |
| return -1; |
| } |
| |
| PacketInitPacket(PacketToSend,(PVOID)buf,size); |
| if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){ |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed"); |
| PacketFreePacket(PacketToSend); |
| return -1; |
| } |
| |
| PacketFreePacket(PacketToSend); |
| |
| /* |
| * We assume it all got sent if "PacketSendPacket()" succeeded. |
| * "pcap_inject()" is expected to return the number of bytes |
| * sent. |
| */ |
| return size; |
| } |
| |
| static void |
| pcap_cleanup_win32(pcap_t *p) |
| { |
| if (p->adapter != NULL) { |
| PacketCloseAdapter(p->adapter); |
| p->adapter = NULL; |
| } |
| if (p->Packet) { |
| PacketFreePacket(p->Packet); |
| p->Packet = NULL; |
| } |
| pcap_cleanup_live_common(p); |
| } |
| |
| static int |
| pcap_activate_win32(pcap_t *p) |
| { |
| NetType type; |
| |
| if (p->opt.rfmon) { |
| /* |
| * No monitor mode on Windows. It could be done on |
| * Vista with drivers that support the native 802.11 |
| * mechanism and monitor mode. |
| */ |
| return (PCAP_ERROR_RFMON_NOTSUP); |
| } |
| |
| /* Init WinSock */ |
| wsockinit(); |
| |
| p->adapter = PacketOpenAdapter(p->opt.source); |
| |
| if (p->adapter == NULL) |
| { |
| /* Adapter detected but we are not able to open it. Return failure. */ |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror()); |
| return PCAP_ERROR; |
| } |
| |
| /*get network type*/ |
| if(PacketGetNetType (p->adapter,&type) == FALSE) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror()); |
| goto bad; |
| } |
| |
| /*Set the linktype*/ |
| switch (type.LinkType) |
| { |
| case NdisMediumWan: |
| p->linktype = DLT_EN10MB; |
| break; |
| |
| case NdisMedium802_3: |
| p->linktype = DLT_EN10MB; |
| /* |
| * This is (presumably) a real Ethernet capture; give it a |
| * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so |
| * that an application can let you choose it, in case you're |
| * capturing DOCSIS traffic that a Cisco Cable Modem |
| * Termination System is putting out onto an Ethernet (it |
| * doesn't put an Ethernet header onto the wire, it puts raw |
| * DOCSIS frames out on the wire inside the low-level |
| * Ethernet framing). |
| */ |
| p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); |
| /* |
| * If that fails, just leave the list empty. |
| */ |
| if (p->dlt_list != NULL) { |
| p->dlt_list[0] = DLT_EN10MB; |
| p->dlt_list[1] = DLT_DOCSIS; |
| p->dlt_count = 2; |
| } |
| break; |
| |
| case NdisMediumFddi: |
| p->linktype = DLT_FDDI; |
| break; |
| |
| case NdisMedium802_5: |
| p->linktype = DLT_IEEE802; |
| break; |
| |
| case NdisMediumArcnetRaw: |
| p->linktype = DLT_ARCNET; |
| break; |
| |
| case NdisMediumArcnet878_2: |
| p->linktype = DLT_ARCNET; |
| break; |
| |
| case NdisMediumAtm: |
| p->linktype = DLT_ATM_RFC1483; |
| break; |
| |
| case NdisMediumCHDLC: |
| p->linktype = DLT_CHDLC; |
| break; |
| |
| case NdisMediumPPPSerial: |
| p->linktype = DLT_PPP_SERIAL; |
| break; |
| |
| case NdisMediumNull: |
| p->linktype = DLT_NULL; |
| break; |
| |
| case NdisMediumBare80211: |
| p->linktype = DLT_IEEE802_11; |
| break; |
| |
| case NdisMediumRadio80211: |
| p->linktype = DLT_IEEE802_11_RADIO; |
| break; |
| |
| case NdisMediumPpi: |
| p->linktype = DLT_PPI; |
| break; |
| |
| default: |
| p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/ |
| break; |
| } |
| |
| /* Set promiscuous mode */ |
| if (p->opt.promisc) |
| { |
| |
| if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode"); |
| goto bad; |
| } |
| } |
| else |
| { |
| if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode"); |
| goto bad; |
| } |
| } |
| |
| /* Set the buffer size */ |
| p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE; |
| |
| /* allocate Packet structure used during the capture */ |
| if((p->Packet = PacketAllocatePacket())==NULL) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure"); |
| goto bad; |
| } |
| |
| if(!(p->adapter->Flags & INFO_FLAG_DAG_CARD)) |
| { |
| /* |
| * Traditional Adapter |
| */ |
| /* |
| * If the buffer size wasn't explicitly set, default to |
| * WIN32_DEFAULT_USER_BUFFER_SIZE. |
| */ |
| if (p->opt.buffer_size == 0) |
| p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE; |
| |
| if(PacketSetBuff(p->adapter,p->opt.buffer_size)==FALSE) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); |
| goto bad; |
| } |
| |
| p->buffer = (u_char *)malloc(p->bufsize); |
| if (p->buffer == NULL) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); |
| goto bad; |
| } |
| |
| PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize); |
| |
| /* tell the driver to copy the buffer only if it contains at least 16K */ |
| if(PacketSetMinToCopy(p->adapter,16000)==FALSE) |
| { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s", pcap_win32strerror()); |
| goto bad; |
| } |
| } |
| else |
| #ifdef HAVE_DAG_API |
| { |
| /* |
| * Dag Card |
| */ |
| LONG status; |
| HKEY dagkey; |
| DWORD lptype; |
| DWORD lpcbdata; |
| int postype = 0; |
| char keyname[512]; |
| |
| snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s", |
| "SYSTEM\\CurrentControlSet\\Services\\DAG", |
| strstr(_strlwr(p->opt.source), "dag")); |
| do |
| { |
| status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey); |
| if(status != ERROR_SUCCESS) |
| break; |
| |
| status = RegQueryValueEx(dagkey, |
| "PosType", |
| NULL, |
| &lptype, |
| (char*)&postype, |
| &lpcbdata); |
| |
| if(status != ERROR_SUCCESS) |
| { |
| postype = 0; |
| } |
| |
| RegCloseKey(dagkey); |
| } |
| while(FALSE); |
| |
| |
| p->snapshot = PacketSetSnapLen(p->adapter, snaplen); |
| |
| /* Set the length of the FCS associated to any packet. This value |
| * will be subtracted to the packet length */ |
| p->md.dag_fcs_bits = p->adapter->DagFcsLen; |
| } |
| #else |
| goto bad; |
| #endif /* HAVE_DAG_API */ |
| |
| PacketSetReadTimeout(p->adapter, p->md.timeout); |
| |
| #ifdef HAVE_DAG_API |
| if(p->adapter->Flags & INFO_FLAG_DAG_CARD) |
| { |
| /* install dag specific handlers for read and setfilter */ |
| p->read_op = pcap_read_win32_dag; |
| p->setfilter_op = pcap_setfilter_win32_dag; |
| } |
| else |
| { |
| #endif /* HAVE_DAG_API */ |
| /* install traditional npf handlers for read and setfilter */ |
| p->read_op = pcap_read_win32_npf; |
| p->setfilter_op = pcap_setfilter_win32_npf; |
| #ifdef HAVE_DAG_API |
| } |
| #endif /* HAVE_DAG_API */ |
| p->setdirection_op = NULL; /* Not implemented. */ |
| /* XXX - can this be implemented on some versions of Windows? */ |
| p->inject_op = pcap_inject_win32; |
| p->set_datalink_op = NULL; /* can't change data link type */ |
| p->getnonblock_op = pcap_getnonblock_win32; |
| p->setnonblock_op = pcap_setnonblock_win32; |
| p->stats_op = pcap_stats_win32; |
| p->setbuff_op = pcap_setbuff_win32; |
| p->setmode_op = pcap_setmode_win32; |
| p->setmintocopy_op = pcap_setmintocopy_win32; |
| p->cleanup_op = pcap_cleanup_win32; |
| |
| return (0); |
| bad: |
| pcap_cleanup_win32(p); |
| return (PCAP_ERROR); |
| } |
| |
| pcap_t * |
| pcap_create(const char *device, char *ebuf) |
| { |
| pcap_t *p; |
| |
| if (strlen(device) == 1) |
| { |
| /* |
| * It's probably a unicode string |
| * Convert to ascii and pass it to pcap_create_common |
| * |
| * This wonderful hack is needed because pcap_lookupdev still returns |
| * unicode strings, and it's used by windump when no device is specified |
| * in the command line |
| */ |
| size_t length; |
| char* deviceAscii; |
| |
| length = wcslen((wchar_t*)device); |
| |
| deviceAscii = (char*)malloc(length + 1); |
| |
| if (deviceAscii == NULL) |
| { |
| snprintf(ebuf, PCAP_ERRBUF_SIZE, "Malloc failed"); |
| return NULL; |
| } |
| |
| snprintf(deviceAscii, length + 1, "%ws", (wchar_t*)device); |
| p = pcap_create_common(deviceAscii, ebuf); |
| free(deviceAscii); |
| } |
| else |
| { |
| p = pcap_create_common(device, ebuf); |
| } |
| |
| if (p == NULL) |
| return (NULL); |
| |
| p->activate_op = pcap_activate_win32; |
| return (p); |
| } |
| |
| static int |
| pcap_setfilter_win32_npf(pcap_t *p, struct bpf_program *fp) |
| { |
| if(PacketSetBpf(p->adapter,fp)==FALSE){ |
| /* |
| * Kernel filter not installed. |
| * XXX - fall back on userland filtering, as is done |
| * on other platforms? |
| */ |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Driver error: cannot set bpf filter: %s", pcap_win32strerror()); |
| return (-1); |
| } |
| |
| /* |
| * Discard any previously-received packets, as they might have |
| * passed whatever filter was formerly in effect, but might |
| * not pass this filter (BIOCSETF discards packets buffered |
| * in the kernel, so you can lose packets in any case). |
| */ |
| p->cc = 0; |
| return (0); |
| } |
| |
| /* |
| * We filter at user level, since the kernel driver does't process the packets |
| */ |
| static int |
| pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) { |
| |
| if(!fp) |
| { |
| strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); |
| return -1; |
| } |
| |
| /* Install a user level filter */ |
| if (install_bpf_program(p, fp) < 0) |
| { |
| snprintf(p->errbuf, sizeof(p->errbuf), |
| "setfilter, unable to install the filter: %s", pcap_strerror(errno)); |
| return -1; |
| } |
| |
| p->md.use_bpf = 0; |
| |
| return (0); |
| } |
| |
| static int |
| pcap_getnonblock_win32(pcap_t *p, char *errbuf) |
| { |
| /* |
| * XXX - if there were a PacketGetReadTimeout() call, we |
| * would use it, and return 1 if the timeout is -1 |
| * and 0 otherwise. |
| */ |
| return (p->nonblock); |
| } |
| |
| static int |
| pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf) |
| { |
| int newtimeout; |
| |
| if (nonblock) { |
| /* |
| * Set the read timeout to -1 for non-blocking mode. |
| */ |
| newtimeout = -1; |
| } else { |
| /* |
| * Restore the timeout set when the device was opened. |
| * (Note that this may be -1, in which case we're not |
| * really leaving non-blocking mode.) |
| */ |
| newtimeout = p->md.timeout; |
| } |
| if (!PacketSetReadTimeout(p->adapter, newtimeout)) { |
| snprintf(p->errbuf, PCAP_ERRBUF_SIZE, |
| "PacketSetReadTimeout: %s", pcap_win32strerror()); |
| return (-1); |
| } |
| p->nonblock = (newtimeout == -1); |
| return (0); |
| } |
| |
| /*platform-dependent routine to add devices other than NDIS interfaces*/ |
| int |
| pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) |
| { |
| return (0); |
| } |