summaryrefslogtreecommitdiffstats
path: root/contrib/libpcap/pcap-win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libpcap/pcap-win32.c')
-rw-r--r--contrib/libpcap/pcap-win32.c195
1 files changed, 147 insertions, 48 deletions
diff --git a/contrib/libpcap/pcap-win32.c b/contrib/libpcap/pcap-win32.c
index 130a442..f63b5c4 100644
--- a/contrib/libpcap/pcap-win32.c
+++ b/contrib/libpcap/pcap-win32.c
@@ -31,11 +31,6 @@
*
*/
-#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__
@@ -72,6 +67,19 @@ static int pcap_setnonblock_win32(pcap_t *, int, char *);
#define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8)
/*
+ * Private data for capturing on WinPcap devices.
+ */
+struct pcap_win {
+ int nonblock;
+
+ int filtering_in_kernel; /* using kernel filter */
+
+#ifdef HAVE_DAG_API
+ int dag_fcs_bits; /* Number of checksum bits from link layer */
+#endif
+};
+
+/*
* Header that the WinPcap driver associates to the packets.
* Once was in bpf.h
*/
@@ -105,16 +113,27 @@ wsockinit()
{
WORD wVersionRequested;
WSADATA wsaData;
- int err;
+ static int err = -1;
+ static int done = 0;
+
+ if (done)
+ return err;
+
wVersionRequested = MAKEWORD( 1, 1);
err = WSAStartup( wVersionRequested, &wsaData );
+ atexit ((void(*)(void))WSACleanup);
+ InitializeCriticalSection(&g_PcapCompileCriticalSection);
+ done = 1;
+
if ( err != 0 )
- {
- return -1;
- }
- return 0;
+ err = -1;
+ return err;
}
+int pcap_wsockinit()
+{
+ return wsockinit();
+}
static int
pcap_stats_win32(pcap_t *p, struct pcap_stat *ps)
@@ -165,12 +184,21 @@ pcap_setmintocopy_win32(pcap_t *p, int size)
return 0;
}
+/*return the Adapter for a pcap_t*/
+static Adapter *
+pcap_getadapter_win32(pcap_t *p)
+{
+ return p->adapter;
+}
+
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;
+ u_char *datap;
+ struct pcap_win *pw = p->priv;
cc = p->cc;
if (p->cc == 0) {
@@ -180,17 +208,17 @@ pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
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.
+ * has, and return PCAP_ERROR_BREAK to indicate
+ * that we were told to break out of the loop.
*/
p->break_loop = 0;
- return (-2);
+ return (PCAP_ERROR_BREAK);
}
/* capture the packets */
if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
- return (-1);
+ return (PCAP_ERROR);
}
cc = p->Packet->ulBytesReceived;
@@ -211,16 +239,17 @@ pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
/*
* 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.
+ * packets, clear the flag and return PCAP_ERROR_BREAK
+ * 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);
+ return (PCAP_ERROR_BREAK);
} else {
p->bp = bp;
p->cc = ep - bp;
@@ -232,16 +261,35 @@ pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
caplen = bhp->bh_caplen;
hdrlen = bhp->bh_hdrlen;
+ datap = bp + hdrlen;
/*
- * XXX A bpf_hdr matches a pcap_pkthdr.
+ * Short-circuit evaluation: if using BPF filter
+ * in kernel, no need to do it now - we already know
+ * the packet passed the filter.
+ *
+ * XXX - bpf_filter() should always return TRUE if
+ * handed a null pointer for the program, but it might
+ * just try to "run" the filter, so we check here.
*/
- (*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);
+ if (pw->filtering_in_kernel ||
+ p->fcode.bf_insns == NULL ||
+ bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) {
+ /*
+ * XXX A bpf_hdr matches a pcap_pkthdr.
+ */
+ (*callback)(user, (struct pcap_pkthdr*)bp, datap);
+ bp += Packet_WORDALIGN(caplen + hdrlen);
+ if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
+ p->bp = bp;
+ p->cc = ep - bp;
+ return (n);
+ }
+ } else {
+ /*
+ * Skip this packet.
+ */
+ bp += Packet_WORDALIGN(caplen + hdrlen);
}
}
#undef bhp
@@ -253,6 +301,7 @@ pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
static int
pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
+ struct pcap_win *pw = p->priv;
u_char *dp = NULL;
int packet_len = 0, caplen = 0;
struct pcap_pkthdr pcap_header;
@@ -295,7 +344,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
break;
/* Increase the number of captured packets */
- p->md.stat.ps_recv++;
+ pw->stat.ps_recv++;
/* Find the beginning of the packet */
dp = ((u_char *)header) + dag_record_size;
@@ -312,7 +361,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
case TYPE_ETH:
swt = SWAPS(header->wlen);
- packet_len = swt - (p->md.dag_fcs_bits);
+ packet_len = swt - (pw->dag_fcs_bits);
caplen = erf_record_len - dag_record_size - 2;
if (caplen > packet_len)
{
@@ -324,7 +373,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
case TYPE_HDLC_POS:
swt = SWAPS(header->wlen);
- packet_len = swt - (p->md.dag_fcs_bits);
+ packet_len = swt - (pw->dag_fcs_bits);
caplen = erf_record_len - dag_record_size;
if (caplen > packet_len)
{
@@ -397,7 +446,7 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
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)
+ if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt))
{
p->bp = (char*)header;
p->cc = endofbuf - (char*)header;
@@ -457,6 +506,7 @@ pcap_cleanup_win32(pcap_t *p)
static int
pcap_activate_win32(pcap_t *p)
{
+ struct pcap_win *pw = p->priv;
NetType type;
if (p->opt.rfmon) {
@@ -622,11 +672,23 @@ pcap_activate_win32(pcap_t *p)
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)
+ if (p->opt.immediate)
{
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s", pcap_win32strerror());
- goto bad;
+ /* tell the driver to copy the buffer as soon as data arrives */
+ if(PacketSetMinToCopy(p->adapter,0)==FALSE)
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s", pcap_win32strerror());
+ goto bad;
+ }
+ }
+ else
+ {
+ /* 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
@@ -672,13 +734,13 @@ pcap_activate_win32(pcap_t *p)
/* 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;
+ pw->dag_fcs_bits = p->adapter->DagFcsLen;
}
#else
goto bad;
#endif /* HAVE_DAG_API */
- PacketSetReadTimeout(p->adapter, p->md.timeout);
+ PacketSetReadTimeout(p->adapter, p->opt.timeout);
#ifdef HAVE_DAG_API
if(p->adapter->Flags & INFO_FLAG_DAG_CARD)
@@ -706,6 +768,7 @@ pcap_activate_win32(pcap_t *p)
p->setbuff_op = pcap_setbuff_win32;
p->setmode_op = pcap_setmode_win32;
p->setmintocopy_op = pcap_setmintocopy_win32;
+ p->getadapter_op = pcap_getadapter_win32;
p->cleanup_op = pcap_cleanup_win32;
return (0);
@@ -743,12 +806,12 @@ pcap_create_interface(const char *device, char *ebuf)
}
snprintf(deviceAscii, length + 1, "%ws", (wchar_t*)device);
- p = pcap_create_common(deviceAscii, ebuf);
+ p = pcap_create_common(deviceAscii, ebuf, sizeof (struct pcap_win));
free(deviceAscii);
}
else
{
- p = pcap_create_common(device, ebuf);
+ p = pcap_create_common(device, ebuf, sizeof (struct pcap_win));
}
if (p == NULL)
@@ -761,17 +824,52 @@ pcap_create_interface(const char *device, char *ebuf)
static int
pcap_setfilter_win32_npf(pcap_t *p, struct bpf_program *fp)
{
+ struct pcap_win *pw = p->priv;
+
if(PacketSetBpf(p->adapter,fp)==FALSE){
/*
* Kernel filter not installed.
- * XXX - fall back on userland filtering, as is done
- * on other platforms?
+ *
+ * XXX - we don't know whether this failed because:
+ *
+ * the kernel rejected the filter program as invalid,
+ * in which case we should fall back on userland
+ * filtering;
+ *
+ * the kernel rejected the filter program as too big,
+ * in which case we should again fall back on
+ * userland filtering;
+ *
+ * there was some other problem, in which case we
+ * should probably report an error.
+ *
+ * For NPF devices, the Win32 status will be
+ * STATUS_INVALID_DEVICE_REQUEST for invalid
+ * filters, but I don't know what it'd be for
+ * other problems, and for some other devices
+ * it might not be set at all.
+ *
+ * So we just fall back on userland filtering in
+ * all cases.
*/
- snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Driver error: cannot set bpf filter: %s", pcap_win32strerror());
- return (-1);
+
+ /*
+ * install_bpf_program() validates the program.
+ *
+ * XXX - what if we already have a filter in the kernel?
+ */
+ if (install_bpf_program(p, fp) < 0)
+ return (-1);
+ pw->filtering_in_kernel = 0; /* filtering in userland */
+ return (0);
}
/*
+ * It worked.
+ */
+ pw->filtering_in_kernel = 1; /* filtering in the kernel */
+
+ /*
* 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
@@ -801,25 +899,26 @@ pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) {
return -1;
}
- p->md.use_bpf = 0;
-
return (0);
}
static int
pcap_getnonblock_win32(pcap_t *p, char *errbuf)
{
+ struct pcap_win *pw = p->priv;
+
/*
* 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);
+ return (pw->nonblock);
}
static int
pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf)
{
+ struct pcap_win *pw = p->priv;
int newtimeout;
if (nonblock) {
@@ -833,14 +932,14 @@ pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf)
* (Note that this may be -1, in which case we're not
* really leaving non-blocking mode.)
*/
- newtimeout = p->md.timeout;
+ newtimeout = p->opt.timeout;
}
if (!PacketSetReadTimeout(p->adapter, newtimeout)) {
snprintf(errbuf, PCAP_ERRBUF_SIZE,
"PacketSetReadTimeout: %s", pcap_win32strerror());
return (-1);
}
- p->nonblock = (newtimeout == -1);
+ pw->nonblock = (newtimeout == -1);
return (0);
}
OpenPOWER on IntegriCloud