2 * Copyright (c) 1999 - 2003
3 * NetGroup, Politecnico di Torino (Italy)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #pragma VxD_LOCKED_CODE_SEG
43 #pragma VxD_LOCKED_DATA_SEG
45 /*head of the open instances*/
46 PDEVICE_EXTENSION GlobalDeviceExtension
= 0;
48 POPEN_INSTANCE InstToClose
[128];
50 /*number of processes attached to this driver*/
54 /************************************************************
55 This routine initializes the Packet driver.
57 DriverObject - Pointer to driver object created by system.
58 RegistryPath - Pointer to the Unicode name of the registry path
61 The function value is the final status from the initialization operation.
62 ************************************************************/
64 DriverEntry( IN PDRIVER_OBJECT DriverObject
,
65 IN PUNICODE_STRING RegistryPath
68 NDIS_PROTOCOL_CHARACTERISTICS ProtocolChar
;
69 NDIS_STRING ProtoName
= NDIS_STRING_CONST("PACKET");
70 NDIS_HANDLE NdisProtocolHandle
;
72 TRACE_ENTER( "DriverEntry" );
75 NdisAllocateMemory( (PVOID
*)&GlobalDeviceExtension
, sizeof( DEVICE_EXTENSION
), 0, -1 );
76 if ( GlobalDeviceExtension
!= NULL
)
78 NdisZeroMemory( (UCHAR
*)GlobalDeviceExtension
, sizeof(DEVICE_EXTENSION
) );
79 NdisZeroMemory( (UCHAR
*)&ProtocolChar
, sizeof(NDIS_PROTOCOL_CHARACTERISTICS
) );
80 ProtocolChar
.MajorNdisVersion
= 0x03;
81 ProtocolChar
.MinorNdisVersion
= 0x0A;
82 ProtocolChar
.Reserved
= 0;
83 ProtocolChar
.OpenAdapterCompleteHandler
= PacketOpenAdapterComplete
;
84 ProtocolChar
.CloseAdapterCompleteHandler
= PacketUnbindAdapterComplete
;
85 ProtocolChar
.SendCompleteHandler
= PacketSendComplete
;
86 ProtocolChar
.TransferDataCompleteHandler
= PacketTransferDataComplete
;
87 ProtocolChar
.ResetCompleteHandler
= PacketResetComplete
;
88 ProtocolChar
.RequestCompleteHandler
= PacketRequestComplete
;
89 ProtocolChar
.ReceiveHandler
= Packet_tap
;
90 ProtocolChar
.ReceiveCompleteHandler
= PacketReceiveComplete
;
91 ProtocolChar
.StatusHandler
= PacketStatus
;
92 ProtocolChar
.StatusCompleteHandler
= PacketStatusComplete
;
93 ProtocolChar
.BindAdapterHandler
= PacketBindAdapter
;
94 ProtocolChar
.UnbindAdapterHandler
= PacketUnbindAdapter
;
95 ProtocolChar
.UnloadProtocolHandler
= PacketUnload
;
96 ProtocolChar
.Name
= ProtoName
;
97 NdisRegisterProtocol( &Status
,
98 &GlobalDeviceExtension
->NdisProtocolHandle
,
100 sizeof(NDIS_PROTOCOL_CHARACTERISTICS
) );
101 if (Status
!= NDIS_STATUS_SUCCESS
)
103 NdisFreeMemory( GlobalDeviceExtension
, sizeof( DEVICE_EXTENSION
) , 0 );
104 IF_TRACE( "Failed to register protocol with NDIS" );
105 INIT_LEAVE( "DriverEntry" );
108 /*initializes the list of the open instances*/
109 NdisAllocateSpinLock( &(GlobalDeviceExtension
->OpenSpinLock
) );
110 InitializeListHead( &GlobalDeviceExtension
->OpenList
);
111 GlobalDeviceExtension
->DriverObject
= DriverObject
;
113 if(Bind_Names() != NDIS_STATUS_SUCCESS
) return NDIS_STATUS_FAILURE
;
115 IF_TRACE( "protocol registered with NDIS!!!" );
116 INIT_LEAVE( "DriverEntry" );
119 IF_TRACE( "Memory Failure" );
121 TRACE_LEAVE( "DriverEntry" );
123 return NDIS_STATUS_RESOURCES
;
127 /************************************************************
128 Function used to associate the names of the network devices
129 with the internal NDIS names
131 OUTPUT: NDIS_STATUS_SUCCESS if succesful, otherwise NDIS_STATUS_FAILURE
132 ************************************************************/
133 DWORD
Bind_Names(void){
142 TRACE_ENTER( "Bind_Names" );
144 // initialize the list of adapter names
145 InitializeListHead( &GlobalDeviceExtension
->AdapterNames
);
147 // change to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\Net
148 res
=VMM_RegOpenKey(HKEY_LOCAL_MACHINE
,"SYSTEM",&Key
);
149 res
=VMM_RegOpenKey(Key
,"CURRENTCONTROLSET",&Key
);
150 res
=VMM_RegOpenKey(Key
,"SERVICES",&Key
);
151 res
=VMM_RegOpenKey(Key
,"CLASS",&Key
);
152 res
=VMM_RegOpenKey(Key
,"NET",&Key
);
154 if(res
!=ERROR_SUCCESS
) return NDIS_STATUS_FAILURE
;
157 // Scan the list of the adapters
158 while(VMM_RegEnumKey(Key
,i
,NdisName
,Klen
)==ERROR_SUCCESS
)
160 res
=VMM_RegOpenKey(Key
,NdisName
,&Key1
);
161 res
=VMM_RegOpenKey(Key1
,"NDIS",&Key1
);
163 res
=VMM_RegQueryValueEx(Key1
,"LOGDRIVERNAME",NULL
,NULL
, DevName
,&Klen1
);
164 if(res
!=ERROR_SUCCESS
){
170 NdisAllocateMemory( (PVOID
*)&AName
, sizeof(ADAPTER_NAME
), 0, -1 );
173 return NDIS_STATUS_FAILURE
;
176 NdisMoveMemory(AName
->realname
,NdisName
,Klen
);
177 NdisMoveMemory(AName
->devicename
,DevName
,Klen1
);
178 AName
->realnamestr
.Length
=strlen(NdisName
);
179 AName
->realnamestr
.MaximumLength
=Klen
;
180 AName
->realnamestr
.Buffer
=AName
->realname
;
182 InsertHeadList( &GlobalDeviceExtension
->AdapterNames
, &AName
->ListElement
);
188 TRACE_LEAVE( "Bind_Names" );
190 if(i
==0) return NDIS_STATUS_FAILURE
;
191 else return NDIS_STATUS_SUCCESS
;
195 /************************************************************
196 Callback function called by NDIS when the last insatnce of
197 the packet driver is closed by the capture driver,
198 i.e. when the driver is unloaded
201 ************************************************************/
202 VOID NDIS_API
PacketUnload()
204 TRACE_ENTER( "Unload" );
206 TRACE_LEAVE( "Unload" );
209 /************************************************************
210 this function returns the descriptor of the adapter from
211 the device ID and process tag
212 INPUT: Name of the adapter to open
213 OUTPUT: instance of the driver
214 ************************************************************/
215 POPEN_INSTANCE
GetRunningAdapter(DWORD hDevice
,DWORD tagProcess
)
218 DWORD dwSec_Counter
=1000; // Or something like that
220 POPEN_INSTANCE pOpen
;
221 PWRAPPER_MAC_BLOCK pWMBlock
;
222 PNDIS_MAC_CHARACTERISTICS pNMChar
;
226 NdisAcquireSpinLock(&GlobalDeviceExtension
->OpenSpinLock
);
228 pHead
= &(GlobalDeviceExtension
->OpenList
);
235 pOpen
= CONTAINING_RECORD( pEntry
, OPEN_INSTANCE
, ListElement
);
236 if((pOpen
->hDevice
==hDevice
)&&(pOpen
->tagProcess
==tagProcess
)){
237 NdisReleaseSpinLock( &GlobalDeviceExtension
->OpenSpinLock
);
240 pEntry
=pEntry
->Flink
;
243 }while ((pEntry
!= pHead
)&&(dwSec_Counter
));
245 NdisReleaseSpinLock( &GlobalDeviceExtension
->OpenSpinLock
);
249 /************************************************************
250 this function returns the NDIS name of an adapter given its
252 INPUT: Name of the adapter to open
253 OUTPUT: instance of the driver
254 ************************************************************/
256 PNDIS_STRING
GetNDISAdapterName(BYTE
* DeviceName
)
260 PLIST_ENTRY pHead
= &(GlobalDeviceExtension
->AdapterNames
);
263 TRACE_ENTER( "GetNDISAdapterName" );
267 if(IsListEmpty(pHead
)){
268 if(Bind_Names()==NDIS_STATUS_FAILURE
)
273 pAdap
= CONTAINING_RECORD( pEntry
, ADAPTER_NAME
, ListElement
);
274 if(compare(pAdap
->devicename
,DeviceName
)==1)return &(pAdap
->realnamestr
);
275 pEntry
=pEntry
->Flink
;
276 }while (pEntry
!= pHead
|| count
++>32);
278 TRACE_LEAVE( "GetNDISAdapterName" );
283 /************************************************************
284 This function evaluates the length of a string.
285 Useful to avoid the string library functions that are not
286 defined at this level
287 ************************************************************/
292 while ( *s
++ ) len
++;
297 /************************************************************
298 This function compares two strings
299 ************************************************************/
300 BYTE
compare(BYTE
*s1
,BYTE
*s2
)
302 TRACE_ENTER( "compare" );
306 if (*s1
!=*s2
) return (BYTE
) 0;
313 TRACE_LEAVE( "compare" );
315 if ((*s1
==0) && (*s2
==0)) return (BYTE
) 1;
316 else return (BYTE
) 0;
319 /************************************************************
320 Return the names of all the MAC drivers on which the driver
322 INPUT: dwDDB e hDevice - parameters coming from the
323 DeviceIOControl procedure, not used here.
324 OUTPUT: pDiocParms - structure containing the returned buffer
325 ************************************************************/
327 DWORD
PacketGetMacNameList( DWORD dwDDB
,
329 PDIOCPARAMETERS pDiocParms
)
334 PWRAPPER_MAC_BLOCK pWMBlock
;
335 PNDIS_MAC_CHARACTERISTICS pNMChar
;
338 PLIST_ENTRY pHead
= &(GlobalDeviceExtension
->AdapterNames
);
341 TRACE_ENTER( "PacketGetMacNameList" );
345 pAdap
= CONTAINING_RECORD( pEntry
, ADAPTER_NAME
, ListElement
);
346 uLength
= strlen( pAdap
->devicename
);
348 if ( uLength
< pDiocParms
->cbOutBuffer
- dwBytes
- 1 )
350 strcat( (BYTE
*)(pDiocParms
->lpvOutBuffer
), pAdap
->devicename
);
351 strcat( (BYTE
*)(pDiocParms
->lpvOutBuffer
), " " );
352 dwBytes
+= (uLength
+ 1);
356 pEntry
=pEntry
->Flink
;
357 }while (pEntry
!= pHead
);
359 *(ULONG
*)(pDiocParms
->lpcbBytesReturned
) = dwBytes
;
360 IF_TRACE_MSG( " Bytes Returned: %lu", *(ULONG
*)(pDiocParms
->lpcbBytesReturned
) );
362 TRACE_LEAVE( "PacketGetMacNameList" );
364 return NDIS_STATUS_SUCCESS
;
368 /************************************************************
369 This is the dispatch routine for create/open and close requests.
370 These requests complete successfully.
371 INPUT: dwDDB e hDevice - parameters sent by the DeviceIOControl procedure
372 dwService - requested service
373 pDiocParms - structure containing the parameters of the call
374 OUTPUT: the status of the operation
375 ************************************************************/
377 DWORD _stdcall
PacketIOControl( DWORD dwService
,
380 PDIOCPARAMETERS pDiocParms
)
387 PPACKET_OID_DATA reqbuff
;
388 POPEN_INSTANCE Open
,tOpen
;
397 TRACE_ENTER( "DeviceIoControl" );
399 if(!(dwService
==IOCTL_PROTOCOL_MACNAME
||
400 dwService
==IOCTL_OPEN
||
402 Open
=GetRunningAdapter(hDevice
,pDiocParms
->tagProcess
);
403 if(Open
==NULL
) return NDIS_STATUS_FAILURE
;
408 case IOCTL_OPEN
: //open message
412 //get the NDIS name of current adapter
413 str
=GetNDISAdapterName((BYTE
*)pDiocParms
->lpvInBuffer
);
415 if(str
==NULL
) return NDIS_STATUS_FAILURE
;
416 //try to open an instance of the adapter
417 Status
= PacketOpen( str
, dwDDB
, hDevice
, pDiocParms
);
425 case BIOCGSTATS
: //fuction to obtain the capture stats
427 StatsBuf
=(int*)pDiocParms
->lpvOutBuffer
;
428 StatsBuf
[0]=Open
->Received
;
429 StatsBuf
[1]=Open
->Dropped
;
430 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 8;
431 return NDIS_STATUS_SUCCESS
;
436 case BIOCEVNAME
: //fuction to set the shared Event
438 Open
->ReadEvent
=((DWORD
*)pDiocParms
->lpvInBuffer
)[0];
439 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 0;
441 return NDIS_STATUS_SUCCESS
;
446 case BIOCSETF
: //fuction to set a new bpf filter
448 /*free the previous buffer if it was present*/
449 if(Open
->bpfprogram
!=NULL
){
450 NdisFreeMemory(Open
->bpfprogram
,Open
->bpfprogramlen
,0);
451 Open
->bpfprogram
=NULL
; //NULL means accept all
452 Open
->bpfprogramlen
=0;
455 /*get the pointer to the new program*/
456 prog
=(PUCHAR
)pDiocParms
->lpvInBuffer
;
458 /*before accepting the program we must check that it's valid
459 Otherwise, a bogus program could easily crash the system*/
461 Open
->bpfprogramlen
=pDiocParms
->cbInBuffer
;
462 if(bpf_validate((struct bpf_insn
*)prog
,Open
->bpfprogramlen
/sizeof(struct bpf_insn
))==0)
464 Open
->bpfprogramlen
=0;
465 Open
->bpfprogram
=NULL
;
466 return NDIS_STATUS_FAILURE
; // filter not accepted
469 /*allocate the memory to contain the new filter program*/
470 if(NdisAllocateMemory(&Open
->bpfprogram
,Open
->bpfprogramlen
, 0, -1 )==NDIS_STATUS_FAILURE
)
473 Open
->bpfprogramlen
=0;
474 Open
->bpfprogram
=NULL
;
475 return NDIS_STATUS_FAILURE
;
478 /*copy the program in the new buffer*/
479 NdisMoveMemory(Open
->bpfprogram
,prog
,Open
->bpfprogramlen
);
481 /*reset the buffer that could contain packets that don't match the filter*/
488 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = Open
->bpfprogramlen
;
493 case BIOCSETBUFFERSIZE
: //function to set the dimension of the buffer for the packets
495 /*get the size to allocate*/
496 dim
=((PULONG
)pDiocParms
->lpvInBuffer
)[0];
497 /*free the old buffer*/
498 if(Open
->Buffer
!=NULL
)
499 NdisFreeMemory(Open
->Buffer
,Open
->BufSize
,0);
502 /*allocate the new buffer*/
505 NdisAllocateMemory( (PVOID
*)&tpointer
,dim
, 0, -1 );
510 return NDIS_STATUS_FAILURE
;
513 Open
->Buffer
=tpointer
;
519 Open
->BufSize
=(UINT
)dim
;
521 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = dim
;
527 mode
=((PULONG
)pDiocParms
->lpvInBuffer
)[0];
529 Open
->mode
=MODE_STAT
;
533 if(Open
->TimeOut
==0)Open
->TimeOut
=1000;
535 else if(mode
==MODE_CAPT
){
536 Open
->mode
=MODE_CAPT
;
537 return NDIS_STATUS_SUCCESS
;
540 return NDIS_STATUS_FAILURE
;
547 timeout
=((PULONG
)pDiocParms
->lpvInBuffer
)[0];
548 Open
->TimeOut
=timeout
;
550 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = timeout
;
556 timezone
=((PSHORT
)pDiocParms
->lpvInBuffer
)[0];
558 Open
->StartTime
+=((__int64
)timezone
)*(__int64
)1193182*60;
560 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = timezone
;
564 case BIOCSWRITEREP
: //set the writes repetition number
566 Open
->Nwrites
=((PULONG
)pDiocParms
->lpvInBuffer
)[0];
568 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = Open
->Nwrites
;
572 case DIOC_CLOSEHANDLE
:
573 Status
=PacketClose( Open
, dwDDB
, hDevice
, pDiocParms
);
578 if ( GlobalDeviceExtension
)
580 //If any instance is still opened we must close it
581 NdisAcquireSpinLock(&GlobalDeviceExtension
->OpenSpinLock
);
585 pHead
= &(GlobalDeviceExtension
->OpenList
);
586 if(pHead
!=NULL
&& !IsListEmpty(pHead
))
588 //count the number of open instances
591 tOpen
= CONTAINING_RECORD( pEntry
, OPEN_INSTANCE
, ListElement
);
593 pEntry
=pEntry
->Flink
;
595 InstToClose
[nOpen
++]=tOpen
;
597 }while (pEntry
!= pHead
);
599 for(i
=0;i
<nOpen
;i
++){
600 PacketClose(InstToClose
[i
],0,InstToClose
[i
]->hDevice
,NULL
);
604 NdisReleaseSpinLock( &GlobalDeviceExtension
->OpenSpinLock
);
606 //free the names' list
607 pHead
= &(GlobalDeviceExtension
->AdapterNames
);
610 while((pEntry
=PacketRemoveHeadList(pHead
))!=NULL
){
611 AName
= CONTAINING_RECORD( pEntry
, ADAPTER_NAME
, ListElement
);
612 NdisFreeMemory(AName
,sizeof(ADAPTER_NAME
),0);
616 //unregister the protocol from NDIS
617 NdisDeregisterProtocol( &Status
, GlobalDeviceExtension
->NdisProtocolHandle
);
619 //free the global device extension
620 NdisFreeMemory(GlobalDeviceExtension
,sizeof( DEVICE_EXTENSION
),0);
625 case IOCTL_PROTOCOL_RESET
:
627 PacketReset( &Status
, Open
);
633 case IOCTL_PROTOCOL_STATISTICS
:
635 return PacketRequest( Open
, dwService
, dwDDB
, hDevice
, pDiocParms
);
637 case IOCTL_PROTOCOL_READ
:
639 return PacketRead( Open
, dwDDB
, hDevice
, pDiocParms
);
641 case IOCTL_PROTOCOL_WRITE
:
643 return PacketWrite( Open
, dwDDB
, hDevice
, pDiocParms
);
645 case IOCTL_PROTOCOL_MACNAME
:
647 PacketGetMacNameList( dwDDB
, hDevice
, pDiocParms
);
652 *(DWORD
*)(pDiocParms
->lpcbBytesReturned
) = 0;
655 TRACE_LEAVE( "DeviceIoControl" );
657 return NDIS_STATUS_SUCCESS
;
662 /************************************************************
663 Function called by NDIS when there is something to communicate
665 ************************************************************/
668 IN NDIS_HANDLE ProtocolBindingContext
,
669 IN NDIS_STATUS Status
,
670 IN PVOID StatusBuffer
,
671 IN UINT StatusBufferSize
674 TRACE_ENTER( "Status Indication" );
675 TRACE_LEAVE( "Status Indication" );
679 /************************************************************
680 Complete the previous call
681 ************************************************************/
683 PacketStatusComplete(
684 IN NDIS_HANDLE ProtocolBindingContext
688 TRACE_ENTER( "StatusIndicationComplete" );
689 TRACE_LEAVE( "StatusIndicationComplete" );
693 /************************************************************
694 Removes an element from a list.
695 Performs a check to see if the list is empty
696 ************************************************************/
698 PacketRemoveHeadList(
699 IN PLIST_ENTRY pListHead
702 if ( !IsListEmpty( pListHead
) )
704 PLIST_ENTRY pLE
= RemoveHeadList( pListHead
);