]> The Tcpdump Group git mirrors - libpcap/blob - pcap-win32.c
Add a "pcap_breakloop()" API to break out of the loop in
[libpcap] / pcap-win32.c
1 /*
2 * Copyright (c) 1999 - 2003
3 * NetGroup, Politecnico di Torino (Italy)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33 #ifndef lint
34 static const char rcsid[] =
35 "@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.15 2003-11-04 07:05:37 guy Exp $ (LBL)";
36 #endif
37
38 #include <pcap-int.h>
39 #include <packet32.h>
40 #include <Ntddndis.h>
41 #ifdef __MINGW32__
42 int* _errno();
43 #define errno (*_errno())
44 #endif /* __MINGW32__ */
45
46 static int pcap_setfilter_win32(pcap_t *, struct bpf_program *);
47
48 #define PcapBufSize 256000 /*dimension of the buffer in the pcap_t structure*/
49 #define SIZE_BUF 1000000
50
51 /*
52 * Header that the WinPcap driver associates to the packets.
53 * Once was in bpf.h
54 */
55 struct bpf_hdr {
56 struct timeval bh_tstamp; /* time stamp */
57 bpf_u_int32 bh_caplen; /* length of captured portion */
58 bpf_u_int32 bh_datalen; /* original length of packet */
59 u_short bh_hdrlen; /* length of bpf header (this struct
60 plus alignment padding) */
61 };
62
63 /* Start winsock */
64 int
65 wsockinit()
66 {
67 WORD wVersionRequested;
68 WSADATA wsaData;
69 int err;
70 wVersionRequested = MAKEWORD( 1, 1);
71 err = WSAStartup( wVersionRequested, &wsaData );
72 if ( err != 0 )
73 {
74 return -1;
75 }
76 return 0;
77 }
78
79
80 static int
81 pcap_stats_win32(pcap_t *p, struct pcap_stat *ps)
82 {
83
84 if(PacketGetStats(p->adapter, (struct bpf_stat*)ps) != TRUE){
85 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStats error: %s", pcap_win32strerror());
86 return -1;
87 }
88
89 return 0;
90 }
91
92 static int
93 pcap_read_win32(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
94 {
95 int cc;
96 int n = 0;
97 register u_char *bp, *ep;
98
99 cc = p->cc;
100 if (p->cc == 0) {
101
102 /* capture the packets */
103 if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){
104 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
105 return (-1);
106 }
107
108 cc = p->Packet->ulBytesReceived;
109
110 bp = p->Packet->Buffer;
111 }
112 else
113 bp = p->bp;
114
115 /*
116 * Loop through each packet.
117 */
118 #define bhp ((struct bpf_hdr *)bp)
119 ep = bp + cc;
120 while (bp < ep) {
121 register int caplen, hdrlen;
122
123 /*
124 * Has "pcap_breakloop()" been called?
125 * If so, return immediately - if we haven't read any
126 * packets, clear the flag and return -2 to indicate
127 * that we were told to break out of the loop, otherwise
128 * leave the flag set, so that the *next* call will break
129 * out of the loop without having read any packets, and
130 * return the number of packets we've processed so far.
131 */
132 if (p->break_loop) {
133 if (n == 0) {
134 p->break_loop = 0;
135 return (-2);
136 } else {
137 p->bp = bp;
138 p->cc = ep - bp;
139 return (n);
140 }
141 }
142
143 caplen = bhp->bh_caplen;
144 hdrlen = bhp->bh_hdrlen;
145
146 /*
147 * XXX A bpf_hdr matches a pcap_pkthdr.
148 */
149 (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
150 bp += BPF_WORDALIGN(caplen + hdrlen);
151 if (++n >= cnt && cnt > 0) {
152 p->bp = bp;
153 p->cc = ep - bp;
154 return (n);
155 }
156 }
157 #undef bhp
158 p->cc = 0;
159 return (n);
160 }
161
162
163 static void
164 pcap_close_win32(pcap_t *p)
165 {
166 if (p->buffer != NULL)
167 free(p->buffer);
168 if (p->adapter != NULL) {
169 PacketCloseAdapter(p->adapter);
170 p->adapter = NULL;
171 }
172 }
173
174 pcap_t *
175 pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
176 char *ebuf)
177 {
178 register pcap_t *p;
179 NetType type;
180
181 /* Init WinSock */
182 wsockinit();
183
184 p = (pcap_t *)malloc(sizeof(*p));
185 if (p == NULL)
186 {
187 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
188 return (NULL);
189 }
190 memset(p, 0, sizeof(*p));
191 p->adapter=NULL;
192
193 p->adapter = PacketOpenAdapter((char*)device);
194
195 if (p->adapter == NULL)
196 {
197 /* Adapter detected but we are not able to open it. Return failure. */
198 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror());
199 return NULL;
200 }
201
202 /*get network type*/
203 if(PacketGetNetType (p->adapter,&type) == FALSE)
204 {
205 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror());
206 goto bad;
207 }
208
209 /*Set the linktype*/
210 switch (type.LinkType)
211 {
212 case NdisMediumWan:
213 p->linktype = DLT_EN10MB;
214 break;
215
216 case NdisMedium802_3:
217 p->linktype = DLT_EN10MB;
218 break;
219
220 case NdisMediumFddi:
221 p->linktype = DLT_FDDI;
222 break;
223
224 case NdisMedium802_5:
225 p->linktype = DLT_IEEE802;
226 break;
227
228 case NdisMediumArcnetRaw:
229 p->linktype = DLT_ARCNET;
230 break;
231
232 case NdisMediumArcnet878_2:
233 p->linktype = DLT_ARCNET;
234 break;
235
236 case NdisMediumAtm:
237 p->linktype = DLT_ATM_RFC1483;
238 break;
239
240 default:
241 p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/
242 break;
243 }
244
245 /* Set promisquous mode */
246 if (promisc) PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS);
247 else PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL);
248
249 /* Set the buffer size */
250 p->bufsize = PcapBufSize;
251
252 p->buffer = (u_char *)malloc(PcapBufSize);
253 if (p->buffer == NULL)
254 {
255 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
256 goto bad;
257 }
258
259 p->snapshot = snaplen;
260
261 /* allocate Packet structure used during the capture */
262 if((p->Packet = PacketAllocatePacket())==NULL)
263 {
264 snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure");
265 goto bad;
266 }
267
268 PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize);
269
270 /* allocate the standard buffer in the driver */
271 if(PacketSetBuff( p->adapter, SIZE_BUF)==FALSE)
272 {
273 snprintf(ebuf, PCAP_ERRBUF_SIZE,"driver error: not enough memory to allocate the kernel buffer\n");
274 goto bad;
275 }
276
277 /* tell the driver to copy the buffer only if it contains at least 16K */
278 if(PacketSetMinToCopy(p->adapter,16000)==FALSE)
279 {
280 snprintf(ebuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s\n", pcap_win32strerror());
281 goto bad;
282 }
283
284 PacketSetReadTimeout(p->adapter, to_ms);
285
286 p->read_op = pcap_read_win32;
287 p->setfilter_op = pcap_setfilter_win32;
288 p->set_datalink_op = NULL; /* can't change data link type */
289 p->stats_op = pcap_stats_win32;
290 p->close_op = pcap_close_win32;
291
292 return (p);
293 bad:
294 if (p->adapter)
295 PacketCloseAdapter(p->adapter);
296 if (p->buffer != NULL)
297 free(p->buffer);
298 free(p);
299 return (NULL);
300 }
301
302
303 static int
304 pcap_setfilter_win32(pcap_t *p, struct bpf_program *fp)
305 {
306 if(PacketSetBpf(p->adapter,fp)==FALSE){
307 /* kernel filter not installed. */
308 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Driver error: cannot set bpf filter: %s", pcap_win32strerror());
309 return (-1);
310 }
311 return (0);
312 }
313
314
315 /* Set the driver working mode */
316 int
317 pcap_setmode(pcap_t *p, int mode){
318
319 if (p->adapter==NULL)
320 {
321 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode while reading from a file");
322 return -1;
323 }
324
325 if(PacketSetMode(p->adapter,mode)==FALSE)
326 {
327 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
328 return -1;
329 }
330
331 return 0;
332 }
333
334 /* Send a packet to the network */
335 int
336 pcap_sendpacket(pcap_t *p, u_char *buf, int size){
337 LPPACKET PacketToSend;
338
339 if (p->adapter==NULL)
340 {
341 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Writing a packet is allowed only on a physical adapter");
342 return -1;
343 }
344
345 PacketToSend=PacketAllocatePacket();
346 PacketInitPacket(PacketToSend,buf,size);
347 if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){
348 PacketFreePacket(PacketToSend);
349 return -1;
350 }
351
352 PacketFreePacket(PacketToSend);
353 return 0;
354 }
355
356 /* Set the dimension of the kernel-level capture buffer */
357 int
358 pcap_setbuff(pcap_t *p, int dim)
359 {
360 if (p->adapter==NULL)
361 {
362 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set while reading from a file");
363 return -1;
364 }
365
366 if(PacketSetBuff(p->adapter,dim)==FALSE)
367 {
368 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
369 return -1;
370 }
371 return 0;
372 }
373
374 /*set the minimum amount of data that will release a read call*/
375 int
376 pcap_setmintocopy(pcap_t *p, int size)
377 {
378 if (p->adapter==NULL)
379 {
380 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Impossible to set the mintocopy parameter on an offline capture");
381 return -1;
382 }
383
384 if(PacketSetMinToCopy(p->adapter, size)==FALSE)
385 {
386 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
387 return -1;
388 }
389 return 0;
390 }