]> The Tcpdump Group git mirrors - libpcap/blob - pcap-win32.c
c71e86c35f6770cd08e073e1f59a2d1b5101ce5f
[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.10 2003-07-25 04:04:59 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 #define PcapBufSize 256000 /*dimension of the buffer in the pcap_t structure*/
47 #define SIZE_BUF 1000000
48
49 /*
50 * Header that the WinPcap driver associates to the packets.
51 * Once was in bpf.h
52 */
53 struct bpf_hdr {
54 struct timeval bh_tstamp; /* time stamp */
55 bpf_u_int32 bh_caplen; /* length of captured portion */
56 bpf_u_int32 bh_datalen; /* original length of packet */
57 u_short bh_hdrlen; /* length of bpf header (this struct
58 plus alignment padding) */
59 };
60
61 /* Start winsock */
62 int
63 wsockinit()
64 {
65 WORD wVersionRequested;
66 WSADATA wsaData;
67 int err;
68 wVersionRequested = MAKEWORD( 1, 1);
69 err = WSAStartup( wVersionRequested, &wsaData );
70 if ( err != 0 )
71 {
72 return -1;
73 }
74 return 0;
75 }
76
77
78 static int
79 pcap_stats_win32(pcap_t *p, struct pcap_stat *ps)
80 {
81
82 if(PacketGetStats(p->adapter, (struct bpf_stat*)ps) != TRUE){
83 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStats error: %s", pcap_win32strerror());
84 return -1;
85 }
86
87 return 0;
88 }
89
90 int
91 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
92 {
93 int cc;
94 int n = 0;
95 register u_char *bp, *ep;
96
97 cc = p->cc;
98 if (p->cc == 0) {
99
100 /* capture the packets */
101 if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){
102 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed");
103 return (-1);
104 }
105
106 cc = p->Packet->ulBytesReceived;
107
108 bp = p->Packet->Buffer;
109 }
110 else
111 bp = p->bp;
112
113 /*
114 * Loop through each packet.
115 */
116 #define bhp ((struct bpf_hdr *)bp)
117 ep = bp + cc;
118 while (bp < ep) {
119 register int caplen, hdrlen;
120 caplen = bhp->bh_caplen;
121 hdrlen = bhp->bh_hdrlen;
122
123 /*
124 * XXX A bpf_hdr matches a pcap_pkthdr.
125 */
126 (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
127 bp += BPF_WORDALIGN(caplen + hdrlen);
128 if (++n >= cnt && cnt > 0) {
129 p->bp = bp;
130 p->cc = ep - bp;
131 return (n);
132 }
133 }
134 #undef bhp
135 p->cc = 0;
136 return (n);
137 }
138
139
140 static void
141 pcap_close_win32(pcap_t *p)
142 {
143 if (p->buffer != NULL)
144 free(p->buffer);
145 if (p->adapter != NULL) {
146 PacketCloseAdapter(p->adapter);
147 p->adapter = NULL;
148 }
149 }
150
151 pcap_t *
152 pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
153 char *ebuf)
154 {
155 register pcap_t *p;
156 NetType type;
157
158 /* Init WinSock */
159 wsockinit();
160
161 p = (pcap_t *)malloc(sizeof(*p));
162 if (p == NULL) {
163 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
164 return (NULL);
165 }
166 memset(p, 0, sizeof(*p));
167 p->adapter=NULL;
168
169 p->adapter=PacketOpenAdapter(device);
170 if (p->adapter==NULL) {
171 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror());
172 return NULL;
173 }
174
175 /*get network type*/
176 if(PacketGetNetType (p->adapter,&type)==FALSE)
177 {
178 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror());
179 goto bad;
180 }
181
182 /*Set the linktype*/
183 switch (type.LinkType) {
184
185 case NdisMediumWan:
186 p->linktype = DLT_EN10MB;
187 break;
188
189 case NdisMedium802_3:
190 p->linktype = DLT_EN10MB;
191 break;
192
193 case NdisMediumFddi:
194 p->linktype = DLT_FDDI;
195 break;
196
197 case NdisMedium802_5:
198 p->linktype = DLT_IEEE802;
199 break;
200
201 case NdisMediumArcnetRaw:
202 p->linktype = DLT_ARCNET;
203 break;
204
205 case NdisMediumArcnet878_2:
206 p->linktype = DLT_ARCNET;
207 break;
208
209 case NdisMediumAtm:
210 p->linktype = DLT_ATM_RFC1483;
211 break;
212
213 default:
214 p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/
215 break;
216 }
217
218 /* Set promisquous mode */
219 if (promisc) PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS);
220 else PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL);
221
222 /* Set the buffer size */
223 p->bufsize = PcapBufSize;
224
225 p->buffer = (u_char *)malloc(PcapBufSize);
226 if (p->buffer == NULL) {
227 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
228 goto bad;
229 }
230
231 p->snapshot = snaplen;
232
233 /* allocate Packet structure used during the capture */
234 if((p->Packet = PacketAllocatePacket())==NULL){
235 snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure");
236 goto bad;
237 }
238
239 PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize);
240
241 /* allocate the standard buffer in the driver */
242 if(PacketSetBuff( p->adapter, SIZE_BUF)==FALSE)
243 {
244 snprintf(ebuf, PCAP_ERRBUF_SIZE,"driver error: not enough memory to allocate the kernel buffer\n");
245 goto bad;
246 }
247
248 /* tell the driver to copy the buffer only if it contains at least 16K */
249 if(PacketSetMinToCopy(p->adapter,16000)==FALSE)
250 {
251 snprintf(ebuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s\n", pcap_win32strerror());
252 goto bad;
253 }
254
255 PacketSetReadTimeout(p->adapter, to_ms);
256
257 p->stats_op = pcap_stats_win32;
258 p->close_op = pcap_close_win32;
259
260 return (p);
261 bad:
262 if (p->adapter)
263 PacketCloseAdapter(p->adapter);
264 if (p->buffer != NULL)
265 free(p->buffer);
266 free(p);
267 return (NULL);
268 }
269
270
271 int
272 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
273 {
274 if(p->adapter==NULL){
275 /* Offline capture: make our own copy of the filter */
276 if (install_bpf_program(p, fp) < 0)
277 return (-1);
278 }
279 else if(PacketSetBpf(p->adapter,fp)==FALSE){
280 /* kernel filter not installed. */
281 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Driver error: cannot set bpf filter: %s", pcap_win32strerror());
282 return (-1);
283 }
284 return (0);
285 }
286
287
288 /* Set the driver working mode */
289 int
290 pcap_setmode(pcap_t *p, int mode){
291
292 if (p->adapter==NULL)
293 {
294 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "impossible to set mode while reading from a file");
295 return -1;
296 }
297
298 if(PacketSetMode(p->adapter,mode)==FALSE)
299 {
300 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized");
301 return -1;
302 }
303
304 return 0;
305 }
306
307 /* Send a packet to the network */
308 int
309 pcap_sendpacket(pcap_t *p, u_char *buf, int size){
310 LPPACKET PacketToSend;
311
312 if (p->adapter==NULL)
313 {
314 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Writing a packet is allowed only on a physical adapter");
315 return -1;
316 }
317
318 PacketToSend=PacketAllocatePacket();
319 PacketInitPacket(PacketToSend,buf,size);
320 if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){
321 PacketFreePacket(PacketToSend);
322 return -1;
323 }
324
325 PacketFreePacket(PacketToSend);
326 return 0;
327 }
328
329 /* Set the dimension of the kernel-level capture buffer */
330 int
331 pcap_setbuff(pcap_t *p, int dim)
332 {
333 if (p->adapter==NULL)
334 {
335 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "The kernel buffer size cannot be set while reading from a file");
336 return -1;
337 }
338
339 if(PacketSetBuff(p->adapter,dim)==FALSE)
340 {
341 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");
342 return -1;
343 }
344 return 0;
345 }
346
347 /*set the minimum amount of data that will release a read call*/
348 int
349 pcap_setmintocopy(pcap_t *p, int size)
350 {
351 if (p->adapter==NULL)
352 {
353 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Impossible to set the mintocopy parameter on an offline capture");
354 return -1;
355 }
356
357 if(PacketSetMinToCopy(p->adapter, size)==FALSE)
358 {
359 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size");
360 return -1;
361 }
362 return 0;
363 }
364
365 int
366 pcap_set_datalink_platform(pcap_t *p, int dlt)
367 {
368 return (0);
369 }