nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) |
||
3 | * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California) |
||
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, CACE Technologies |
||
16 | * nor the names of its contributors may be used to endorse or promote |
||
17 | * products derived from this software without specific prior written |
||
18 | * permission. |
||
19 | * |
||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
31 | * |
||
32 | */ |
||
33 | |||
34 | #include <pcap-int.h> |
||
35 | #include <Packet32.h> |
||
36 | #ifdef __MINGW32__ |
||
37 | #ifdef __MINGW64__ |
||
38 | #include <ntddndis.h> |
||
39 | #else /*__MINGW64__*/ |
||
40 | #include <ddk/ntddndis.h> |
||
41 | #include <ddk/ndis.h> |
||
42 | #endif /*__MINGW64__*/ |
||
43 | #else /*__MINGW32__*/ |
||
44 | #include <ntddndis.h> |
||
45 | #endif /*__MINGW32__*/ |
||
46 | #ifdef HAVE_DAG_API |
||
47 | #include <dagnew.h> |
||
48 | #include <dagapi.h> |
||
49 | #endif /* HAVE_DAG_API */ |
||
50 | #ifdef __MINGW32__ |
||
51 | int* _errno(); |
||
52 | #define errno (*_errno()) |
||
53 | #endif /* __MINGW32__ */ |
||
54 | |||
55 | static int pcap_setfilter_win32_npf(pcap_t *, struct bpf_program *); |
||
56 | static int pcap_setfilter_win32_dag(pcap_t *, struct bpf_program *); |
||
57 | static int pcap_getnonblock_win32(pcap_t *, char *); |
||
58 | static int pcap_setnonblock_win32(pcap_t *, int, char *); |
||
59 | |||
60 | /*dimension of the buffer in the pcap_t structure*/ |
||
61 | #define WIN32_DEFAULT_USER_BUFFER_SIZE 256000 |
||
62 | |||
63 | /*dimension of the buffer in the kernel driver NPF */ |
||
64 | #define WIN32_DEFAULT_KERNEL_BUFFER_SIZE 1000000 |
||
65 | |||
66 | /* Equivalent to ntohs(), but a lot faster under Windows */ |
||
67 | #define SWAPS(_X) ((_X & 0xff) << 8) | (_X >> 8) |
||
68 | |||
69 | /* |
||
70 | * Private data for capturing on WinPcap devices. |
||
71 | */ |
||
72 | struct pcap_win { |
||
73 | int nonblock; |
||
74 | |||
75 | int filtering_in_kernel; /* using kernel filter */ |
||
76 | |||
77 | #ifdef HAVE_DAG_API |
||
78 | int dag_fcs_bits; /* Number of checksum bits from link layer */ |
||
79 | #endif |
||
80 | }; |
||
81 | |||
82 | /* |
||
83 | * Header that the WinPcap driver associates to the packets. |
||
84 | * Once was in bpf.h |
||
85 | */ |
||
86 | struct bpf_hdr { |
||
87 | struct timeval bh_tstamp; /* time stamp */ |
||
88 | bpf_u_int32 bh_caplen; /* length of captured portion */ |
||
89 | bpf_u_int32 bh_datalen; /* original length of packet */ |
||
90 | u_short bh_hdrlen; /* length of bpf header (this struct |
||
91 | plus alignment padding) */ |
||
92 | }; |
||
93 | |||
94 | CRITICAL_SECTION g_PcapCompileCriticalSection; |
||
95 | |||
96 | BOOL WINAPI DllMain( |
||
97 | HANDLE hinstDLL, |
||
98 | DWORD dwReason, |
||
99 | LPVOID lpvReserved |
||
100 | ) |
||
101 | { |
||
102 | if (dwReason == DLL_PROCESS_ATTACH) |
||
103 | { |
||
104 | InitializeCriticalSection(&g_PcapCompileCriticalSection); |
||
105 | } |
||
106 | |||
107 | return TRUE; |
||
108 | } |
||
109 | |||
110 | /* Start winsock */ |
||
111 | int |
||
112 | wsockinit() |
||
113 | { |
||
114 | WORD wVersionRequested; |
||
115 | WSADATA wsaData; |
||
116 | static int err = -1; |
||
117 | static int done = 0; |
||
118 | |||
119 | if (done) |
||
120 | return err; |
||
121 | |||
122 | wVersionRequested = MAKEWORD( 1, 1); |
||
123 | err = WSAStartup( wVersionRequested, &wsaData ); |
||
124 | atexit ((void(*)(void))WSACleanup); |
||
125 | InitializeCriticalSection(&g_PcapCompileCriticalSection); |
||
126 | done = 1; |
||
127 | |||
128 | if ( err != 0 ) |
||
129 | err = -1; |
||
130 | return err; |
||
131 | } |
||
132 | |||
133 | int pcap_wsockinit() |
||
134 | { |
||
135 | return wsockinit(); |
||
136 | } |
||
137 | |||
138 | static int |
||
139 | pcap_stats_win32(pcap_t *p, struct pcap_stat *ps) |
||
140 | { |
||
141 | |||
142 | if(PacketGetStats(p->adapter, (struct bpf_stat*)ps) != TRUE){ |
||
143 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "PacketGetStats error: %s", pcap_win32strerror()); |
||
144 | return -1; |
||
145 | } |
||
146 | |||
147 | return 0; |
||
148 | } |
||
149 | |||
150 | /* Set the dimension of the kernel-level capture buffer */ |
||
151 | static int |
||
152 | pcap_setbuff_win32(pcap_t *p, int dim) |
||
153 | { |
||
154 | if(PacketSetBuff(p->adapter,dim)==FALSE) |
||
155 | { |
||
156 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); |
||
157 | return -1; |
||
158 | } |
||
159 | return 0; |
||
160 | } |
||
161 | |||
162 | /* Set the driver working mode */ |
||
163 | static int |
||
164 | pcap_setmode_win32(pcap_t *p, int mode) |
||
165 | { |
||
166 | if(PacketSetMode(p->adapter,mode)==FALSE) |
||
167 | { |
||
168 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: working mode not recognized"); |
||
169 | return -1; |
||
170 | } |
||
171 | |||
172 | return 0; |
||
173 | } |
||
174 | |||
175 | /*set the minimum amount of data that will release a read call*/ |
||
176 | static int |
||
177 | pcap_setmintocopy_win32(pcap_t *p, int size) |
||
178 | { |
||
179 | if(PacketSetMinToCopy(p->adapter, size)==FALSE) |
||
180 | { |
||
181 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: unable to set the requested mintocopy size"); |
||
182 | return -1; |
||
183 | } |
||
184 | return 0; |
||
185 | } |
||
186 | |||
187 | /*return the Adapter for a pcap_t*/ |
||
188 | static Adapter * |
||
189 | pcap_getadapter_win32(pcap_t *p) |
||
190 | { |
||
191 | return p->adapter; |
||
192 | } |
||
193 | |||
194 | static int |
||
195 | pcap_read_win32_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) |
||
196 | { |
||
197 | int cc; |
||
198 | int n = 0; |
||
199 | register u_char *bp, *ep; |
||
200 | u_char *datap; |
||
201 | struct pcap_win *pw = p->priv; |
||
202 | |||
203 | cc = p->cc; |
||
204 | if (p->cc == 0) { |
||
205 | /* |
||
206 | * Has "pcap_breakloop()" been called? |
||
207 | */ |
||
208 | if (p->break_loop) { |
||
209 | /* |
||
210 | * Yes - clear the flag that indicates that it |
||
211 | * has, and return PCAP_ERROR_BREAK to indicate |
||
212 | * that we were told to break out of the loop. |
||
213 | */ |
||
214 | p->break_loop = 0; |
||
215 | return (PCAP_ERROR_BREAK); |
||
216 | } |
||
217 | |||
218 | /* capture the packets */ |
||
219 | if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){ |
||
220 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); |
||
221 | return (PCAP_ERROR); |
||
222 | } |
||
223 | |||
224 | cc = p->Packet->ulBytesReceived; |
||
225 | |||
226 | bp = p->Packet->Buffer; |
||
227 | } |
||
228 | else |
||
229 | bp = p->bp; |
||
230 | |||
231 | /* |
||
232 | * Loop through each packet. |
||
233 | */ |
||
234 | #define bhp ((struct bpf_hdr *)bp) |
||
235 | ep = bp + cc; |
||
236 | while (1) { |
||
237 | register int caplen, hdrlen; |
||
238 | |||
239 | /* |
||
240 | * Has "pcap_breakloop()" been called? |
||
241 | * If so, return immediately - if we haven't read any |
||
242 | * packets, clear the flag and return PCAP_ERROR_BREAK |
||
243 | * to indicate that we were told to break out of the loop, |
||
244 | * otherwise leave the flag set, so that the *next* call |
||
245 | * will break out of the loop without having read any |
||
246 | * packets, and return the number of packets we've |
||
247 | * processed so far. |
||
248 | */ |
||
249 | if (p->break_loop) { |
||
250 | if (n == 0) { |
||
251 | p->break_loop = 0; |
||
252 | return (PCAP_ERROR_BREAK); |
||
253 | } else { |
||
254 | p->bp = bp; |
||
255 | p->cc = ep - bp; |
||
256 | return (n); |
||
257 | } |
||
258 | } |
||
259 | if (bp >= ep) |
||
260 | break; |
||
261 | |||
262 | caplen = bhp->bh_caplen; |
||
263 | hdrlen = bhp->bh_hdrlen; |
||
264 | datap = bp + hdrlen; |
||
265 | |||
266 | /* |
||
267 | * Short-circuit evaluation: if using BPF filter |
||
268 | * in kernel, no need to do it now - we already know |
||
269 | * the packet passed the filter. |
||
270 | * |
||
271 | * XXX - bpf_filter() should always return TRUE if |
||
272 | * handed a null pointer for the program, but it might |
||
273 | * just try to "run" the filter, so we check here. |
||
274 | */ |
||
275 | if (pw->filtering_in_kernel || |
||
276 | p->fcode.bf_insns == NULL || |
||
277 | bpf_filter(p->fcode.bf_insns, datap, bhp->bh_datalen, caplen)) { |
||
278 | /* |
||
279 | * XXX A bpf_hdr matches a pcap_pkthdr. |
||
280 | */ |
||
281 | (*callback)(user, (struct pcap_pkthdr*)bp, datap); |
||
282 | bp += Packet_WORDALIGN(caplen + hdrlen); |
||
283 | if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) { |
||
284 | p->bp = bp; |
||
285 | p->cc = ep - bp; |
||
286 | return (n); |
||
287 | } |
||
288 | } else { |
||
289 | /* |
||
290 | * Skip this packet. |
||
291 | */ |
||
292 | bp += Packet_WORDALIGN(caplen + hdrlen); |
||
293 | } |
||
294 | } |
||
295 | #undef bhp |
||
296 | p->cc = 0; |
||
297 | return (n); |
||
298 | } |
||
299 | |||
300 | #ifdef HAVE_DAG_API |
||
301 | static int |
||
302 | pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user) |
||
303 | { |
||
304 | struct pcap_win *pw = p->priv; |
||
305 | u_char *dp = NULL; |
||
306 | int packet_len = 0, caplen = 0; |
||
307 | struct pcap_pkthdr pcap_header; |
||
308 | u_char *endofbuf; |
||
309 | int n = 0; |
||
310 | dag_record_t *header; |
||
311 | unsigned erf_record_len; |
||
312 | ULONGLONG ts; |
||
313 | int cc; |
||
314 | unsigned swt; |
||
315 | unsigned dfp = p->adapter->DagFastProcess; |
||
316 | |||
317 | cc = p->cc; |
||
318 | if (cc == 0) /* Get new packets only if we have processed all the ones of the previous read */ |
||
319 | { |
||
320 | /* Get new packets from the network */ |
||
321 | if(PacketReceivePacket(p->adapter, p->Packet, TRUE)==FALSE){ |
||
322 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error: PacketReceivePacket failed"); |
||
323 | return (-1); |
||
324 | } |
||
325 | |||
326 | cc = p->Packet->ulBytesReceived; |
||
327 | if(cc == 0) |
||
328 | /* The timeout has expired but we no packets arrived */ |
||
329 | return 0; |
||
330 | header = (dag_record_t*)p->adapter->DagBuffer; |
||
331 | } |
||
332 | else |
||
333 | header = (dag_record_t*)p->bp; |
||
334 | |||
335 | endofbuf = (char*)header + cc; |
||
336 | |||
337 | /* |
||
338 | * Cycle through the packets |
||
339 | */ |
||
340 | do |
||
341 | { |
||
342 | erf_record_len = SWAPS(header->rlen); |
||
343 | if((char*)header + erf_record_len > endofbuf) |
||
344 | break; |
||
345 | |||
346 | /* Increase the number of captured packets */ |
||
347 | pw->stat.ps_recv++; |
||
348 | |||
349 | /* Find the beginning of the packet */ |
||
350 | dp = ((u_char *)header) + dag_record_size; |
||
351 | |||
352 | /* Determine actual packet len */ |
||
353 | switch(header->type) |
||
354 | { |
||
355 | case TYPE_ATM: |
||
356 | packet_len = ATM_SNAPLEN; |
||
357 | caplen = ATM_SNAPLEN; |
||
358 | dp += 4; |
||
359 | |||
360 | break; |
||
361 | |||
362 | case TYPE_ETH: |
||
363 | swt = SWAPS(header->wlen); |
||
364 | packet_len = swt - (pw->dag_fcs_bits); |
||
365 | caplen = erf_record_len - dag_record_size - 2; |
||
366 | if (caplen > packet_len) |
||
367 | { |
||
368 | caplen = packet_len; |
||
369 | } |
||
370 | dp += 2; |
||
371 | |||
372 | break; |
||
373 | |||
374 | case TYPE_HDLC_POS: |
||
375 | swt = SWAPS(header->wlen); |
||
376 | packet_len = swt - (pw->dag_fcs_bits); |
||
377 | caplen = erf_record_len - dag_record_size; |
||
378 | if (caplen > packet_len) |
||
379 | { |
||
380 | caplen = packet_len; |
||
381 | } |
||
382 | |||
383 | break; |
||
384 | } |
||
385 | |||
386 | if(caplen > p->snapshot) |
||
387 | caplen = p->snapshot; |
||
388 | |||
389 | /* |
||
390 | * Has "pcap_breakloop()" been called? |
||
391 | * If so, return immediately - if we haven't read any |
||
392 | * packets, clear the flag and return -2 to indicate |
||
393 | * that we were told to break out of the loop, otherwise |
||
394 | * leave the flag set, so that the *next* call will break |
||
395 | * out of the loop without having read any packets, and |
||
396 | * return the number of packets we've processed so far. |
||
397 | */ |
||
398 | if (p->break_loop) |
||
399 | { |
||
400 | if (n == 0) |
||
401 | { |
||
402 | p->break_loop = 0; |
||
403 | return (-2); |
||
404 | } |
||
405 | else |
||
406 | { |
||
407 | p->bp = (char*)header; |
||
408 | p->cc = endofbuf - (char*)header; |
||
409 | return (n); |
||
410 | } |
||
411 | } |
||
412 | |||
413 | if(!dfp) |
||
414 | { |
||
415 | /* convert between timestamp formats */ |
||
416 | ts = header->ts; |
||
417 | pcap_header.ts.tv_sec = (int)(ts >> 32); |
||
418 | ts = (ts & 0xffffffffi64) * 1000000; |
||
419 | ts += 0x80000000; /* rounding */ |
||
420 | pcap_header.ts.tv_usec = (int)(ts >> 32); |
||
421 | if (pcap_header.ts.tv_usec >= 1000000) { |
||
422 | pcap_header.ts.tv_usec -= 1000000; |
||
423 | pcap_header.ts.tv_sec++; |
||
424 | } |
||
425 | } |
||
426 | |||
427 | /* No underlaying filtering system. We need to filter on our own */ |
||
428 | if (p->fcode.bf_insns) |
||
429 | { |
||
430 | if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0) |
||
431 | { |
||
432 | /* Move to next packet */ |
||
433 | header = (dag_record_t*)((char*)header + erf_record_len); |
||
434 | continue; |
||
435 | } |
||
436 | } |
||
437 | |||
438 | /* Fill the header for the user suppplied callback function */ |
||
439 | pcap_header.caplen = caplen; |
||
440 | pcap_header.len = packet_len; |
||
441 | |||
442 | /* Call the callback function */ |
||
443 | (*callback)(user, &pcap_header, dp); |
||
444 | |||
445 | /* Move to next packet */ |
||
446 | header = (dag_record_t*)((char*)header + erf_record_len); |
||
447 | |||
448 | /* Stop if the number of packets requested by user has been reached*/ |
||
449 | if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) |
||
450 | { |
||
451 | p->bp = (char*)header; |
||
452 | p->cc = endofbuf - (char*)header; |
||
453 | return (n); |
||
454 | } |
||
455 | } |
||
456 | while((u_char*)header < endofbuf); |
||
457 | |||
458 | return 1; |
||
459 | } |
||
460 | #endif /* HAVE_DAG_API */ |
||
461 | |||
462 | /* Send a packet to the network */ |
||
463 | static int |
||
464 | pcap_inject_win32(pcap_t *p, const void *buf, size_t size){ |
||
465 | LPPACKET PacketToSend; |
||
466 | |||
467 | PacketToSend=PacketAllocatePacket(); |
||
468 | |||
469 | if (PacketToSend == NULL) |
||
470 | { |
||
471 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketAllocatePacket failed"); |
||
472 | return -1; |
||
473 | } |
||
474 | |||
475 | PacketInitPacket(PacketToSend,(PVOID)buf,size); |
||
476 | if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){ |
||
477 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed"); |
||
478 | PacketFreePacket(PacketToSend); |
||
479 | return -1; |
||
480 | } |
||
481 | |||
482 | PacketFreePacket(PacketToSend); |
||
483 | |||
484 | /* |
||
485 | * We assume it all got sent if "PacketSendPacket()" succeeded. |
||
486 | * "pcap_inject()" is expected to return the number of bytes |
||
487 | * sent. |
||
488 | */ |
||
489 | return size; |
||
490 | } |
||
491 | |||
492 | static void |
||
493 | pcap_cleanup_win32(pcap_t *p) |
||
494 | { |
||
495 | if (p->adapter != NULL) { |
||
496 | PacketCloseAdapter(p->adapter); |
||
497 | p->adapter = NULL; |
||
498 | } |
||
499 | if (p->Packet) { |
||
500 | PacketFreePacket(p->Packet); |
||
501 | p->Packet = NULL; |
||
502 | } |
||
503 | pcap_cleanup_live_common(p); |
||
504 | } |
||
505 | |||
506 | static int |
||
507 | pcap_activate_win32(pcap_t *p) |
||
508 | { |
||
509 | struct pcap_win *pw = p->priv; |
||
510 | NetType type; |
||
511 | |||
512 | if (p->opt.rfmon) { |
||
513 | /* |
||
514 | * No monitor mode on Windows. It could be done on |
||
515 | * Vista with drivers that support the native 802.11 |
||
516 | * mechanism and monitor mode. |
||
517 | */ |
||
518 | return (PCAP_ERROR_RFMON_NOTSUP); |
||
519 | } |
||
520 | |||
521 | /* Init WinSock */ |
||
522 | wsockinit(); |
||
523 | |||
524 | p->adapter = PacketOpenAdapter(p->opt.source); |
||
525 | |||
526 | if (p->adapter == NULL) |
||
527 | { |
||
528 | /* Adapter detected but we are not able to open it. Return failure. */ |
||
529 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror()); |
||
530 | return PCAP_ERROR; |
||
531 | } |
||
532 | |||
533 | /*get network type*/ |
||
534 | if(PacketGetNetType (p->adapter,&type) == FALSE) |
||
535 | { |
||
536 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror()); |
||
537 | goto bad; |
||
538 | } |
||
539 | |||
540 | /*Set the linktype*/ |
||
541 | switch (type.LinkType) |
||
542 | { |
||
543 | case NdisMediumWan: |
||
544 | p->linktype = DLT_EN10MB; |
||
545 | break; |
||
546 | |||
547 | case NdisMedium802_3: |
||
548 | p->linktype = DLT_EN10MB; |
||
549 | /* |
||
550 | * This is (presumably) a real Ethernet capture; give it a |
||
551 | * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so |
||
552 | * that an application can let you choose it, in case you're |
||
553 | * capturing DOCSIS traffic that a Cisco Cable Modem |
||
554 | * Termination System is putting out onto an Ethernet (it |
||
555 | * doesn't put an Ethernet header onto the wire, it puts raw |
||
556 | * DOCSIS frames out on the wire inside the low-level |
||
557 | * Ethernet framing). |
||
558 | */ |
||
559 | p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2); |
||
560 | /* |
||
561 | * If that fails, just leave the list empty. |
||
562 | */ |
||
563 | if (p->dlt_list != NULL) { |
||
564 | p->dlt_list[0] = DLT_EN10MB; |
||
565 | p->dlt_list[1] = DLT_DOCSIS; |
||
566 | p->dlt_count = 2; |
||
567 | } |
||
568 | break; |
||
569 | |||
570 | case NdisMediumFddi: |
||
571 | p->linktype = DLT_FDDI; |
||
572 | break; |
||
573 | |||
574 | case NdisMedium802_5: |
||
575 | p->linktype = DLT_IEEE802; |
||
576 | break; |
||
577 | |||
578 | case NdisMediumArcnetRaw: |
||
579 | p->linktype = DLT_ARCNET; |
||
580 | break; |
||
581 | |||
582 | case NdisMediumArcnet878_2: |
||
583 | p->linktype = DLT_ARCNET; |
||
584 | break; |
||
585 | |||
586 | case NdisMediumAtm: |
||
587 | p->linktype = DLT_ATM_RFC1483; |
||
588 | break; |
||
589 | |||
590 | case NdisMediumCHDLC: |
||
591 | p->linktype = DLT_CHDLC; |
||
592 | break; |
||
593 | |||
594 | case NdisMediumPPPSerial: |
||
595 | p->linktype = DLT_PPP_SERIAL; |
||
596 | break; |
||
597 | |||
598 | case NdisMediumNull: |
||
599 | p->linktype = DLT_NULL; |
||
600 | break; |
||
601 | |||
602 | case NdisMediumBare80211: |
||
603 | p->linktype = DLT_IEEE802_11; |
||
604 | break; |
||
605 | |||
606 | case NdisMediumRadio80211: |
||
607 | p->linktype = DLT_IEEE802_11_RADIO; |
||
608 | break; |
||
609 | |||
610 | case NdisMediumPpi: |
||
611 | p->linktype = DLT_PPI; |
||
612 | break; |
||
613 | |||
614 | default: |
||
615 | p->linktype = DLT_EN10MB; /*an unknown adapter is assumed to be ethernet*/ |
||
616 | break; |
||
617 | } |
||
618 | |||
619 | /* Set promiscuous mode */ |
||
620 | if (p->opt.promisc) |
||
621 | { |
||
622 | |||
623 | if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE) |
||
624 | { |
||
625 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode"); |
||
626 | goto bad; |
||
627 | } |
||
628 | } |
||
629 | else |
||
630 | { |
||
631 | if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE) |
||
632 | { |
||
633 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode"); |
||
634 | goto bad; |
||
635 | } |
||
636 | } |
||
637 | |||
638 | /* Set the buffer size */ |
||
639 | p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE; |
||
640 | |||
641 | /* allocate Packet structure used during the capture */ |
||
642 | if((p->Packet = PacketAllocatePacket())==NULL) |
||
643 | { |
||
644 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure"); |
||
645 | goto bad; |
||
646 | } |
||
647 | |||
648 | if(!(p->adapter->Flags & INFO_FLAG_DAG_CARD)) |
||
649 | { |
||
650 | /* |
||
651 | * Traditional Adapter |
||
652 | */ |
||
653 | /* |
||
654 | * If the buffer size wasn't explicitly set, default to |
||
655 | * WIN32_DEFAULT_USER_BUFFER_SIZE. |
||
656 | */ |
||
657 | if (p->opt.buffer_size == 0) |
||
658 | p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE; |
||
659 | |||
660 | if(PacketSetBuff(p->adapter,p->opt.buffer_size)==FALSE) |
||
661 | { |
||
662 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer"); |
||
663 | goto bad; |
||
664 | } |
||
665 | |||
666 | p->buffer = (u_char *)malloc(p->bufsize); |
||
667 | if (p->buffer == NULL) |
||
668 | { |
||
669 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); |
||
670 | goto bad; |
||
671 | } |
||
672 | |||
673 | PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize); |
||
674 | |||
675 | if (p->opt.immediate) |
||
676 | { |
||
677 | /* tell the driver to copy the buffer as soon as data arrives */ |
||
678 | if(PacketSetMinToCopy(p->adapter,0)==FALSE) |
||
679 | { |
||
680 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s", pcap_win32strerror()); |
||
681 | goto bad; |
||
682 | } |
||
683 | } |
||
684 | else |
||
685 | { |
||
686 | /* tell the driver to copy the buffer only if it contains at least 16K */ |
||
687 | if(PacketSetMinToCopy(p->adapter,16000)==FALSE) |
||
688 | { |
||
689 | snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s", pcap_win32strerror()); |
||
690 | goto bad; |
||
691 | } |
||
692 | } |
||
693 | } |
||
694 | else |
||
695 | #ifdef HAVE_DAG_API |
||
696 | { |
||
697 | /* |
||
698 | * Dag Card |
||
699 | */ |
||
700 | LONG status; |
||
701 | HKEY dagkey; |
||
702 | DWORD lptype; |
||
703 | DWORD lpcbdata; |
||
704 | int postype = 0; |
||
705 | char keyname[512]; |
||
706 | |||
707 | snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s", |
||
708 | "SYSTEM\\CurrentControlSet\\Services\\DAG", |
||
709 | strstr(_strlwr(p->opt.source), "dag")); |
||
710 | do |
||
711 | { |
||
712 | status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey); |
||
713 | if(status != ERROR_SUCCESS) |
||
714 | break; |
||
715 | |||
716 | status = RegQueryValueEx(dagkey, |
||
717 | "PosType", |
||
718 | NULL, |
||
719 | &lptype, |
||
720 | (char*)&postype, |
||
721 | &lpcbdata); |
||
722 | |||
723 | if(status != ERROR_SUCCESS) |
||
724 | { |
||
725 | postype = 0; |
||
726 | } |
||
727 | |||
728 | RegCloseKey(dagkey); |
||
729 | } |
||
730 | while(FALSE); |
||
731 | |||
732 | |||
733 | p->snapshot = PacketSetSnapLen(p->adapter, snaplen); |
||
734 | |||
735 | /* Set the length of the FCS associated to any packet. This value |
||
736 | * will be subtracted to the packet length */ |
||
737 | pw->dag_fcs_bits = p->adapter->DagFcsLen; |
||
738 | } |
||
739 | #else |
||
740 | goto bad; |
||
741 | #endif /* HAVE_DAG_API */ |
||
742 | |||
743 | PacketSetReadTimeout(p->adapter, p->opt.timeout); |
||
744 | |||
745 | #ifdef HAVE_DAG_API |
||
746 | if(p->adapter->Flags & INFO_FLAG_DAG_CARD) |
||
747 | { |
||
748 | /* install dag specific handlers for read and setfilter */ |
||
749 | p->read_op = pcap_read_win32_dag; |
||
750 | p->setfilter_op = pcap_setfilter_win32_dag; |
||
751 | } |
||
752 | else |
||
753 | { |
||
754 | #endif /* HAVE_DAG_API */ |
||
755 | /* install traditional npf handlers for read and setfilter */ |
||
756 | p->read_op = pcap_read_win32_npf; |
||
757 | p->setfilter_op = pcap_setfilter_win32_npf; |
||
758 | #ifdef HAVE_DAG_API |
||
759 | } |
||
760 | #endif /* HAVE_DAG_API */ |
||
761 | p->setdirection_op = NULL; /* Not implemented. */ |
||
762 | /* XXX - can this be implemented on some versions of Windows? */ |
||
763 | p->inject_op = pcap_inject_win32; |
||
764 | p->set_datalink_op = NULL; /* can't change data link type */ |
||
765 | p->getnonblock_op = pcap_getnonblock_win32; |
||
766 | p->setnonblock_op = pcap_setnonblock_win32; |
||
767 | p->stats_op = pcap_stats_win32; |
||
768 | p->setbuff_op = pcap_setbuff_win32; |
||
769 | p->setmode_op = pcap_setmode_win32; |
||
770 | p->setmintocopy_op = pcap_setmintocopy_win32; |
||
771 | p->getadapter_op = pcap_getadapter_win32; |
||
772 | p->cleanup_op = pcap_cleanup_win32; |
||
773 | |||
774 | return (0); |
||
775 | bad: |
||
776 | pcap_cleanup_win32(p); |
||
777 | return (PCAP_ERROR); |
||
778 | } |
||
779 | |||
780 | pcap_t * |
||
781 | pcap_create_interface(const char *device, char *ebuf) |
||
782 | { |
||
783 | pcap_t *p; |
||
784 | |||
785 | if (strlen(device) == 1) |
||
786 | { |
||
787 | /* |
||
788 | * It's probably a unicode string |
||
789 | * Convert to ascii and pass it to pcap_create_common |
||
790 | * |
||
791 | * This wonderful hack is needed because pcap_lookupdev still returns |
||
792 | * unicode strings, and it's used by windump when no device is specified |
||
793 | * in the command line |
||
794 | */ |
||
795 | size_t length; |
||
796 | char* deviceAscii; |
||
797 | |||
798 | length = wcslen((wchar_t*)device); |
||
799 | |||
800 | deviceAscii = (char*)malloc(length + 1); |
||
801 | |||
802 | if (deviceAscii == NULL) |
||
803 | { |
||
804 | snprintf(ebuf, PCAP_ERRBUF_SIZE, "Malloc failed"); |
||
805 | return NULL; |
||
806 | } |
||
807 | |||
808 | snprintf(deviceAscii, length + 1, "%ws", (wchar_t*)device); |
||
809 | p = pcap_create_common(deviceAscii, ebuf, sizeof (struct pcap_win)); |
||
810 | free(deviceAscii); |
||
811 | } |
||
812 | else |
||
813 | { |
||
814 | p = pcap_create_common(device, ebuf, sizeof (struct pcap_win)); |
||
815 | } |
||
816 | |||
817 | if (p == NULL) |
||
818 | return (NULL); |
||
819 | |||
820 | p->activate_op = pcap_activate_win32; |
||
821 | return (p); |
||
822 | } |
||
823 | |||
824 | static int |
||
825 | pcap_setfilter_win32_npf(pcap_t *p, struct bpf_program *fp) |
||
826 | { |
||
827 | struct pcap_win *pw = p->priv; |
||
828 | |||
829 | if(PacketSetBpf(p->adapter,fp)==FALSE){ |
||
830 | /* |
||
831 | * Kernel filter not installed. |
||
832 | * |
||
833 | * XXX - we don't know whether this failed because: |
||
834 | * |
||
835 | * the kernel rejected the filter program as invalid, |
||
836 | * in which case we should fall back on userland |
||
837 | * filtering; |
||
838 | * |
||
839 | * the kernel rejected the filter program as too big, |
||
840 | * in which case we should again fall back on |
||
841 | * userland filtering; |
||
842 | * |
||
843 | * there was some other problem, in which case we |
||
844 | * should probably report an error. |
||
845 | * |
||
846 | * For NPF devices, the Win32 status will be |
||
847 | * STATUS_INVALID_DEVICE_REQUEST for invalid |
||
848 | * filters, but I don't know what it'd be for |
||
849 | * other problems, and for some other devices |
||
850 | * it might not be set at all. |
||
851 | * |
||
852 | * So we just fall back on userland filtering in |
||
853 | * all cases. |
||
854 | */ |
||
855 | |||
856 | /* |
||
857 | * install_bpf_program() validates the program. |
||
858 | * |
||
859 | * XXX - what if we already have a filter in the kernel? |
||
860 | */ |
||
861 | if (install_bpf_program(p, fp) < 0) |
||
862 | return (-1); |
||
863 | pw->filtering_in_kernel = 0; /* filtering in userland */ |
||
864 | return (0); |
||
865 | } |
||
866 | |||
867 | /* |
||
868 | * It worked. |
||
869 | */ |
||
870 | pw->filtering_in_kernel = 1; /* filtering in the kernel */ |
||
871 | |||
872 | /* |
||
873 | * Discard any previously-received packets, as they might have |
||
874 | * passed whatever filter was formerly in effect, but might |
||
875 | * not pass this filter (BIOCSETF discards packets buffered |
||
876 | * in the kernel, so you can lose packets in any case). |
||
877 | */ |
||
878 | p->cc = 0; |
||
879 | return (0); |
||
880 | } |
||
881 | |||
882 | /* |
||
883 | * We filter at user level, since the kernel driver does't process the packets |
||
884 | */ |
||
885 | static int |
||
886 | pcap_setfilter_win32_dag(pcap_t *p, struct bpf_program *fp) { |
||
887 | |||
888 | if(!fp) |
||
889 | { |
||
890 | strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf)); |
||
891 | return -1; |
||
892 | } |
||
893 | |||
894 | /* Install a user level filter */ |
||
895 | if (install_bpf_program(p, fp) < 0) |
||
896 | { |
||
897 | snprintf(p->errbuf, sizeof(p->errbuf), |
||
898 | "setfilter, unable to install the filter: %s", pcap_strerror(errno)); |
||
899 | return -1; |
||
900 | } |
||
901 | |||
902 | return (0); |
||
903 | } |
||
904 | |||
905 | static int |
||
906 | pcap_getnonblock_win32(pcap_t *p, char *errbuf) |
||
907 | { |
||
908 | struct pcap_win *pw = p->priv; |
||
909 | |||
910 | /* |
||
911 | * XXX - if there were a PacketGetReadTimeout() call, we |
||
912 | * would use it, and return 1 if the timeout is -1 |
||
913 | * and 0 otherwise. |
||
914 | */ |
||
915 | return (pw->nonblock); |
||
916 | } |
||
917 | |||
918 | static int |
||
919 | pcap_setnonblock_win32(pcap_t *p, int nonblock, char *errbuf) |
||
920 | { |
||
921 | struct pcap_win *pw = p->priv; |
||
922 | int newtimeout; |
||
923 | |||
924 | if (nonblock) { |
||
925 | /* |
||
926 | * Set the read timeout to -1 for non-blocking mode. |
||
927 | */ |
||
928 | newtimeout = -1; |
||
929 | } else { |
||
930 | /* |
||
931 | * Restore the timeout set when the device was opened. |
||
932 | * (Note that this may be -1, in which case we're not |
||
933 | * really leaving non-blocking mode.) |
||
934 | */ |
||
935 | newtimeout = p->opt.timeout; |
||
936 | } |
||
937 | if (!PacketSetReadTimeout(p->adapter, newtimeout)) { |
||
938 | snprintf(errbuf, PCAP_ERRBUF_SIZE, |
||
939 | "PacketSetReadTimeout: %s", pcap_win32strerror()); |
||
940 | return (-1); |
||
941 | } |
||
942 | pw->nonblock = (newtimeout == -1); |
||
943 | return (0); |
||
944 | } |
||
945 | |||
946 | /*platform-dependent routine to add devices other than NDIS interfaces*/ |
||
947 | int |
||
948 | pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) |
||
949 | { |
||
950 | return (0); |
||
951 | } |