]> The Tcpdump Group git mirrors - libpcap/blob - pcap-win32.c
1bf18afaa3d5f8d2d2be34ae0d48c00736f835a7
[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.14 2003-09-22 11:48:40 risso 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 caplen = bhp->bh_caplen;
123 hdrlen = bhp->bh_hdrlen;
124
125 /*
126 * XXX A bpf_hdr matches a pcap_pkthdr.
127 */
128 (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
129 bp += BPF_WORDALIGN(caplen + hdrlen);
130 if (++n >= cnt && cnt > 0) {
131 p->bp = bp;
132 p->cc = ep - bp;
133 return (n);
134 }
135 }
136 #undef bhp
137 p->cc = 0;
138 return (n);
139 }
140
141
142 static void
143 pcap_close_win32(pcap_t *p)
144 {
145 if (p->buffer != NULL)
146 free(p->buffer);
147 if (p->adapter != NULL) {
148 PacketCloseAdapter(p->adapter);
149 p->adapter = NULL;
150 }
151 }
152
153 pcap_t *
154 pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
155 char *ebuf)
156 {
157 register pcap_t *p;
158 NetType type;
159
160 /* Init WinSock */
161 wsockinit();
162
163 p = (pcap_t *)malloc(sizeof(*p));
164 if (p == NULL)
165 {
166 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
167 return (NULL);
168 }
169 memset(p, 0, sizeof(*p));
170 p->adapter=NULL;
171
172 p->adapter = PacketOpenAdapter((char*)device);
173
174 if (p->adapter == NULL)
175 {
176 /* Adapter detected but we are not able to open it. Return failure. */
177 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror());
178 return NULL;
179 }
180
181 /*get network type*/
182 if(PacketGetNetType (p->adapter,&type) == FALSE)
183 {
184 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror());
185 goto bad;
186 }
187
188 /*Set the linktype*/
189 switch (type.LinkType)
190 {
191 case NdisMediumWan:
192 p->linktype = DLT_EN10MB;
193 break;
194
195 case NdisMedium802_3:
196 p->linktype = DLT_EN10MB;
197 break;
198
199 case NdisMediumFddi:
200 p->linktype = DLT_FDDI;
201 break;
202
203 case NdisMedium802_5:
204 p->linktype = DLT_IEEE802;
205 break;
206
207 case NdisMediumArcnetRaw:
208 p->linktype = DLT_ARCNET;
209 break;
210
211 case NdisMediumArcnet878_2:
212 p->linktype = DLT_ARCNET;
213 break;
214
215 case NdisMediumAtm:
216 p->linktype = DLT_ATM_RFC1483;
217 break;
218
219 default:
220 p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/
221 break;
222 }
223
224 /* Set promisquous mode */
225 if (promisc) PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS);
226 else PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL);
227
228 /* Set the buffer size */
229 p->bufsize = PcapBufSize;
230
231 p->buffer = (u_char *)malloc(PcapBufSize);
232 if (p->buffer == NULL)
233 {
234 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
235 goto bad;
236 }
237
238 p->snapshot = snaplen;
239
240 /* allocate Packet structure used during the capture */
241 if((p->Packet = PacketAllocatePacket())==NULL)
242 {
243 snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure");
244 goto bad;
245 }
246
247 PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize);
248
249 /* allocate the standard buffer in the driver */
250 if(PacketSetBuff( p->adapter, SIZE_BUF)==FALSE)
251 {
252 snprintf(ebuf, PCAP_ERRBUF_SIZE,"driver error: not enough memory to allocate the kernel buffer\n");
253 goto bad;
254 }
255
256 /* tell the driver to copy the buffer only if it contains at least 16K */
257 if(PacketSetMinToCopy(p->adapter,16000)==FALSE)
258 {
259 snprintf(ebuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s\n", pcap_win32strerror());
260 goto bad;
261 }
262
263 PacketSetReadTimeout(p->adapter, to_ms);
264
265 p->read_op = pcap_read_win32;
266 p->setfilter_op = pcap_setfilter_win32;
267 p->set_datalink_op = NULL; /* can't change data link type */
268 p->stats_op = pcap_stats_win32;
269 p->close_op = pcap_close_win32;
270
271 return (p);
272 bad:
273 if (p->adapter)
274 PacketCloseAdapter(p->adapter);
275 if (p->buffer != NULL)
276 free(p->buffer);
277 free(p);
278 return (NULL);
279 }
280
281
282 static int
283 pcap_setfilter_win32(pcap_t *p, struct bpf_program *fp)
284 {
285 if(PacketSetBpf(p->adapter,fp)==FALSE){
286 /* kernel filter not installed. */
287 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Driver error: cannot set bpf filter: %s", pcap_win32strerror());
288 return (-1);
289 }
290 return (0);
291 }
292
293
294 /* Set the driver working mode */
295 int
296 pcap_setmode(pcap_t *p, int mode){
297
298 if (p->adapter==NULL)
299 {
300 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode while reading from a file");
301 return -1;
302 }
303
304 if(PacketSetMode(p->adapter,mode)==FALSE)
305 {
306 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
307 return -1;
308 }
309
310 return 0;
311 }
312
313 /* Send a packet to the network */
314 int
315 pcap_sendpacket(pcap_t *p, u_char *buf, int size){
316 LPPACKET PacketToSend;
317
318 if (p->adapter==NULL)
319 {
320 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Writing a packet is allowed only on a physical adapter");
321 return -1;
322 }
323
324 PacketToSend=PacketAllocatePacket();
325 PacketInitPacket(PacketToSend,buf,size);
326 if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){
327 PacketFreePacket(PacketToSend);
328 return -1;
329 }
330
331 PacketFreePacket(PacketToSend);
332 return 0;
333 }
334
335 /* Set the dimension of the kernel-level capture buffer */
336 int
337 pcap_setbuff(pcap_t *p, int dim)
338 {
339 if (p->adapter==NULL)
340 {
341 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set while reading from a file");
342 return -1;
343 }
344
345 if(PacketSetBuff(p->adapter,dim)==FALSE)
346 {
347 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
348 return -1;
349 }
350 return 0;
351 }
352
353 /*set the minimum amount of data that will release a read call*/
354 int
355 pcap_setmintocopy(pcap_t *p, int size)
356 {
357 if (p->adapter==NULL)
358 {
359 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Impossible to set the mintocopy parameter on an offline capture");
360 return -1;
361 }
362
363 if(PacketSetMinToCopy(p->adapter, size)==FALSE)
364 {
365 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
366 return -1;
367 }
368 return 0;
369 }