Updated with latest version changes to original source by Politecnico di Torino.
[reactos.git] / reactos / lib / packet / Packet32.c
1 /*
2 * Copyright (c) 1999, 2000
3 * Politecnico di Torino. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the Politecnico
13 * di Torino, and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 #define UNICODE 1
23
24 #include <packet32.h>
25 #include <windows.h>
26 //#include <windowsx.h>
27 #include <ntddndis.h>
28
29 #include "trace.h"
30
31
32 /****** KERNEL Macro APIs ******************************************************/
33
34 #define GetInstanceModule(hInst) (HMODULE)(hInst)
35 #define GlobalPtrHandle(lp) ((HGLOBAL)GlobalHandle(lp))
36 #define GlobalLockPtr(lp) ((BOOL)GlobalLock(GlobalPtrHandle(lp)))
37 #define GlobalUnlockPtr(lp) GlobalUnlock(GlobalPtrHandle(lp))
38 #define GlobalAllocPtr(flags, cb) (GlobalLock(GlobalAlloc((flags), (cb))))
39 #define GlobalReAllocPtr(lp, cbNew, flags) (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags))))
40 #define GlobalFreePtr(lp) (GlobalUnlockPtr(lp), (BOOL)(ULONG_PTR)GlobalFree(GlobalPtrHandle(lp)))
41
42 #undef GMEM_MOVEABLE
43 #define GMEM_MOVEABLE 0
44
45
46
47 /// Title of error windows
48 TCHAR szWindowTitle[] = TEXT("PACKET.DLL");
49
50 #if DBG
51 #define ODS(_x) OutputDebugString(TEXT(_x))
52 //#define ODSEx(_x, _y)
53 #define ODSEx TRACE
54 #else
55 #ifdef _DEBUG_TO_FILE
56 #include <stdio.h>
57 /*!
58 \brief Macro to print a debug string. The behavior differs depending on the debug level
59 */
60 #define ODS(_x) { \
61 FILE *f; \
62 f = fopen("winpcap_debug.txt", "a"); \
63 fprintf(f, "%s", _x); \
64 fclose(f); \
65 }
66 /*!
67 \brief Macro to print debug data with the printf convention. The behavior differs depending on
68 the debug level
69 */
70 #define ODSEx(_x, _y) { \
71 FILE *f; \
72 f = fopen("winpcap_debug.txt", "a"); \
73 fprintf(f, _x, _y); \
74 fclose(f); \
75 }
76
77 LONG PacketDumpRegistryKey(PCHAR KeyName, PCHAR FileName);
78 #else
79 #define ODS(_x)
80 #define ODSEx(_x, _y)
81 #endif
82 #endif
83
84 //service handles
85 SC_HANDLE scmHandle = NULL;
86 SC_HANDLE srvHandle = NULL;
87 LPCTSTR NPFServiceName = TEXT("NPF");
88 LPCTSTR NPFServiceDesc = TEXT("Netgroup Packet Filter");
89 LPCTSTR NPFDriverName = TEXT("\\npf.sys");
90 LPCTSTR NPFRegistryLocation = TEXT("SYSTEM\\ControlSet001\\Services\\NPF");
91
92
93 //---------------------------------------------------------------------------
94
95 /*!
96 \brief The main dll function.
97 */
98
99 BOOL APIENTRY DllMain (HANDLE DllHandle,DWORD Reason,LPVOID lpReserved)
100 {
101 BOOLEAN Status=TRUE;
102
103 switch ( Reason )
104 {
105 case DLL_PROCESS_ATTACH:
106
107 ODS("\n************Packet32: DllMain************\n");
108
109 #ifdef _DEBUG_TO_FILE
110 // dump a bunch of registry keys useful for debug to file
111 PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
112 "adapters.reg");
113 PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip",
114 "tcpip.reg");
115 PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\NPF",
116 "npf.reg");
117 PacketDumpRegistryKey("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services",
118 "services.reg");
119 #endif
120 break;
121
122 case DLL_PROCESS_DETACH:
123 break;
124
125 default:
126 break;
127 }
128
129 return Status;
130 }
131
132 /*!
133 \brief Converts an ASCII string to UNICODE. Uses the MultiByteToWideChar() system function.
134 \param string The string to convert.
135 \return The converted string.
136 */
137
138 WCHAR* SChar2WChar(char* string)
139 {
140 WCHAR* TmpStr;
141 TmpStr=(WCHAR*) malloc ((strlen(string)+2)*sizeof(WCHAR));
142
143 MultiByteToWideChar(CP_ACP, 0, string, -1, TmpStr, (strlen(string)+2));
144
145 return TmpStr;
146 }
147
148 /*!
149 \brief Sets the maximum possible lookahead buffer for the driver's Packet_tap() function.
150 \param AdapterObject Handle to the service control manager.
151 \return If the function succeeds, the return value is nonzero.
152
153 The lookahead buffer is the portion of packet that Packet_tap() can access from the NIC driver's memory
154 without performing a copy. This function tries to increase the size of that buffer.
155 */
156
157 BOOLEAN PacketSetMaxLookaheadsize (LPADAPTER AdapterObject)
158 {
159 BOOLEAN Status;
160 ULONG IoCtlBufferLength=(sizeof(PACKET_OID_DATA)+sizeof(ULONG)-1);
161 PPACKET_OID_DATA OidData;
162
163 OidData=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,IoCtlBufferLength);
164 if (OidData == NULL) {
165 ODS("PacketSetMaxLookaheadsize failed\n");
166 return FALSE;
167 }
168
169 //set the size of the lookahead buffer to the maximum available by the the NIC driver
170 OidData->Oid=OID_GEN_MAXIMUM_LOOKAHEAD;
171 OidData->Length=sizeof(ULONG);
172 Status=PacketRequest(AdapterObject,FALSE,OidData);
173 OidData->Oid=OID_GEN_CURRENT_LOOKAHEAD;
174 Status=PacketRequest(AdapterObject,TRUE,OidData);
175 GlobalFreePtr(OidData);
176 return Status;
177 }
178
179 /*!
180 \brief Retrieves the event associated in the driver with a capture instance and stores it in an
181 _ADAPTER structure.
182 \param AdapterObject Handle to the service control manager.
183 \return If the function succeeds, the return value is nonzero.
184
185 This function is used by PacketOpenAdapter() to retrieve the read event from the driver by means of an ioctl
186 call and set it in the _ADAPTER structure pointed by AdapterObject.
187 */
188
189 BOOLEAN PacketSetReadEvt(LPADAPTER AdapterObject)
190 {
191 DWORD BytesReturned;
192 WCHAR EventName[39];
193
194 // this tells the terminal service to retrieve the event from the global namespace
195 wcsncpy(EventName,L"Global\\",sizeof(L"Global\\"));
196
197 // retrieve the name of the shared event from the driver
198 if(DeviceIoControl(AdapterObject->hFile,pBIOCEVNAME,NULL,0,EventName+7,13*sizeof(TCHAR),&BytesReturned,NULL)==FALSE) return FALSE;
199
200 EventName[20]=0; // terminate the string
201
202 // open the shared event
203 AdapterObject->ReadEvent=CreateEventW(NULL,
204 TRUE,
205 FALSE,
206 EventName);
207
208 // in NT4 "Global\" is not automatically ignored: try to use simply the event name
209 if(GetLastError()!=ERROR_ALREADY_EXISTS){
210 if(AdapterObject->ReadEvent != NULL)
211 CloseHandle(AdapterObject->ReadEvent);
212
213 // open the shared event
214 AdapterObject->ReadEvent=CreateEventW(NULL,
215 TRUE,
216 FALSE,
217 EventName+7);
218 }
219
220 if(AdapterObject->ReadEvent==NULL || GetLastError()!=ERROR_ALREADY_EXISTS){
221 ODS("PacketSetReadEvt: error retrieving the event from the kernel\n");
222 return FALSE;
223 }
224
225 AdapterObject->ReadTimeOut=0;
226
227 return TRUE;
228
229 }
230
231 /*!
232 \brief Installs the NPF device driver.
233 \param ascmHandle Handle to the service control manager.
234 \param ascmHandle A pointer to a handle that will receive the pointer to the driver's service.
235 \param driverPath The full path of the .sys file to load.
236 \return If the function succeeds, the return value is nonzero.
237
238 This function installs the driver's service in the system using the CreateService function.
239 */
240
241 BOOL PacketInstallDriver(SC_HANDLE ascmHandle, SC_HANDLE* srvHandle, TCHAR* driverPath)
242 {
243 BOOL result = FALSE;
244 ULONG err;
245
246 ODS("installdriver\n");
247
248 if (GetFileAttributes(driverPath) != 0xffffffff) {
249 *srvHandle = CreateService(ascmHandle,
250 NPFServiceName,
251 NPFServiceDesc,
252 SERVICE_ALL_ACCESS,
253 SERVICE_KERNEL_DRIVER,
254 SERVICE_DEMAND_START,
255 SERVICE_ERROR_NORMAL,
256 driverPath,
257 NULL, NULL, NULL, NULL, NULL);
258 if (*srvHandle == NULL) {
259 if (GetLastError() == ERROR_SERVICE_EXISTS) {
260 //npf.sys already existed
261 result = TRUE;
262 }
263 } else {
264 //Created service for npf.sys
265 result = TRUE;
266 }
267 }
268 if (result == TRUE) {
269 if (*srvHandle != NULL) {
270 CloseServiceHandle(*srvHandle);
271 }
272 }
273
274 if (result == FALSE){
275 err = GetLastError();
276 if (err != 2) {
277 ODSEx("PacketInstallDriver failed, Error=%d\n",err);
278 }
279 }
280 return result;
281
282 }
283
284 /*!
285 \brief Convert a Unicode dotted-quad to a 32-bit IP address.
286 \param cp A string containing the address.
287 \return the converted 32-bit numeric address.
288
289 Doesn't check to make sure the address is valid.
290 */
291
292
293 ULONG inet_addrU(const WCHAR *cp)
294 {
295 ULONG val, part;
296 WCHAR c;
297 int i;
298
299 val = 0;
300 for (i = 0; i < 4; i++) {
301 part = 0;
302 while ((c = *cp++) != '\0' && c != '.') {
303 if (c < '0' || c > '9')
304 return -1;
305 part = part*10 + (c - '0');
306 }
307 if (part > 255)
308 return -1;
309 val = val | (part << i*8);
310 if (i == 3) {
311 if (c != '\0')
312 return -1; // extra gunk at end of string
313 } else {
314 if (c == '\0')
315 return -1; // string ends early
316 }
317 }
318 return val;
319 }
320
321 /*!
322 \brief Dumps a registry key to disk in text format. Uses regedit.
323 \param KeyName Name of the ket to dump. All its subkeys will be saved recursively.
324 \param FileName Name of the file that will contain the dump.
325 \return If the function succeeds, the return value is nonzero.
326
327 For debugging purposes, we use this function to obtain some registry keys from the user's machine.
328 */
329
330 #ifdef _DEBUG_TO_FILE
331
332 LONG PacketDumpRegistryKey(PCHAR KeyName, PCHAR FileName)
333 {
334 CHAR Command[256];
335
336 strcpy(Command, "regedit /e ");
337 strcat(Command, FileName);
338 strcat(Command, " ");
339 strcat(Command, KeyName);
340
341 /// Let regedit do the dirt work for us
342 system(Command);
343
344 return TRUE;
345 }
346 #endif
347
348 //---------------------------------------------------------------------------
349 // PUBLIC API
350 //---------------------------------------------------------------------------
351
352 /** @ingroup packetapi
353 * @{
354 */
355
356 /** @defgroup packet32 Packet.dll exported functions and variables
357 * @{
358 */
359
360 /// Current packet.dll Version. It can be retrieved directly or through the PacketGetVersion() function.
361 char PacketLibraryVersion[] = "2.3";
362
363 /*!
364 \brief Returns a string with the dll version.
365 \return A char pointer to the version of the library.
366 */
367 PCHAR PacketGetVersion(){
368 return PacketLibraryVersion;
369 }
370
371 /*!
372 \brief Returns information about the MAC type of an adapter.
373 \param AdapterObject The adapter on which information is needed.
374 \param type Pointer to a NetType structure that will be filled by the function.
375 \return If the function succeeds, the return value is nonzero, otherwise the return value is zero.
376
377 This function return the link layer technology and the speed (in bps) of an opened adapter.
378 The LinkType field of the type parameter can have one of the following values:
379
380 - NdisMedium802_3: Ethernet (802.3)
381 - NdisMediumWan: WAN
382 - NdisMedium802_5: Token Ring (802.5)
383 - NdisMediumFddi: FDDI
384 - NdisMediumAtm: ATM
385 - NdisMediumArcnet878_2: ARCNET (878.2)
386 */
387 BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type)
388 {
389 BOOLEAN Status;
390 ULONG IoCtlBufferLength=(sizeof(PACKET_OID_DATA)+sizeof(ULONG)-1);
391 PPACKET_OID_DATA OidData;
392
393 OidData=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,IoCtlBufferLength);
394 if (OidData == NULL) {
395 ODS("PacketGetNetType failed\n");
396 return FALSE;
397 }
398 //get the link-layer type
399 OidData->Oid = OID_GEN_MEDIA_IN_USE;
400 OidData->Length = sizeof (ULONG);
401 Status = PacketRequest(AdapterObject,FALSE,OidData);
402 type->LinkType=*((UINT*)OidData->Data);
403
404 //get the link-layer speed
405 OidData->Oid = OID_GEN_LINK_SPEED;
406 OidData->Length = sizeof (ULONG);
407 Status = PacketRequest(AdapterObject,FALSE,OidData);
408 type->LinkSpeed=*((UINT*)OidData->Data)*100;
409 GlobalFreePtr (OidData);
410
411 ODSEx("Media:%d ",type->LinkType);
412 ODSEx("Speed=%d\n",type->LinkSpeed);
413
414 return Status;
415 }
416
417 /*!
418 \brief Stops and unloads the WinPcap device driver.
419 \return If the function succeeds, the return value is nonzero, otherwise it is zero.
420
421 This function can be used to unload the driver from memory when the application no more needs it.
422 Note that the driver is physically stopped and unloaded only when all the files on its devices
423 are closed, i.e. when all the applications that use WinPcap close all their adapters.
424 */
425 BOOL PacketStopDriver()
426 {
427 SC_HANDLE scmHandle;
428 SC_HANDLE schService;
429 BOOL ret;
430 SERVICE_STATUS serviceStatus;
431
432 scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
433
434 if(scmHandle != NULL){
435
436 schService = OpenService (scmHandle,
437 NPFServiceName,
438 SERVICE_ALL_ACCESS
439 );
440
441 if (schService != NULL)
442 {
443
444 ret = ControlService (schService,
445 SERVICE_CONTROL_STOP,
446 &serviceStatus
447 );
448 if (!ret)
449 {
450 }
451
452 CloseServiceHandle (schService);
453
454 CloseServiceHandle(scmHandle);
455
456 return ret;
457 }
458 }
459
460 return FALSE;
461
462 }
463
464 /*!
465 \brief Opens an adapter.
466 \param AdapterName A string containing the name of the device to open.
467 Use the PacketGetAdapterNames() function to retrieve the list of available devices.
468 \return If the function succeeds, the return value is the pointer to a properly initialized ADAPTER object,
469 otherwise the return value is NULL.
470
471 This function tries to load and start the packet driver at the first invocation. In this way,
472 the management of the driver is transparent to the application, that simply needs to open an adapter to start
473 WinPcap.
474
475 \note the Windows 95 version of the NPF driver works with the ASCII string format, while the Windows NT
476 version works with UNICODE. Therefore, AdapterName \b should be an ASCII string in Windows 95, and a UNICODE
477 string in Windows NT. This difference is not a problem if the string pointed by AdapterName was obtained
478 through the PacketGetAdapterNames function, because it returns the names of the adapters in the proper format.
479 Problems can arise in Windows NT when the string is obtained from ANSI C functions like scanf, because they
480 use the ASCII format. Since this could be a relevant problem during the porting of command-line applications
481 from UNIX, we included in the Windows NT version of PacketOpenAdapter the ability to detect ASCII strings and
482 convert them to UNICODE before sending them to the device driver. Therefore PacketOpenAdapter in Windows NT
483 accepts both the ASCII and the UNICODE format. If a ASCII string is received, it is converted to UNICODE
484 by PACKET.DLL before being passed to the driver.
485 */
486 LPADAPTER PacketOpenAdapter(LPTSTR AdapterName)
487 {
488 LPADAPTER lpAdapter;
489 BOOLEAN Result;
490 char *AdapterNameA;
491 WCHAR *AdapterNameU;
492 DWORD error;
493 SC_HANDLE svcHandle = NULL;
494 TCHAR driverPath[512];
495 TCHAR WinPath[256];
496 LONG KeyRes;
497 HKEY PathKey;
498 SERVICE_STATUS SStat;
499 BOOLEAN QuerySStat;
500 WCHAR SymbolicLink[128];
501
502 ODSEx("PacketOpenAdapter: trying to open the adapter=%S\n",AdapterName);
503
504 scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
505 if(scmHandle == NULL){
506 error = GetLastError();
507 ODSEx("OpenSCManager failed! Error=%d\n", error);
508 } else {
509 *driverPath = 0;
510 GetCurrentDirectory(512, driverPath);
511 wsprintf(driverPath + wcslen(driverPath), NPFDriverName);
512
513 // check if the NPF registry key is already present
514 // this means that the driver is already installed and that we don't need to call PacketInstallDriver
515 KeyRes=RegOpenKeyEx(HKEY_LOCAL_MACHINE,
516 NPFRegistryLocation,
517 0,
518 KEY_READ,
519 &PathKey);
520
521 if(KeyRes != ERROR_SUCCESS){
522 Result = PacketInstallDriver(scmHandle,&svcHandle,driverPath);
523 } else {
524 Result = TRUE;
525 RegCloseKey(PathKey);
526 }
527
528 if (Result) {
529
530 srvHandle = OpenService(scmHandle, NPFServiceName, SERVICE_START | SERVICE_QUERY_STATUS );
531 if (srvHandle != NULL){
532
533 QuerySStat = QueryServiceStatus(srvHandle, &SStat);
534 ODSEx("The status of the driver is:%d\n",SStat.dwCurrentState);
535
536 if (!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING){
537 ODS("Calling startservice\n");
538 if (StartService(srvHandle, 0, NULL)==0){
539 error = GetLastError();
540 if (error!=ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS){
541 SetLastError(error);
542 if (scmHandle != NULL) CloseServiceHandle(scmHandle);
543 error = GetLastError();
544 ODSEx("PacketOpenAdapter: StartService failed, Error=%d\n",error);
545 return NULL;
546 }
547 }
548 }
549 } else {
550 error = GetLastError();
551 ODSEx("OpenService failed! Error=%d", error);
552 }
553 } else {
554 if (GetSystemDirectory(WinPath, sizeof(WinPath)/sizeof(TCHAR)) == 0) {
555 return FALSE;
556 }
557 wsprintf(driverPath, TEXT("%s\\drivers%s"), WinPath, NPFDriverName);
558
559 if (KeyRes != ERROR_SUCCESS) {
560 Result = PacketInstallDriver(scmHandle,&svcHandle,driverPath);
561 } else {
562 Result = TRUE;
563 }
564 if (Result) {
565 srvHandle = OpenService(scmHandle,NPFServiceName,SERVICE_START);
566 if (srvHandle != NULL) {
567 QuerySStat = QueryServiceStatus(srvHandle, &SStat);
568 ODSEx("The status of the driver is:%d\n",SStat.dwCurrentState);
569 if (!QuerySStat || SStat.dwCurrentState != SERVICE_RUNNING) {
570 ODS("Calling startservice\n");
571 if (StartService(srvHandle, 0, NULL) == 0) {
572 error = GetLastError();
573 if (error != ERROR_SERVICE_ALREADY_RUNNING && error!=ERROR_ALREADY_EXISTS) {
574 SetLastError(error);
575 if (scmHandle != NULL) CloseServiceHandle(scmHandle);
576 ODSEx("PacketOpenAdapter: StartService failed, Error=%d\n",error);
577 return NULL;
578 }
579 }
580 }
581 } else {
582 error = GetLastError();
583 ODSEx("OpenService failed! Error=%d", error);
584 }
585 }
586 }
587 }
588 if (scmHandle != NULL) CloseServiceHandle(scmHandle);
589
590 AdapterNameA = (char*)AdapterName;
591 if (AdapterNameA[1] != 0) { // ASCII
592 AdapterNameU = SChar2WChar(AdapterNameA);
593 AdapterName = AdapterNameU;
594 } else { // Unicode
595 AdapterNameU = NULL;
596 }
597
598 lpAdapter = (LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(ADAPTER));
599 if (lpAdapter == NULL) {
600 ODS("PacketOpenAdapter: GlobalAlloc Failed\n");
601 error = GetLastError();
602 if (AdapterNameU != NULL) free(AdapterNameU);
603 //set the error to the one on which we failed
604 SetLastError(error);
605 ODS("PacketOpenAdapter: Failed to allocate the adapter structure\n");
606 return NULL;
607 }
608 lpAdapter->NumWrites = 1;
609
610 wsprintf(SymbolicLink,TEXT("\\\\.\\%s%s"), DOSNAMEPREFIX, &AdapterName[8]);
611
612 // Copy only the bytes that fit in the adapter structure.
613 // Note that lpAdapter->SymbolicLink is present for backward compatibility but will
614 // never be used by the apps
615 memcpy(lpAdapter->SymbolicLink, (PCHAR)SymbolicLink, MAX_LINK_NAME_LENGTH);
616
617 //try if it is possible to open the adapter immediately
618 lpAdapter->hFile = CreateFile(SymbolicLink,GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,0,0);
619
620 if (lpAdapter->hFile != INVALID_HANDLE_VALUE) {
621 ODSEx("PacketOpenAdapter: CreateFile(%S) successfull\n", SymbolicLink);
622 if (PacketSetReadEvt(lpAdapter) == FALSE) {
623 error = GetLastError();
624 ODS("PacketOpenAdapter: Unable to open the read event\n");
625 if (AdapterNameU != NULL)
626 free(AdapterNameU);
627 GlobalFreePtr(lpAdapter);
628 //set the error to the one on which we failed
629 SetLastError(error);
630 ODSEx("PacketOpenAdapter: PacketSetReadEvt failed, Error=%d\n",error);
631 return NULL;
632 }
633
634 PacketSetMaxLookaheadsize(lpAdapter);
635 if (AdapterNameU != NULL)
636 free(AdapterNameU);
637 return lpAdapter;
638 }
639 //this is probably the first request on the packet driver.
640 //We must create the dos device and set the access rights on it
641 else {
642 Result = DefineDosDevice(DDD_RAW_TARGET_PATH,
643 &SymbolicLink[4],
644 AdapterName);
645 if (Result) {
646
647 ODSEx("PacketOpenAdapter: calling CreateFile(%S)\n", SymbolicLink);
648
649 lpAdapter->hFile = CreateFile(
650 SymbolicLink,
651 GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,0,0);
652 if (lpAdapter->hFile != INVALID_HANDLE_VALUE) {
653 if (PacketSetReadEvt(lpAdapter) == FALSE) {
654 error = GetLastError();
655 ODS("PacketOpenAdapter: Unable to open the read event\n");
656 if (AdapterNameU != NULL)
657 free(AdapterNameU);
658 GlobalFreePtr(lpAdapter);
659 //set the error to the one on which we failed
660 SetLastError(error);
661 ODSEx("PacketOpenAdapter: PacketSetReadEvt failed, Error=1,%d\n",error);
662 return NULL;
663 }
664 PacketSetMaxLookaheadsize(lpAdapter);
665 if (AdapterNameU != NULL)
666 free(AdapterNameU);
667 return lpAdapter;
668 } else {
669 ODS("PacketOpenAdapter: CreateFile failed\n");
670 }
671 } else {
672 ODSEx("PacketOpenAdapter: DefineDosDevice(%S) failed\n", &SymbolicLink[4]);
673 }
674 }
675 error = GetLastError();
676 if (AdapterNameU != NULL)
677 free(AdapterNameU);
678 GlobalFreePtr(lpAdapter);
679 //set the error to the one on which we failed
680 SetLastError(error);
681 ODSEx("PacketOpenAdapter: CreateFile failed, Error=2,%d\n",error);
682 return NULL;
683
684 }
685
686 /*!
687 \brief Closes an adapter.
688 \param lpAdapter the pointer to the adapter to close.
689
690 PacketCloseAdapter closes the given adapter and frees the associated ADAPTER structure
691 */
692 VOID PacketCloseAdapter(LPADAPTER lpAdapter)
693 {
694 CloseHandle(lpAdapter->hFile);
695 SetEvent(lpAdapter->ReadEvent);
696 CloseHandle(lpAdapter->ReadEvent);
697 GlobalFreePtr(lpAdapter);
698 }
699
700 /*!
701 \brief Allocates a _PACKET structure.
702 \return On succeess, the return value is the pointer to a _PACKET structure otherwise the
703 return value is NULL.
704
705 The structure returned will be passed to the PacketReceivePacket() function to receive the
706 packets from the driver.
707
708 \warning The Buffer field of the _PACKET structure is not set by this function.
709 The buffer \b must be allocated by the application, and associated to the PACKET structure
710 with a call to PacketInitPacket.
711 */
712 LPPACKET PacketAllocatePacket(void)
713 {
714
715 LPPACKET lpPacket;
716 lpPacket = (LPPACKET)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,sizeof(PACKET));
717 if (lpPacket == NULL) {
718 ODS("PacketAllocatePacket: GlobalAlloc Failed\n");
719 return NULL;
720 }
721 return lpPacket;
722 }
723
724 /*!
725 \brief Frees a _PACKET structure.
726 \param lpPacket The structure to free.
727
728 \warning the user-allocated buffer associated with the _PACKET structure is not deallocated
729 by this function and \b must be explicitly deallocated by the programmer.
730
731 */
732 VOID PacketFreePacket(LPPACKET lpPacket)
733 {
734 GlobalFreePtr(lpPacket);
735 }
736
737 /*!
738 \brief Initializes a _PACKET structure.
739 \param lpPacket The structure to initialize.
740 \param Buffer A pointer to a user-allocated buffer that will contain the captured data.
741 \param Length the length of the buffer. This is the maximum buffer size that will be
742 transferred from the driver to the application using a single read.
743
744 \note the size of the buffer associated with the PACKET structure is a parameter that can sensibly
745 influence the performance of the capture process, since this buffer will contain the packets received
746 from the the driver. The driver is able to return several packets using a single read call
747 (see the PacketReceivePacket() function for details), and the number of packets transferable to the
748 application in a call is limited only by the size of the buffer associated with the PACKET structure
749 passed to PacketReceivePacket(). Therefore setting a big buffer with PacketInitPacket can noticeably
750 decrease the number of system calls, reducing the impcat of the capture process on the processor.
751 */
752
753 VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length)
754 {
755 lpPacket->Buffer = Buffer;
756 lpPacket->Length = Length;
757 lpPacket->ulBytesReceived = 0;
758 lpPacket->bIoComplete = FALSE;
759 }
760
761 /*!
762 \brief Read data (packets or statistics) from the NPF driver.
763 \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter from which
764 the data is received.
765 \param lpPacket Pointer to a PACKET structure that will contain the data.
766 \param Sync This parameter is deprecated and will be ignored. It is present for compatibility with
767 older applications.
768 \return If the function succeeds, the return value is nonzero.
769
770 The data received with this function can be a group of packets or a static on the network traffic,
771 depending on the working mode of the driver. The working mode can be set with the PacketSetMode()
772 function. Give a look at that function if you are interested in the format used to return statistics
773 values, here only the normal capture mode will be described.
774
775 The number of packets received with this function is variable. It depends on the number of packets
776 currently stored in the driver\92s buffer, on the size of these packets and on the size of the buffer
777 associated to the lpPacket parameter. The following figure shows the format used by the driver to pass
778 packets to the application.
779
780 \image html encoding.gif "method used to encode the packets"
781
782 Packets are stored in the buffer associated with the lpPacket _PACKET structure. The Length field of
783 that structure is updated with the amount of data copied in the buffer. Each packet has a header
784 consisting in a bpf_hdr structure that defines its length and contains its timestamp. A padding field
785 is used to word-align the data in the buffer (to speed up the access to the packets). The bh_datalen
786 and bh_hdrlen fields of the bpf_hdr structures should be used to extract the packets from the buffer.
787
788 Examples can be seen either in the TestApp sample application (see the \ref packetsamps page) provided
789 in the developer's pack, or in the pcap_read() function of wpcap.
790 */
791 BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)
792 {
793 BOOLEAN res;
794 if ((int)AdapterObject->ReadTimeOut != -1)
795 WaitForSingleObject(AdapterObject->ReadEvent, (AdapterObject->ReadTimeOut==0)?INFINITE:AdapterObject->ReadTimeOut);
796 res = ReadFile(AdapterObject->hFile, lpPacket->Buffer, lpPacket->Length, &lpPacket->ulBytesReceived,NULL);
797 return res;
798 }
799
800 /*!
801 \brief Sends one (or more) copies of a packet to the network.
802 \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter that will
803 send the packets.
804 \param lpPacket Pointer to a PACKET structure with the packet to send.
805 \param Sync This parameter is deprecated and will be ignored. It is present for compatibility with
806 older applications.
807 \return If the function succeeds, the return value is nonzero.
808
809 This function is used to send a raw packet to the network. 'Raw packet' means that the programmer
810 will have to include the protocol headers, since the packet is sent to the network 'as is'.
811 The CRC needs not to be calculated and put at the end of the packet, because it will be transparently
812 added by the network interface.
813
814 The behavior of this function is influenced by the PacketSetNumWrites() function. With PacketSetNumWrites(),
815 it is possible to change the number of times a single write must be repeated. The default is 1,
816 i.e. every call to PacketSendPacket() will correspond to one packet sent to the network. If this number is
817 greater than 1, for example 1000, every raw packet written by the application will be sent 1000 times on
818 the network. This feature mitigates the overhead of the context switches and therefore can be used to generate
819 high speed traffic. It is particularly useful for tools that test networks, routers, and servers and need
820 to obtain high network loads.
821 The optimized sending process is still limited to one packet at a time: for the moment it cannot be used
822 to send a buffer with multiple packets.
823
824 \note The ability to write multiple packets is currently present only in the Windows NTx version of the
825 packet driver. In Windows 95/98/ME it is emulated at user level in packet.dll. This means that an application
826 that uses the multiple write method will run in Windows 9x as well, but its performance will be very low
827 compared to the one of WindowsNTx.
828 */
829 BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)
830 {
831 DWORD BytesTransfered;
832 return WriteFile(AdapterObject->hFile,lpPacket->Buffer,lpPacket->Length,&BytesTransfered,NULL);
833 }
834
835
836 /*!
837 \brief Sends a buffer of packets to the network.
838 \param AdapterObject Pointer to an _ADAPTER structure identifying the network adapter that will
839 send the packets.
840 \param PacketBuff Pointer to buffer with the packets to send.
841 \param Size Size of the buffer pointed by the PacketBuff argument.
842 \param Sync if TRUE, the packets are sent respecting the timestamps. If FALSE, the packets are sent as
843 fast as possible
844 \return The amount of bytes actually sent. If the return value is smaller than the Size parameter, an
845 error occurred during the send. The error can be caused by a driver/adapter problem or by an
846 inconsistent/bogus packet buffer.
847
848 This function is used to send a buffer of raw packets to the network. The buffer can contain an arbitrary
849 number of raw packets, each of which preceded by a dump_bpf_hdr structure. The dump_bpf_hdr is the same used
850 by WinPcap and libpcap to store the packets in a file, therefore sending a capture file is straightforward.
851 'Raw packets' means that the sending application will have to include the protocol headers, since every packet
852 is sent to the network 'as is'. The CRC of the packets needs not to be calculated, because it will be
853 transparently added by the network interface.
854
855 \note Using this function if more efficient than issuing a series of PacketSendPacket(), because the packets are
856 buffered in the kernel driver, so the number of context switches is reduced.
857
858 \note When Sync is set to TRUE, the packets are synchronized in the kerenl with a high precision timestamp.
859 This requires a remarkable amount of CPU, but allows to send the packets with a precision of some microseconds
860 (depending on the precision of the performance counter of the machine). Such a precision cannot be reached
861 sending the packets separately with PacketSendPacket().
862 */
863 INT PacketSendPackets(LPADAPTER AdapterObject, PVOID PacketBuff, ULONG Size, BOOLEAN Sync)
864 {
865 BOOLEAN Res;
866 DWORD BytesTransfered, TotBytesTransfered=0;
867 struct timeval BufStartTime;
868 LARGE_INTEGER StartTicks, CurTicks, TargetTicks, TimeFreq;
869
870
871 ODS("PacketSendPackets");
872
873 // Obtain starting timestamp of the buffer
874 BufStartTime.tv_sec = ((struct timeval*)(PacketBuff))->tv_sec;
875 BufStartTime.tv_usec = ((struct timeval*)(PacketBuff))->tv_usec;
876
877 // Retrieve the reference time counters
878 QueryPerformanceCounter(&StartTicks);
879 QueryPerformanceFrequency(&TimeFreq);
880
881 CurTicks.QuadPart = StartTicks.QuadPart;
882
883 do{
884 // Send the data to the driver
885 Res = DeviceIoControl(AdapterObject->hFile,
886 (Sync)?pBIOCSENDPACKETSSYNC:pBIOCSENDPACKETSNOSYNC,
887 (PCHAR)PacketBuff + TotBytesTransfered,
888 Size - TotBytesTransfered,
889 NULL,
890 0,
891 &BytesTransfered,
892 NULL);
893
894 TotBytesTransfered += BytesTransfered;
895
896 // calculate the time interval to wait before sending the next packet
897 TargetTicks.QuadPart = StartTicks.QuadPart +
898 (LONGLONG)
899 ((((struct timeval*)((PCHAR)PacketBuff + TotBytesTransfered))->tv_sec - BufStartTime.tv_sec) * 1000000 +
900 (((struct timeval*)((PCHAR)PacketBuff + TotBytesTransfered))->tv_usec - BufStartTime.tv_usec)) *
901 (TimeFreq.QuadPart) / 1000000;
902
903 // Exit from the loop on termination or error
904 if(TotBytesTransfered >= Size || Res != TRUE)
905 break;
906
907 // Wait until the time interval has elapsed
908 while( CurTicks.QuadPart <= TargetTicks.QuadPart )
909 QueryPerformanceCounter(&CurTicks);
910
911 }
912 while(TRUE);
913
914 return TotBytesTransfered;
915 }
916
917 /*!
918 \brief Defines the minimum amount of data that will be received in a read.
919 \param AdapterObject Pointer to an _ADAPTER structure
920 \param nbytes the minimum amount of data in the kernel buffer that will cause the driver to
921 release a read on this adapter.
922 \return If the function succeeds, the return value is nonzero.
923
924 In presence of a large value for nbytes, the kernel waits for the arrival of several packets before
925 copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage,
926 i.e. better performance, which is a good setting for applications like sniffers. Vice versa, a small value
927 means that the kernel will copy the packets as soon as the application is ready to receive them. This is
928 suggested for real time applications (like, for example, a bridge) that need the better responsiveness from
929 the kernel.
930
931 \b note: this function has effect only in Windows NTx. The driver for Windows 9x doesn't offer
932 this possibility, therefore PacketSetMinToCopy is implemented under these systems only for compatibility.
933 */
934
935 BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes)
936 {
937 DWORD BytesReturned;
938 return DeviceIoControl(AdapterObject->hFile,pBIOCSMINTOCOPY,&nbytes,4,NULL,0,&BytesReturned,NULL);
939 }
940
941 /*!
942 \brief Sets the working mode of an adapter.
943 \param AdapterObject Pointer to an _ADAPTER structure.
944 \param mode The new working mode of the adapter.
945 \return If the function succeeds, the return value is nonzero.
946
947 The device driver of WinPcap has 4 working modes:
948 - Capture mode (mode = PACKET_MODE_CAPT): normal capture mode. The packets transiting on the wire are copied
949 to the application when PacketReceivePacket() is called. This is the default working mode of an adapter.
950 - Statistical mode (mode = PACKET_MODE_STAT): programmable statistical mode. PacketReceivePacket() returns, at
951 precise intervals, statics values on the network traffic. The interval between the statistic samples is
952 by default 1 second but it can be set to any other value (with a 1 ms precision) with the
953 PacketSetReadTimeout() function. The data returned by PacketReceivePacket() when the adapter is in statistical
954 mode is shown in the following figure:<p>
955 \image html stats.gif "data structure returned by statistical mode"
956 Two 64-bit counters are provided: the number of packets and the amount of bytes that satisfy a filter
957 previously set with PacketSetBPF(). If no filter has been set, all the packets are counted. The counters are
958 encapsulated in a bpf_hdr structure, so that they will be parsed correctly by wpcap. Statistical mode has a
959 very low impact on system performance compared to capture mode.
960 - Dump mode (mode = PACKET_MODE_DUMP): the packets are dumped to disk by the driver, in libpcap format. This
961 method is much faster than saving the packets after having captured them. No data is returned
962 by PacketReceivePacket(). If the application sets a filter with PacketSetBPF(), only the packets that satisfy
963 this filter are dumped to disk.
964 - Statitical Dump mode (mode = PACKET_MODE_STAT_DUMP): the packets are dumped to disk by the driver, in libpcap
965 format, like in dump mode. PacketReceivePacket() returns, at precise intervals, statics values on the
966 network traffic and on the amount of data saved to file, in a way similar to statistical mode.
967 The data returned by PacketReceivePacket() when the adapter is in statistical dump mode is shown in
968 the following figure:<p>
969 \image html dump.gif "data structure returned by statistical dump mode"
970 Three 64-bit counters are provided: the number of packets accepted, the amount of bytes accepted and the
971 effective amount of data (including headers) dumped to file. If no filter has been set, all the packets are
972 dumped to disk. The counters are encapsulated in a bpf_hdr structure, so that they will be parsed correctly
973 by wpcap.
974 Look at the NetMeter example in the
975 WinPcap developer's pack to see how to use statistics mode.
976 */
977 BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode)
978 {
979 DWORD BytesReturned;
980 return DeviceIoControl(AdapterObject->hFile,pBIOCSMODE,&mode,4,NULL,0,&BytesReturned,NULL);
981 }
982
983 /*!
984 \brief Sets the name of the file that will receive the packet when the adapter is in dump mode.
985 \param AdapterObject Pointer to an _ADAPTER structure.
986 \param name the file name, in ASCII or UNICODE.
987 \param len the length of the buffer containing the name, in bytes.
988 \return If the function succeeds, the return value is nonzero.
989
990 This function defines the file name that the driver will open to store the packets on disk when
991 it works in dump mode. The adapter must be in dump mode, i.e. PacketSetMode() should have been
992 called previously with mode = PACKET_MODE_DUMP. otherwise this function will fail.
993 If PacketSetDumpName was already invoked on the adapter pointed by AdapterObject, the driver
994 closes the old file and opens the new one.
995 */
996
997 BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len)
998 {
999 DWORD BytesReturned;
1000 WCHAR *FileName;
1001 BOOLEAN res;
1002 WCHAR NameWithPath[1024];
1003 int TStrLen;
1004 WCHAR *NamePos;
1005
1006 if(((PUCHAR)name)[1]!=0 && len>1){ //ASCII
1007 FileName=SChar2WChar(name);
1008 len*=2;
1009 }
1010 else { //Unicode
1011 FileName=name;
1012 }
1013
1014 TStrLen=GetFullPathName(FileName,1024,NameWithPath,&NamePos);
1015
1016 len=TStrLen*2+2; //add the terminating null character
1017
1018 // Try to catch malformed strings
1019 if(len>2048){
1020 if(((PUCHAR)name)[1]!=0 && len>1) free(FileName);
1021 return FALSE;
1022 }
1023
1024 res = DeviceIoControl(AdapterObject->hFile,pBIOCSETDUMPFILENAME,NameWithPath,len,NULL,0,&BytesReturned,NULL);
1025 free(FileName);
1026 return res;
1027 }
1028
1029 /*!
1030 \brief Set the dump mode limits.
1031 \param AdapterObject Pointer to an _ADAPTER structure.
1032 \param maxfilesize The maximum dimension of the dump file, in bytes. 0 means no limit.
1033 \param maxnpacks The maximum number of packets contained in the dump file. 0 means no limit.
1034 \return If the function succeeds, the return value is nonzero.
1035
1036 This function sets the limits after which the NPF driver stops to save the packets to file when an adapter
1037 is in dump mode. This allows to limit the dump file to a precise number of bytes or packets, avoiding that
1038 very long dumps fill the disk space. If both maxfilesize and maxnpacks are set, the dump is stopped when
1039 the first of the two is reached.
1040
1041 \note When a limit is reached, the dump is stopped, but the file remains opened. In order to flush
1042 correctly the data and access the file consistently, you need to close the adapter with PacketCloseAdapter().
1043 */
1044 BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks)
1045 {
1046 DWORD BytesReturned;
1047 UINT valbuff[2];
1048
1049 valbuff[0] = maxfilesize;
1050 valbuff[1] = maxnpacks;
1051
1052 return DeviceIoControl(AdapterObject->hFile,
1053 pBIOCSETDUMPLIMITS,
1054 valbuff,
1055 sizeof valbuff,
1056 NULL,
1057 0,
1058 &BytesReturned,
1059 NULL);
1060 }
1061
1062 /*!
1063 \brief Returns the status of the kernel dump process, i.e. tells if one of the limits defined with PacketSetDumpLimits() was reached.
1064 \param AdapterObject Pointer to an _ADAPTER structure.
1065 \param sync if TRUE, the function blocks until the dump is finished, otherwise it returns immediately.
1066 \return TRUE if the dump is ended, FALSE otherwise.
1067
1068 PacketIsDumpEnded() informs the user about the limits that were set with a previous call to
1069 PacketSetDumpLimits().
1070
1071 \warning If no calls to PacketSetDumpLimits() were performed or if the dump process has no limits
1072 (i.e. if the arguments of the last call to PacketSetDumpLimits() were both 0), setting sync to TRUE will
1073 block the application on this call forever.
1074 */
1075 BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync)
1076 {
1077 DWORD BytesReturned;
1078 int IsDumpEnded;
1079 BOOLEAN res;
1080
1081 if(sync)
1082 WaitForSingleObject(AdapterObject->ReadEvent, INFINITE);
1083
1084 res = DeviceIoControl(AdapterObject->hFile,
1085 pBIOCISDUMPENDED,
1086 NULL,
1087 0,
1088 &IsDumpEnded,
1089 4,
1090 &BytesReturned,
1091 NULL);
1092
1093 if(res == FALSE) return TRUE; // If the IOCTL returns an error we consider the dump finished
1094
1095 return (BOOLEAN)IsDumpEnded;
1096 }
1097
1098 /*!
1099 \brief Returns the notification event associated with the read calls on an adapter.
1100 \param AdapterObject Pointer to an _ADAPTER structure.
1101 \return The handle of the event that the driver signals when some data is available in the kernel buffer.
1102
1103 The event returned by this function is signaled by the driver if:
1104 - The adapter pointed by AdapterObject is in capture mode and an amount of data greater or equal
1105 than the one set with the PacketSetMinToCopy() function is received from the network.
1106 - the adapter pointed by AdapterObject is in capture mode, no data has been received from the network
1107 but the the timeout set with the PacketSetReadTimeout() function has elapsed.
1108 - the adapter pointed by AdapterObject is in statics mode and the the timeout set with the
1109 PacketSetReadTimeout() function has elapsed. This means that a new statistic sample is available.
1110
1111 In every case, a call to PacketReceivePacket() will return immediately.
1112 The event can be passed to standard Win32 functions (like WaitForSingleObject or WaitForMultipleObjects)
1113 to wait until the driver's buffer contains some data. It is particularly useful in GUI applications that
1114 need to wait concurrently on several events.
1115
1116 */
1117 HANDLE PacketGetReadEvent(LPADAPTER AdapterObject)
1118 {
1119 return AdapterObject->ReadEvent;
1120 }
1121
1122 /*!
1123 \brief Sets the number of times a single packet written with PacketSendPacket() will be repeated on the network.
1124 \param AdapterObject Pointer to an _ADAPTER structure.
1125 \param nwrites Number of copies of a packet that will be physically sent by the interface.
1126 \return If the function succeeds, the return value is nonzero.
1127
1128 See PacketSendPacket() for details.
1129 */
1130 BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites)
1131 {
1132 DWORD BytesReturned;
1133 return DeviceIoControl(AdapterObject->hFile,pBIOCSWRITEREP,&nwrites,4,NULL,0,&BytesReturned,NULL);
1134 }
1135
1136 /*!
1137 \brief Sets the timeout after which a read on an adapter returns.
1138 \param AdapterObject Pointer to an _ADAPTER structure.
1139 \param timeout indicates the timeout, in milliseconds, after which a call to PacketReceivePacket() on
1140 the adapter pointed by AdapterObject will be released, also if no packets have been captured by the driver.
1141 Setting timeout to 0 means no timeout, i.e. PacketReceivePacket() never returns if no packet arrives.
1142 A timeout of -1 causes PacketReceivePacket() to always return immediately.
1143 \return If the function succeeds, the return value is nonzero.
1144
1145 \note This function works also if the adapter is working in statistics mode, and can be used to set the
1146 time interval between two statistic reports.
1147 */
1148 BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout)
1149 {
1150 DWORD BytesReturned;
1151 int DriverTimeOut=-1;
1152
1153 AdapterObject->ReadTimeOut=timeout;
1154
1155 return DeviceIoControl(AdapterObject->hFile,pBIOCSRTIMEOUT,&DriverTimeOut,4,NULL,0,&BytesReturned,NULL);
1156 }
1157
1158 /*!
1159 \brief Sets the size of the kernel-level buffer associated with a capture.
1160 \param AdapterObject Pointer to an _ADAPTER structure.
1161 \param dim New size of the buffer, in \b kilobytes.
1162 \return The function returns TRUE if successfully completed, FALSE if there is not enough memory to
1163 allocate the new buffer.
1164
1165 When a new dimension is set, the data in the old buffer is discarded and the packets stored in it are
1166 lost.
1167
1168 Note: the dimension of the kernel buffer affects heavily the performances of the capture process.
1169 An adequate buffer in the driver is able to keep the packets while the application is busy, compensating
1170 the delays of the application and avoiding the loss of packets during bursts or high network activity.
1171 The buffer size is set to 0 when an instance of the driver is opened: the programmer should remember to
1172 set it to a proper value. As an example, wpcap sets the buffer size to 1MB at the beginning of a capture.
1173 */
1174 BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim)
1175 {
1176 DWORD BytesReturned;
1177 return DeviceIoControl(AdapterObject->hFile,pBIOCSETBUFFERSIZE,&dim,4,NULL,0,&BytesReturned,NULL);
1178 }
1179
1180 /*!
1181 \brief Sets a kernel-level packet filter.
1182 \param AdapterObject Pointer to an _ADAPTER structure.
1183 \param fp Pointer to a filtering program that will be associated with this capture or monitoring
1184 instance and that will be executed on every incoming packet.
1185 \return This function returns TRUE if the filter is set successfully, FALSE if an error occurs
1186 or if the filter program is not accepted after a safeness check by the driver. The driver performs
1187 the check in order to avoid system crashes due to buggy or malicious filters, and it rejects non
1188 conformat filters.
1189
1190 This function associates a new BPF filter to the adapter AdapterObject. The filter, pointed by fp, is a
1191 set of bpf_insn instructions.
1192
1193 A filter can be automatically created by using the pcap_compile() function of wpcap. This function
1194 converts a human readable text expression with the syntax of WinDump (see the manual of WinDump at
1195 http://netgroup.polito.it/windump for details) into a BPF program. If your program doesn't link wpcap, but
1196 you need to know the code of a particular filter, you can launch WinDump with the -d or -dd or -ddd
1197 flags to obtain the pseudocode.
1198
1199 */
1200 BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp)
1201 {
1202 DWORD BytesReturned;
1203 return DeviceIoControl(AdapterObject->hFile,pBIOCSETF,(char*)fp->bf_insns,fp->bf_len*sizeof(struct bpf_insn),NULL,0,&BytesReturned,NULL);
1204 }
1205
1206 /*!
1207 \brief Returns a couple of statistic values about the current capture session.
1208 \param AdapterObject Pointer to an _ADAPTER structure.
1209 \param s Pointer to a user provided bpf_stat structure that will be filled by the function.
1210 \return If the function succeeds, the return value is nonzero.
1211
1212 With this function, the programmer can know the value of two internal variables of the driver:
1213
1214 - the number of packets that have been received by the adapter AdapterObject, starting at the
1215 time in which it was opened with PacketOpenAdapter.
1216 - the number of packets that have been dropped by the driver. A packet is dropped when the kernel
1217 buffer associated with the adapter is full.
1218 */
1219 BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s)
1220 {
1221 BOOLEAN Res;
1222 DWORD BytesReturned;
1223 struct bpf_stat tmpstat; // We use a support structure to avoid kernel-level inconsistencies with old or malicious applications
1224
1225 Res = DeviceIoControl(AdapterObject->hFile,
1226 pBIOCGSTATS,
1227 NULL,
1228 0,
1229 &tmpstat,
1230 sizeof(struct bpf_stat),
1231 &BytesReturned,
1232 NULL);
1233
1234 // Copy only the first two values retrieved from the driver
1235 s->bs_recv = tmpstat.bs_recv;
1236 s->bs_drop = tmpstat.bs_drop;
1237
1238 return Res;
1239 }
1240
1241 /*!
1242 \brief Returns statistic values about the current capture session. Enhanced version of PacketGetStats().
1243 \param AdapterObject Pointer to an _ADAPTER structure.
1244 \param s Pointer to a user provided bpf_stat structure that will be filled by the function.
1245 \return If the function succeeds, the return value is nonzero.
1246
1247 With this function, the programmer can retireve the sname values provided by PacketGetStats(), plus:
1248
1249 - the number of drops by interface (not yet supported, always 0).
1250 - the number of packets that reached the application, i.e that were accepted by the kernel filter and
1251 that fitted in the kernel buffer.
1252 */
1253 BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s)
1254 {
1255 BOOLEAN Res;
1256 DWORD BytesReturned;
1257 struct bpf_stat tmpstat; // We use a support structure to avoid kernel-level inconsistencies with old or malicious applications
1258
1259 Res = DeviceIoControl(AdapterObject->hFile,
1260 pBIOCGSTATS,
1261 NULL,
1262 0,
1263 &tmpstat,
1264 sizeof(struct bpf_stat),
1265 &BytesReturned,
1266 NULL);
1267
1268 s->bs_recv = tmpstat.bs_recv;
1269 s->bs_drop = tmpstat.bs_drop;
1270 s->ps_ifdrop = tmpstat.ps_ifdrop;
1271 s->bs_capt = tmpstat.bs_capt;
1272
1273 return Res;
1274 }
1275
1276 /*!
1277 \brief Performs a query/set operation on an internal variable of the network card driver.
1278 \param AdapterObject Pointer to an _ADAPTER structure.
1279 \param Set Determines if the operation is a set (Set=TRUE) or a query (Set=FALSE).
1280 \param OidData A pointer to a _PACKET_OID_DATA structure that contains or receives the data.
1281 \return If the function succeeds, the return value is nonzero.
1282
1283 \note not all the network adapters implement all the query/set functions. There is a set of mandatory
1284 OID functions that is granted to be present on all the adapters, and a set of facultative functions, not
1285 provided by all the cards (see the Microsoft DDKs to see which functions are mandatory). If you use a
1286 facultative function, be careful to enclose it in an if statement to check the result.
1287 */
1288 BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData)
1289 {
1290 DWORD BytesReturned;
1291 BOOLEAN Result;
1292
1293 Result=DeviceIoControl(AdapterObject->hFile,(DWORD) Set ? pBIOCSETOID : pBIOCQUERYOID,
1294 OidData,sizeof(PACKET_OID_DATA)-1+OidData->Length,OidData,
1295 sizeof(PACKET_OID_DATA)-1+OidData->Length,&BytesReturned,NULL);
1296
1297 // output some debug info
1298 ODSEx("PacketRequest, OID=%d ", OidData->Oid);
1299 ODSEx("Length=%d ", OidData->Length);
1300 ODSEx("Set=%d ", Set);
1301 ODSEx("Res=%d\n", Result);
1302
1303 return Result;
1304 }
1305
1306 /*!
1307 \brief Sets a hardware filter on the incoming packets.
1308 \param AdapterObject Pointer to an _ADAPTER structure.
1309 \param Filter The identifier of the filter.
1310 \return If the function succeeds, the return value is nonzero.
1311
1312 The filter defined with this filter is evaluated by the network card, at a level that is under the NPF
1313 device driver. Here is a list of the most useful hardware filters (A complete list can be found in ntddndis.h):
1314
1315 - NDIS_PACKET_TYPE_PROMISCUOUS: sets promiscuous mode. Every incoming packet is accepted by the adapter.
1316 - NDIS_PACKET_TYPE_DIRECTED: only packets directed to the workstation's adapter are accepted.
1317 - NDIS_PACKET_TYPE_BROADCAST: only broadcast packets are accepted.
1318 - NDIS_PACKET_TYPE_MULTICAST: only multicast packets belonging to groups of which this adapter is a member are accepted.
1319 - NDIS_PACKET_TYPE_ALL_MULTICAST: every multicast packet is accepted.
1320 - NDIS_PACKET_TYPE_ALL_LOCAL: all local packets, i.e. NDIS_PACKET_TYPE_DIRECTED + NDIS_PACKET_TYPE_BROADCAST + NDIS_PACKET_TYPE_MULTICAST
1321 */
1322 BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter)
1323 {
1324 BOOLEAN Status;
1325 ULONG IoCtlBufferLength=(sizeof(PACKET_OID_DATA)+sizeof(ULONG)-1);
1326 PPACKET_OID_DATA OidData;
1327
1328 OidData=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,IoCtlBufferLength);
1329 if (OidData == NULL) {
1330 ODS("PacketSetHwFilter: GlobalAlloc Failed\n");
1331 return FALSE;
1332 }
1333 OidData->Oid=OID_GEN_CURRENT_PACKET_FILTER;
1334 OidData->Length=sizeof(ULONG);
1335 *((PULONG)OidData->Data)=Filter;
1336 Status=PacketRequest(AdapterObject,TRUE,OidData);
1337 GlobalFreePtr(OidData);
1338 return Status;
1339 }
1340
1341 /*!
1342 \brief Retrieve the list of available network adapters and their description.
1343 \param pStr User allocated string that will be filled with the names of the adapters.
1344 \param BufferSize Length of the buffer pointed by pStr.
1345 \return If the function succeeds, the return value is nonzero.
1346
1347 Usually, this is the first function that should be used to communicate with the driver.
1348 It returns the names of the adapters installed on the system <B>and supported by WinPcap</B>.
1349 After the names of the adapters, pStr contains a string that describes each of them.
1350
1351 \b Warning:
1352 the result of this function is obtained querying the registry, therefore the format
1353 of the result in Windows NTx is different from the one in Windows 9x. Windows 9x uses the ASCII
1354 encoding method to store a string, while Windows NTx uses UNICODE. After a call to PacketGetAdapterNames
1355 in Windows 95x, pStr contains, in succession:
1356 - a variable number of ASCII strings, each with the names of an adapter, separated by a "\0"
1357 - a double "\0"
1358 - a number of ASCII strings, each with the description of an adapter, separated by a "\0". The number
1359 of descriptions is the same of the one of names. The fisrt description corresponds to the first name, and
1360 so on.
1361 - a double "\0".
1362
1363 In Windows NTx, pStr contains: the names of the adapters, in UNICODE format, separated by a single UNICODE "\0" (i.e. 2 ASCII "\0"), a double UNICODE "\0", followed by the descriptions of the adapters, in ASCII format, separated by a single ASCII "\0" . The string is terminated by a double ASCII "\0".
1364 - a variable number of UNICODE strings, each with the names of an adapter, separated by a UNICODE "\0"
1365 - a double UNICODE "\0"
1366 - a number of ASCII strings, each with the description of an adapter, separated by an ASCII "\0".
1367 - a double ASCII "\0".
1368 */
1369
1370 BOOLEAN PacketGetAdapterNames(PTSTR pStr, PULONG BufferSize)
1371 {
1372 HKEY LinkageKey, AdapKey;
1373 DWORD RegKeySize = 0;
1374 LONG Status;
1375 ULONG Result;
1376 PTSTR BpStr;
1377 char *TTpStr;
1378 char *DpStr;
1379 char *DescBuf;
1380 LPADAPTER adapter;
1381 PPACKET_OID_DATA OidData;
1382 int i = 0, k, rewind;
1383 DWORD dim;
1384 TCHAR AdapName[256];
1385
1386 ODSEx("PacketGetAdapterNames: BufferSize=%d\n",*BufferSize);
1387
1388 OidData = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 512);
1389 if (OidData == NULL) {
1390 ODS("PacketGetAdapterNames: GlobalAlloc Failed\n");
1391 return FALSE;
1392 }
1393
1394 Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1395 TEXT("SYSTEM\\ControlSet001\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"),
1396 0, KEY_READ, &AdapKey);
1397
1398 // Get the size to allocate for the original device names
1399 while ((Result = RegEnumKey(AdapKey, i, AdapName, sizeof(AdapName)/2)) == ERROR_SUCCESS) {
1400 Status = RegOpenKeyEx(AdapKey, AdapName,0, KEY_READ, &LinkageKey);
1401 Status = RegOpenKeyExW(LinkageKey, L"Linkage",0, KEY_READ, &LinkageKey);
1402 Status = RegQueryValueExW(LinkageKey, L"Export", NULL, NULL, NULL, &dim);
1403 i++;
1404 if (Status!=ERROR_SUCCESS) continue;
1405 RegKeySize += dim;
1406 }
1407
1408 // Allocate the memory for the original device names
1409 ODSEx("Need %d bytes for the names\n", RegKeySize+2);
1410 BpStr = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, RegKeySize+2);
1411 if (BpStr == NULL || RegKeySize > *BufferSize) {
1412 ODS("PacketGetAdapterNames: GlobalAlloc Failed\n");
1413 GlobalFreePtr(OidData);
1414 return FALSE;
1415 }
1416 k = 0;
1417 i = 0;
1418
1419 ODS("PacketGetAdapterNames: Cycling through the adapters:\n");
1420
1421 // Copy the names to the buffer
1422 while ((Result = RegEnumKey(AdapKey, i, AdapName, sizeof(AdapName)/2)) == ERROR_SUCCESS) {
1423 WCHAR UpperBindStr[64];
1424
1425 i++;
1426 ODSEx(" %d) ", i);
1427
1428 Status = RegOpenKeyEx(AdapKey,AdapName,0,KEY_READ,&LinkageKey);
1429 Status = RegOpenKeyExW(LinkageKey,L"Linkage",0,KEY_READ,&LinkageKey);
1430
1431 dim=sizeof(UpperBindStr);
1432 Status=RegQueryValueExW(LinkageKey,L"UpperBind",NULL,NULL,(PUCHAR)UpperBindStr,&dim);
1433
1434 ODSEx("UpperBind=%S ", UpperBindStr);
1435
1436 if( Status!=ERROR_SUCCESS || _wcsicmp(UpperBindStr,L"NdisWan")==0 ){
1437 ODS("Name = SKIPPED\n");
1438 continue;
1439 }
1440
1441 dim=RegKeySize-k;
1442 Status=RegQueryValueExW(LinkageKey,L"Export",NULL,NULL,(LPBYTE)BpStr+k,&dim);
1443 if(Status!=ERROR_SUCCESS){
1444 ODS("Name = SKIPPED (error reading the key)\n");
1445 continue;
1446 }
1447
1448 ODSEx("Name = %S\n", (LPBYTE)BpStr+k);
1449
1450 k+=dim-2;
1451 }
1452
1453 CloseHandle(AdapKey);
1454
1455 #ifdef _DEBUG_TO_FILE
1456 //dump BpStr for debug purposes
1457 ODS("Dumping BpStr:");
1458 {
1459 FILE *f;
1460 f = fopen("winpcap_debug.txt", "a");
1461 for(i=0;i<k;i++){
1462 if(!(i%32))fprintf(f, "\n ");
1463 fprintf(f, "%c " , *((LPBYTE)BpStr+i));
1464 }
1465 fclose(f);
1466 }
1467 ODS("\n");
1468 #endif
1469
1470
1471 if (k != 0){
1472
1473 DescBuf=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 4096);
1474 if (DescBuf == NULL) {
1475 GlobalFreePtr (BpStr);
1476 GlobalFreePtr(OidData);
1477 return FALSE;
1478 }
1479 DpStr=DescBuf;
1480
1481 for(i=0,k=0;BpStr[i]!=0 || BpStr[i+1]!=0;){
1482
1483 if(k+wcslen(BpStr+i)+30 > *BufferSize){
1484 // Input buffer too small
1485 GlobalFreePtr(OidData);
1486 GlobalFreePtr (BpStr);
1487 GlobalFreePtr (DescBuf);
1488 ODS("PacketGetAdapterNames: Input buffer too small!\n");
1489 return FALSE;
1490 }
1491
1492 // Create the device name
1493 rewind=k;
1494 memcpy(pStr+k,BpStr+i,16);
1495 memcpy(pStr+k+8,TEXT("NPF_"),8);
1496 i+=8;
1497 k+=12;
1498 while(BpStr[i-1]!=0){
1499 pStr[k++]=BpStr[i++];
1500 }
1501
1502 // Open the adapter
1503 adapter=PacketOpenAdapter(pStr+rewind);
1504 if(adapter==NULL){
1505 k=rewind;
1506 continue;
1507 }
1508
1509 // Retrieve the description
1510 OidData->Oid = OID_GEN_VENDOR_DESCRIPTION;
1511 OidData->Length = 256;
1512 ZeroMemory(OidData->Data,256);
1513 Status = PacketRequest(adapter,FALSE,OidData);
1514 if(Status==0 || ((char*)OidData->Data)[0]==0){
1515 k=rewind;
1516 continue;
1517 }
1518
1519 ODSEx("Adapter Description=%s\n\n",OidData->Data);
1520
1521 // Copy the description
1522 TTpStr=(char*)(OidData->Data);
1523 while(*TTpStr!=0){
1524 *DpStr++=*TTpStr++;
1525 }
1526 *DpStr++=*TTpStr++;
1527
1528 // Close the adapter
1529 PacketCloseAdapter(adapter);
1530
1531 }
1532 *DpStr = 0;
1533
1534 pStr[k++] = 0;
1535 pStr[k] = 0;
1536
1537 if ((ULONG)(DpStr - DescBuf + k) < *BufferSize) {
1538 memcpy(pStr + k, DescBuf, DpStr - DescBuf);
1539 } else {
1540 GlobalFreePtr(OidData);
1541 GlobalFreePtr(BpStr);
1542 GlobalFreePtr(DescBuf);
1543 ODS("\nPacketGetAdapterNames: ended with failure\n");
1544 return FALSE;
1545 }
1546
1547 GlobalFreePtr(OidData);
1548 GlobalFreePtr(BpStr);
1549 GlobalFreePtr(DescBuf);
1550 ODS("\nPacketGetAdapterNames: ended correctly\n");
1551 return TRUE;
1552 }
1553 else{
1554 DWORD RegType;
1555
1556 ODS("Adapters not found under SYSTEM\\ControlSet001\\Control\\Class. Using the TCP/IP bindings.\n");
1557
1558 GlobalFreePtr(BpStr);
1559 Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1560 TEXT("SYSTEM\\ControlSet001\\Services\\Tcpip\\Linkage"),
1561 0, KEY_READ, &LinkageKey);
1562 if (Status == ERROR_SUCCESS) {
1563 // Retrieve the length of the key
1564 Status = RegQueryValueEx(LinkageKey, TEXT("bind"), NULL, &RegType, NULL, &RegKeySize);
1565 // Allocate the buffer
1566 BpStr = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, RegKeySize + 2);
1567 if (BpStr == NULL || RegKeySize > *BufferSize) {
1568 GlobalFreePtr(OidData);
1569 return FALSE;
1570 }
1571 Status = RegQueryValueEx(LinkageKey, TEXT("bind"), NULL, &RegType, (LPBYTE)BpStr, &RegKeySize);
1572 RegCloseKey(LinkageKey);
1573 } else {
1574 //ODS("SYSTEM\\ControlSet001\\Control\\Class - RegKey not found.\n");
1575 ODS("SYSTEM\\ControlSet001\\Services\\Tcpip\\Linkage - RegKey not found.\n");
1576 }
1577 if (Status == ERROR_SUCCESS) {
1578 DescBuf = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, 4096);
1579 if (DescBuf == NULL) {
1580 GlobalFreePtr(BpStr);
1581 GlobalFreePtr(OidData);
1582 return FALSE;
1583 }
1584 DpStr = DescBuf;
1585 for (i = 0, k = 0; BpStr[i] != 0 || BpStr[i+1] != 0; ) {
1586 if (k + wcslen(BpStr + i) + 30 > *BufferSize) {
1587 // Input buffer too small
1588 GlobalFreePtr(OidData);
1589 GlobalFreePtr(BpStr);
1590 GlobalFreePtr(DescBuf);
1591 return FALSE;
1592 }
1593
1594 ODS("\tCreating a device name - started.\n");
1595
1596 // Create the device name
1597 rewind = k;
1598 memcpy(pStr + k,BpStr + i,16);
1599 memcpy(pStr + k + 8, TEXT("NPF_"), 8);
1600 i += 8;
1601 k += 12;
1602 while (BpStr[i - 1] != 0) {
1603 pStr[k++] = BpStr[i++];
1604 }
1605 // Open the adapter
1606 adapter = PacketOpenAdapter(pStr+rewind);
1607 if (adapter == NULL) {
1608 k = rewind;
1609 continue;
1610 }
1611 // Retrieve the description
1612 OidData->Oid = OID_GEN_VENDOR_DESCRIPTION;
1613 OidData->Length = 256;
1614 Status = PacketRequest(adapter, FALSE, OidData);
1615 if (Status == 0 || ((char*)OidData->Data)[0] == 0) {
1616 k = rewind;
1617 ODS("\tCreating a device name - Retrieve the description.\n");
1618 continue;
1619 }
1620
1621 // Copy the description
1622 TTpStr = (char*)(OidData->Data);
1623 while (*TTpStr != 0){
1624 *DpStr++ = *TTpStr++;
1625 }
1626 *DpStr++ = *TTpStr++;
1627 // Close the adapter
1628 PacketCloseAdapter(adapter);
1629
1630 ODS("\tCreating a device name - completed.\n");
1631 }
1632 *DpStr = 0;
1633
1634 pStr[k++] = 0;
1635 pStr[k] = 0;
1636
1637 if ((ULONG)(DpStr - DescBuf + k) < *BufferSize) {
1638 memcpy(pStr + k, DescBuf, DpStr-DescBuf);
1639 } else {
1640 GlobalFreePtr(OidData);
1641 GlobalFreePtr(BpStr);
1642 GlobalFreePtr(DescBuf);
1643 return FALSE;
1644 }
1645
1646 GlobalFreePtr(OidData);
1647 GlobalFreePtr(BpStr);
1648 GlobalFreePtr(DescBuf);
1649 ODS("PacketGetAdapterNames() returning TRUE\n");
1650 return TRUE;
1651 } else {
1652 MessageBox(NULL,TEXT("Can not find TCP/IP bindings.\nIn order to run the packet capture driver you must install TCP/IP."),szWindowTitle,MB_OK);
1653 ODS("Cannot find the TCP/IP bindings\n");
1654 return FALSE;
1655 }
1656 }
1657 }
1658
1659 /*!
1660 \brief Returns comprehensive information the addresses of an adapter.
1661 \param AdapterName String that contain _ADAPTER structure.
1662 \param buffer A user allocated array of npf_if_addr that will be filled by the function.
1663 \param NEntries Size of the array (in npf_if_addr).
1664 \return If the function succeeds, the return value is nonzero.
1665
1666 This function grabs from the registry information like the IP addresses, the netmasks
1667 and the broadcast addresses of an interface. The buffer passed by the user is filled with
1668 npf_if_addr structures, each of which contains the data for a single address. If the buffer
1669 is full, the reaming addresses are dropeed, therefore set its dimension to sizeof(npf_if_addr)
1670 if you want only the first address.
1671 */
1672
1673 BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterName, npf_if_addr* buffer, PLONG NEntries)
1674 {
1675 char *AdapterNameA;
1676 WCHAR *AdapterNameU;
1677 WCHAR *ifname;
1678 HKEY SystemKey;
1679 HKEY InterfaceKey;
1680 HKEY ParametersKey;
1681 HKEY TcpIpKey;
1682 HKEY UnderTcpKey;
1683 LONG status;
1684 WCHAR String[1024+1];
1685 DWORD RegType;
1686 ULONG BufLen;
1687 DWORD DHCPEnabled;
1688 struct sockaddr_in *TmpAddr, *TmpBroad;
1689 LONG naddrs,nmasks,StringPos;
1690 DWORD ZeroBroadcast;
1691
1692 AdapterNameA = (char*)AdapterName;
1693 if(AdapterNameA[1] != 0) { //ASCII
1694 AdapterNameU = SChar2WChar(AdapterNameA);
1695 AdapterName = AdapterNameU;
1696 } else { //Unicode
1697 AdapterNameU = NULL;
1698 }
1699 ifname = wcsrchr(AdapterName, '\\');
1700 if (ifname == NULL)
1701 ifname = AdapterName;
1702 else
1703 ifname++;
1704 if (wcsncmp(ifname, L"NPF_", 4) == 0)
1705 ifname += 4;
1706
1707 if( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1708 TEXT("SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"),
1709 0, KEY_READ, &UnderTcpKey) == ERROR_SUCCESS)
1710 {
1711 status = RegOpenKeyExW(UnderTcpKey,ifname,0,KEY_READ,&TcpIpKey);
1712 if (status != ERROR_SUCCESS) {
1713 RegCloseKey(UnderTcpKey);
1714 goto fail;
1715 }
1716 }
1717 else
1718 {
1719
1720 // Query the registry key with the interface's adresses
1721 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1722 TEXT("SYSTEM\\ControlSet001\\Services"),
1723 0,KEY_READ,&SystemKey);
1724 if (status != ERROR_SUCCESS)
1725 goto fail;
1726 status = RegOpenKeyExW(SystemKey,ifname,0,KEY_READ,&InterfaceKey);
1727 if (status != ERROR_SUCCESS) {
1728 RegCloseKey(SystemKey);
1729 goto fail;
1730 }
1731 RegCloseKey(SystemKey);
1732 status = RegOpenKeyEx(InterfaceKey,TEXT("Parameters"),0,KEY_READ,&ParametersKey);
1733 if (status != ERROR_SUCCESS) {
1734 RegCloseKey(InterfaceKey);
1735 goto fail;
1736 }
1737 RegCloseKey(InterfaceKey);
1738 status = RegOpenKeyEx(ParametersKey,TEXT("TcpIp"),0,KEY_READ,&TcpIpKey);
1739 if (status != ERROR_SUCCESS) {
1740 RegCloseKey(ParametersKey);
1741 goto fail;
1742 }
1743 RegCloseKey(ParametersKey);
1744 BufLen = sizeof String;
1745 }
1746
1747 BufLen = 4;
1748 /* Try to detect if the interface has a zero broadcast addr */
1749 status=RegQueryValueEx(TcpIpKey,TEXT("UseZeroBroadcast"),NULL,&RegType,(LPBYTE)&ZeroBroadcast,&BufLen);
1750 if (status != ERROR_SUCCESS)
1751 ZeroBroadcast=0;
1752
1753 BufLen = 4;
1754 /* See if DHCP is used by this system */
1755 status=RegQueryValueEx(TcpIpKey,TEXT("EnableDHCP"),NULL,&RegType,(LPBYTE)&DHCPEnabled,&BufLen);
1756 if (status != ERROR_SUCCESS)
1757 DHCPEnabled=0;
1758
1759
1760 /* Retrieve the adrresses */
1761 if(DHCPEnabled){
1762
1763 BufLen = sizeof String;
1764 // Open the key with the addresses
1765 status = RegQueryValueEx(TcpIpKey,TEXT("DhcpIPAddress"),NULL,&RegType,(LPBYTE)String,&BufLen);
1766 if (status != ERROR_SUCCESS) {
1767 RegCloseKey(TcpIpKey);
1768 goto fail;
1769 }
1770
1771 // scan the key to obtain the addresses
1772 StringPos = 0;
1773 for(naddrs = 0;naddrs <* NEntries;naddrs++){
1774 TmpAddr = (struct sockaddr_in *) &(buffer[naddrs].IPAddress);
1775
1776 if((TmpAddr->sin_addr.S_un.S_addr = inet_addrU(String + StringPos))!= -1){
1777 TmpAddr->sin_family = AF_INET;
1778
1779 TmpBroad = (struct sockaddr_in *) &(buffer[naddrs].Broadcast);
1780 TmpBroad->sin_family = AF_INET;
1781 if(ZeroBroadcast==0)
1782 TmpBroad->sin_addr.S_un.S_addr = 0xffffffff; // 255.255.255.255
1783 else
1784 TmpBroad->sin_addr.S_un.S_addr = 0; // 0.0.0.0
1785
1786 while(*(String + StringPos) != 0)StringPos++;
1787 StringPos++;
1788
1789 if(*(String + StringPos) == 0 || (StringPos * sizeof (WCHAR)) >= BufLen)
1790 break;
1791 }
1792 else break;
1793 }
1794
1795 BufLen = sizeof String;
1796 // Open the key with the netmasks
1797 status = RegQueryValueEx(TcpIpKey,TEXT("DhcpSubnetMask"),NULL,&RegType,(LPBYTE)String,&BufLen);
1798 if (status != ERROR_SUCCESS) {
1799 RegCloseKey(TcpIpKey);
1800 goto fail;
1801 }
1802
1803 // scan the key to obtain the masks
1804 StringPos = 0;
1805 for(nmasks = 0;nmasks < *NEntries;nmasks++){
1806 TmpAddr = (struct sockaddr_in *) &(buffer[nmasks].SubnetMask);
1807
1808 if((TmpAddr->sin_addr.S_un.S_addr = inet_addrU(String + StringPos))!= -1){
1809 TmpAddr->sin_family = AF_INET;
1810
1811 while(*(String + StringPos) != 0)StringPos++;
1812 StringPos++;
1813
1814 if(*(String + StringPos) == 0 || (StringPos * sizeof (WCHAR)) >= BufLen)
1815 break;
1816 }
1817 else break;
1818 }
1819
1820 // The number of masks MUST be equal to the number of adresses
1821 if(nmasks != naddrs){
1822 RegCloseKey(TcpIpKey);
1823 goto fail;
1824 }
1825
1826 }
1827 else{
1828
1829 BufLen = sizeof String;
1830 // Open the key with the addresses
1831 status = RegQueryValueEx(TcpIpKey,TEXT("IPAddress"),NULL,&RegType,(LPBYTE)String,&BufLen);
1832 if (status != ERROR_SUCCESS) {
1833 RegCloseKey(TcpIpKey);
1834 goto fail;
1835 }
1836
1837 // scan the key to obtain the addresses
1838 StringPos = 0;
1839 for(naddrs = 0;naddrs < *NEntries;naddrs++){
1840 TmpAddr = (struct sockaddr_in *) &(buffer[naddrs].IPAddress);
1841
1842 if((TmpAddr->sin_addr.S_un.S_addr = inet_addrU(String + StringPos))!= -1){
1843 TmpAddr->sin_family = AF_INET;
1844
1845 TmpBroad = (struct sockaddr_in *) &(buffer[naddrs].Broadcast);
1846 TmpBroad->sin_family = AF_INET;
1847 if(ZeroBroadcast==0)
1848 TmpBroad->sin_addr.S_un.S_addr = 0xffffffff; // 255.255.255.255
1849 else
1850 TmpBroad->sin_addr.S_un.S_addr = 0; // 0.0.0.0
1851
1852 while(*(String + StringPos) != 0)StringPos++;
1853 StringPos++;
1854
1855 if(*(String + StringPos) == 0 || (StringPos * sizeof (WCHAR)) >= BufLen)
1856 break;
1857 }
1858 else break;
1859 }
1860
1861 BufLen = sizeof String;
1862 // Open the key with the netmasks
1863 status = RegQueryValueEx(TcpIpKey,TEXT("SubnetMask"),NULL,&RegType,(LPBYTE)String,&BufLen);
1864 if (status != ERROR_SUCCESS) {
1865 RegCloseKey(TcpIpKey);
1866 goto fail;
1867 }
1868
1869 // scan the key to obtain the masks
1870 StringPos = 0;
1871 for(nmasks = 0;nmasks <* NEntries;nmasks++){
1872 TmpAddr = (struct sockaddr_in *) &(buffer[nmasks].SubnetMask);
1873
1874 if((TmpAddr->sin_addr.S_un.S_addr = inet_addrU(String + StringPos))!= -1){
1875 TmpAddr->sin_family = AF_INET;
1876
1877 while(*(String + StringPos) != 0)StringPos++;
1878 StringPos++;
1879
1880 if(*(String + StringPos) == 0 || (StringPos * sizeof (WCHAR)) >= BufLen)
1881 break;
1882 }
1883 else break;
1884 }
1885
1886 // The number of masks MUST be equal to the number of adresses
1887 if(nmasks != naddrs){
1888 RegCloseKey(TcpIpKey);
1889 goto fail;
1890 }
1891
1892 }
1893
1894 *NEntries = naddrs + 1;
1895
1896 RegCloseKey(TcpIpKey);
1897
1898 if (status != ERROR_SUCCESS) {
1899 goto fail;
1900 }
1901
1902
1903 if (AdapterNameU != NULL)
1904 free(AdapterNameU);
1905 return TRUE;
1906
1907 fail:
1908 if (AdapterNameU != NULL)
1909 free(AdapterNameU);
1910 return FALSE;
1911 }
1912
1913 /*!
1914 \brief Returns the IP address and the netmask of an adapter.
1915 \param AdapterName String that contain _ADAPTER structure.
1916 \param netp Pointer to a variable that will receive the IP address of the adapter.
1917 \param maskp Pointer to a variable that will receive the netmask of the adapter.
1918 \return If the function succeeds, the return value is nonzero.
1919
1920 \note this function is obsolete and is maintained for backward compatibility. Use PacketGetNetInfoEx() instead.
1921 */
1922
1923 BOOLEAN PacketGetNetInfo(LPTSTR AdapterName, PULONG netp, PULONG maskp)
1924 {
1925 char *AdapterNameA;
1926 WCHAR *AdapterNameU;
1927 WCHAR *ifname;
1928 HKEY SystemKey;
1929 HKEY InterfaceKey;
1930 HKEY ParametersKey;
1931 HKEY TcpIpKey;
1932 LONG status;
1933 WCHAR String[1024+1];
1934 DWORD RegType;
1935 ULONG BufLen;
1936 DWORD DHCPEnabled;
1937 ULONG TAddr,i;
1938
1939 AdapterNameA = (char*)AdapterName;
1940 if(AdapterNameA[1] != 0) { //ASCII
1941 AdapterNameU = SChar2WChar(AdapterNameA);
1942 AdapterName = AdapterNameU;
1943 } else { //Unicode
1944 AdapterNameU = NULL;
1945 }
1946 ifname = wcsrchr(AdapterName, '\\');
1947 if (ifname == NULL)
1948 ifname = AdapterName;
1949 else
1950 ifname++;
1951 if (wcsncmp(ifname, L"NPF_", 4) == 0)
1952 ifname += 4;
1953 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
1954 TEXT("SYSTEM\\ControlSet001\\Services"),
1955 0,KEY_READ,&SystemKey);
1956 if (status != ERROR_SUCCESS)
1957 goto fail;
1958 status = RegOpenKeyExW(SystemKey,ifname,0,KEY_READ,&InterfaceKey);
1959 if (status != ERROR_SUCCESS) {
1960 RegCloseKey(SystemKey);
1961 goto fail;
1962 }
1963 RegCloseKey(SystemKey);
1964 status = RegOpenKeyEx(InterfaceKey,TEXT("Parameters"),0,KEY_READ,&ParametersKey);
1965 if (status != ERROR_SUCCESS) {
1966 RegCloseKey(InterfaceKey);
1967 goto fail;
1968 }
1969 RegCloseKey(InterfaceKey);
1970 status = RegOpenKeyEx(ParametersKey,TEXT("TcpIp"),0,KEY_READ,&TcpIpKey);
1971 if (status != ERROR_SUCCESS) {
1972 RegCloseKey(ParametersKey);
1973 goto fail;
1974 }
1975 RegCloseKey(ParametersKey);
1976
1977 BufLen = 4;
1978 /* See if DHCP is used by this system */
1979 status=RegQueryValueEx(TcpIpKey,TEXT("EnableDHCP"),NULL,&RegType,(LPBYTE)&DHCPEnabled,&BufLen);
1980 if (status != ERROR_SUCCESS)
1981 DHCPEnabled=0;
1982
1983
1984 /* Retrieve the netmask */
1985 if(DHCPEnabled){
1986
1987 BufLen = sizeof String;
1988 status = RegQueryValueEx(TcpIpKey,TEXT("DhcpIPAddress"),NULL,&RegType,(LPBYTE)String,&BufLen);
1989 if (status != ERROR_SUCCESS) {
1990 RegCloseKey(TcpIpKey);
1991 goto fail;
1992 }
1993
1994 TAddr = inet_addrU(String);
1995 // swap bytes for backward compatibility
1996 for(i=0;i<4;i++){
1997 *((char*)netp+i) = *((char*)&TAddr+3-i);
1998 }
1999
2000 BufLen = sizeof String;
2001 status=RegQueryValueEx(TcpIpKey,TEXT("DHCPSubnetMask"),NULL,&RegType,
2002 (LPBYTE)String,&BufLen);
2003
2004 TAddr = inet_addrU(String);
2005 // swap bytes for backward compatibility
2006 for(i=0;i<4;i++){
2007 *((char*)maskp+i) = *((char*)&TAddr+3-i);
2008 }
2009
2010
2011 }
2012 else{
2013
2014 BufLen = sizeof String;
2015 status = RegQueryValueEx(TcpIpKey,TEXT("IPAddress"),NULL,&RegType,(LPBYTE)String,&BufLen);
2016 if (status != ERROR_SUCCESS) {
2017 RegCloseKey(TcpIpKey);
2018 goto fail;
2019 }
2020
2021 TAddr = inet_addrU(String);
2022 // swap bytes for backward compatibility
2023 for(i=0;i<4;i++){
2024 *((char*)netp+i) = *((char*)&TAddr+3-i);
2025 }
2026
2027 BufLen = sizeof String;
2028 status=RegQueryValueEx(TcpIpKey,TEXT("SubnetMask"),NULL,&RegType,
2029 (LPBYTE)String,&BufLen);
2030
2031 TAddr = inet_addrU(String);
2032 // swap bytes for backward compatibility
2033 for(i=0;i<4;i++){
2034 *((char*)maskp+i) = *((char*)&TAddr+3-i);
2035 }
2036
2037
2038 }
2039
2040 if (status != ERROR_SUCCESS) {
2041 RegCloseKey(TcpIpKey);
2042 goto fail;
2043 }
2044
2045
2046 if (AdapterNameU != NULL)
2047 free(AdapterNameU);
2048 return TRUE;
2049
2050 fail:
2051 if (AdapterNameU != NULL)
2052 free(AdapterNameU);
2053 return FALSE;
2054 }
2055
2056 /* @} */