]> The Tcpdump Group git mirrors - libpcap/blob - pcap-win32.c
Add a "read" function pointer to the pcap_t structure, which handles
[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.13 2003-07-25 05:32:05 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 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 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
166 return (NULL);
167 }
168 memset(p, 0, sizeof(*p));
169 p->adapter=NULL;
170
171 p->adapter=PacketOpenAdapter(device);
172 if (p->adapter==NULL) {
173 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror());
174 return NULL;
175 }
176
177 /*get network type*/
178 if(PacketGetNetType (p->adapter,&type)==FALSE)
179 {
180 snprintf(ebuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror());
181 goto bad;
182 }
183
184 /*Set the linktype*/
185 switch (type.LinkType) {
186
187 case NdisMediumWan:
188 p->linktype = DLT_EN10MB;
189 break;
190
191 case NdisMedium802_3:
192 p->linktype = DLT_EN10MB;
193 break;
194
195 case NdisMediumFddi:
196 p->linktype = DLT_FDDI;
197 break;
198
199 case NdisMedium802_5:
200 p->linktype = DLT_IEEE802;
201 break;
202
203 case NdisMediumArcnetRaw:
204 p->linktype = DLT_ARCNET;
205 break;
206
207 case NdisMediumArcnet878_2:
208 p->linktype = DLT_ARCNET;
209 break;
210
211 case NdisMediumAtm:
212 p->linktype = DLT_ATM_RFC1483;
213 break;
214
215 default:
216 p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/
217 break;
218 }
219
220 /* Set promisquous mode */
221 if (promisc) PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS);
222 else PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL);
223
224 /* Set the buffer size */
225 p->bufsize = PcapBufSize;
226
227 p->buffer = (u_char *)malloc(PcapBufSize);
228 if (p->buffer == NULL) {
229 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
230 goto bad;
231 }
232
233 p->snapshot = snaplen;
234
235 /* allocate Packet structure used during the capture */
236 if((p->Packet = PacketAllocatePacket())==NULL){
237 snprintf(ebuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure");
238 goto bad;
239 }
240
241 PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize);
242
243 /* allocate the standard buffer in the driver */
244 if(PacketSetBuff( p->adapter, SIZE_BUF)==FALSE)
245 {
246 snprintf(ebuf, PCAP_ERRBUF_SIZE,"driver error: not enough memory to allocate the kernel buffer\n");
247 goto bad;
248 }
249
250 /* tell the driver to copy the buffer only if it contains at least 16K */
251 if(PacketSetMinToCopy(p->adapter,16000)==FALSE)
252 {
253 snprintf(ebuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s\n", pcap_win32strerror());
254 goto bad;
255 }
256
257 PacketSetReadTimeout(p->adapter, to_ms);
258
259 p->read_op = pcap_read_win32;
260 p->setfilter_op = pcap_setfilter_win32;
261 p->set_datalink_op = NULL; /* can't change data link type */
262 p->stats_op = pcap_stats_win32;
263 p->close_op = pcap_close_win32;
264
265 return (p);
266 bad:
267 if (p->adapter)
268 PacketCloseAdapter(p->adapter);
269 if (p->buffer != NULL)
270 free(p->buffer);
271 free(p);
272 return (NULL);
273 }
274
275
276 static int
277 pcap_setfilter_win32(pcap_t *p, struct bpf_program *fp)
278 {
279 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 }