2 * Copyright (c) 1999, 2000
3 * Politecnico di Torino. All rights reserved.
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
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.
33 #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
35 static NDIS_MEDIUM MediumArray
[] = {
39 NdisMediumArcnet878_2
,
44 #define NUM_NDIS_MEDIA (sizeof MediumArray / sizeof MediumArray[0])
46 ULONG NamedEventsCounter
=0;
48 //Itoa. Replaces the buggy RtlIntegerToUnicodeString
49 void PacketItoa(UINT n
,PUCHAR buf
){
60 /// Global start time. Used as an absolute reference for timestamp conversion.
61 struct time_conv G_Start_Time
= {
66 UINT n_Opened_Instances
= 0;
68 NDIS_SPIN_LOCK Opened_Instances_Lock
;
70 //-------------------------------------------------------------------
73 NPF_Open(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
76 PDEVICE_EXTENSION DeviceExtension
;
80 PIO_STACK_LOCATION IrpSp
;
83 NDIS_STATUS ErrorStatus
;
87 IF_LOUD(DbgPrint("NPF: OpenAdapter\n");)
89 DeviceExtension
= DeviceObject
->DeviceExtension
;
92 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
94 // allocate some memory for the open structure
95 #define NPF_TAG_OPENSTRUCT TAG('0', 'O', 'W', 'A')
96 Open
=ExAllocatePoolWithTag(NonPagedPool
, sizeof(OPEN_INSTANCE
), NPF_TAG_OPENSTRUCT
);
101 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
102 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
103 return STATUS_INSUFFICIENT_RESOURCES
;
108 sizeof(OPEN_INSTANCE
)
112 #define NPF_TAG_EVNAME TAG('1', 'O', 'W', 'A')
113 EvName
=ExAllocatePoolWithTag(NonPagedPool
, sizeof(L
"\\BaseNamedObjects\\NPF0000000000"), NPF_TAG_EVNAME
);
118 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
119 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
120 return STATUS_INSUFFICIENT_RESOURCES
;
124 IrpSp
->FileObject
->FsContext
=Open
;
126 Open
->DeviceExtension
=DeviceExtension
;
129 // Save the Irp here for the completeion routine to retrieve
130 Open
->OpenCloseIrp
=Irp
;
132 // Allocate a packet pool for our xmit and receive packets
133 NdisAllocatePacketPool(
137 sizeof(PACKET_RESERVED
));
140 if (Status
!= NDIS_STATUS_SUCCESS
) {
142 IF_LOUD(DbgPrint("NPF: Failed to allocate packet pool\n");)
146 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
147 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
148 return STATUS_INSUFFICIENT_RESOURCES
;
152 RtlCopyBytes(EvName
,L
"\\BaseNamedObjects\\NPF0000000000",sizeof(L
"\\BaseNamedObjects\\NPF0000000000"));
154 //Create the string containing the name of the read event
155 RtlInitUnicodeString(&Open
->ReadEventName
,(PCWSTR
) EvName
);
157 PacketItoa(NamedEventsCounter
,(PUCHAR
)(Open
->ReadEventName
.Buffer
+21));
159 InterlockedIncrement((PLONG
)&NamedEventsCounter
);
161 IF_LOUD(DbgPrint("\nCreated the named event for the read; name=%ws, counter=%d\n", Open
->ReadEventName
.Buffer
,NamedEventsCounter
-1);)
163 //allocate the event objects
164 Open
->ReadEvent
=IoCreateNotificationEvent(&Open
->ReadEventName
,&Open
->ReadEventHandle
);
165 if(Open
->ReadEvent
==NULL
){
168 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
169 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
170 return STATUS_INSUFFICIENT_RESOURCES
;
173 KeInitializeEvent(Open
->ReadEvent
, NotificationEvent
, FALSE
);
174 KeClearEvent(Open
->ReadEvent
);
175 NdisInitializeEvent(&Open
->WriteEvent
);
176 NdisInitializeEvent(&Open
->IOEvent
);
177 NdisInitializeEvent(&Open
->DumpEvent
);
178 NdisInitializeEvent(&Open
->IOEvent
);
179 NdisAllocateSpinLock(&Open
->machine_lock
);
182 // list to hold irp's want to reset the adapter
183 InitializeListHead(&Open
->ResetIrpList
);
186 // Initialize the request list
187 KeInitializeSpinLock(&Open
->RequestSpinLock
);
188 InitializeListHead(&Open
->RequestList
);
190 // Initializes the extended memory of the NPF machine
191 #define NPF_TAG_MACHINE TAG('2', 'O', 'W', 'A')
192 Open
->mem_ex
.buffer
= ExAllocatePoolWithTag(NonPagedPool
, DEFAULT_MEM_EX_SIZE
, NPF_TAG_MACHINE
);
193 if((Open
->mem_ex
.buffer
) == NULL
)
198 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
199 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
200 return STATUS_INSUFFICIENT_RESOURCES
;
203 Open
->mem_ex
.size
= DEFAULT_MEM_EX_SIZE
;
204 RtlZeroMemory(Open
->mem_ex
.buffer
, DEFAULT_MEM_EX_SIZE
);
207 // Initialize the open instance
213 Open
->BLastByte
= (UINT
) -1;
214 Open
->Dropped
= 0; //reset the dropped packets counter
215 Open
->Received
= 0; //reset the received packets counter
216 Open
->Accepted
= 0; //reset the accepted packets counter
217 Open
->bpfprogram
= NULL
; //reset the filter
218 Open
->mode
= MODE_CAPT
;
219 Open
->Nbytes
.QuadPart
= 0;
220 Open
->Npackets
.QuadPart
= 0;
222 Open
->Multiple_Write_Counter
= 0;
224 Open
->TimeOut
.QuadPart
= (LONGLONG
)1;
226 Open
->DumpFileName
.Buffer
= NULL
;
227 Open
->DumpFileHandle
= NULL
;
228 Open
->tme
.active
= TME_NONE_ACTIVE
;
229 Open
->DumpLimitReached
= FALSE
;
230 Open
->MaxFrameSize
= 0;
232 //allocate the spinlock for the statistic counters
233 NdisAllocateSpinLock(&Open
->CountersLock
);
235 //allocate the spinlock for the buffer pointers
236 NdisAllocateSpinLock(&Open
->BufLock
);
239 // link up the request stored in our open block
241 for (i
=0;i
<MAX_REQUESTS
;i
++) {
242 ExInterlockedInsertTailList(
244 &Open
->Requests
[i
].ListElement
,
245 &Open
->RequestSpinLock
);
250 IoMarkIrpPending(Irp
);
253 // Try to open the MAC
255 IF_LOUD(DbgPrint("NPF: Openinig the device %ws, BindingContext=%d\n",DeviceExtension
->AdapterName
.Buffer
, Open
);)
260 &Open
->AdapterHandle
,
264 DeviceExtension
->NdisProtocolHandle
,
266 &DeviceExtension
->AdapterName
,
270 IF_LOUD(DbgPrint("NPF: Opened the device, Status=%x\n",Status
);)
272 if (Status
!= NDIS_STATUS_PENDING
)
274 NPF_OpenAdapterComplete(Open
,Status
,NDIS_STATUS_SUCCESS
);
277 return(STATUS_PENDING
);
280 //-------------------------------------------------------------------
282 VOID STDCALL
NPF_OpenAdapterComplete(
283 IN NDIS_HANDLE ProtocolBindingContext
,
284 IN NDIS_STATUS Status
,
285 IN NDIS_STATUS OpenErrorStatus
)
290 PLIST_ENTRY RequestListEntry
;
291 PINTERNAL_REQUEST MaxSizeReq
;
292 NDIS_STATUS ReqStatus
;
295 IF_LOUD(DbgPrint("NPF: OpenAdapterComplete\n");)
297 Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
302 Irp
=Open
->OpenCloseIrp
;
304 if (Status
!= NDIS_STATUS_SUCCESS
) {
306 IF_LOUD(DbgPrint("NPF: OpenAdapterComplete-FAILURE\n");)
308 NdisFreePacketPool(Open
->PacketPool
);
311 Open
->mem_ex
.size
= 0;
312 if(Open
->mem_ex
.buffer
!= NULL
)ExFreePool(Open
->mem_ex
.buffer
);
314 ExFreePool(Open
->ReadEventName
.Buffer
);
316 ZwClose(Open
->ReadEventHandle
);
322 NdisAcquireSpinLock(&Opened_Instances_Lock
);
323 n_Opened_Instances
++;
324 NdisReleaseSpinLock(&Opened_Instances_Lock
);
326 IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances
);)
328 // Get the absolute value of the system boot time.
329 // This is used for timestamp conversion.
330 TIME_SYNCHRONIZE(&G_Start_Time
);
332 // Extract a request from the list of free ones
333 RequestListEntry
=ExInterlockedRemoveHeadList(&Open
->RequestList
, &Open
->RequestSpinLock
);
335 if (RequestListEntry
== NULL
)
338 Open
->MaxFrameSize
= 1514; // Assume Ethernet
340 Irp
->IoStatus
.Status
= Status
;
341 Irp
->IoStatus
.Information
= 0;
342 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
347 MaxSizeReq
= CONTAINING_RECORD(RequestListEntry
, INTERNAL_REQUEST
, ListElement
);
348 MaxSizeReq
->Irp
= Irp
;
349 MaxSizeReq
->Internal
= TRUE
;
352 MaxSizeReq
->Request
.RequestType
= NdisRequestQueryInformation
;
353 MaxSizeReq
->Request
.DATA
.QUERY_INFORMATION
.Oid
= OID_GEN_MAXIMUM_TOTAL_SIZE
;
356 MaxSizeReq
->Request
.DATA
.QUERY_INFORMATION
.InformationBuffer
= &Open
->MaxFrameSize
;
357 MaxSizeReq
->Request
.DATA
.QUERY_INFORMATION
.InformationBufferLength
= 4;
359 // submit the request
363 &MaxSizeReq
->Request
);
366 if (ReqStatus
!= NDIS_STATUS_PENDING
) {
367 NPF_RequestComplete(Open
, &MaxSizeReq
->Request
, ReqStatus
);
374 Irp
->IoStatus
.Status
= Status
;
375 Irp
->IoStatus
.Information
= 0;
376 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
382 //-------------------------------------------------------------------
385 NPF_Close(IN PDEVICE_OBJECT DeviceObject
,IN PIRP Irp
)
390 PIO_STACK_LOCATION IrpSp
;
391 LARGE_INTEGER ThreadDelay
;
393 IF_LOUD(DbgPrint("NPF: CloseAdapter\n");)
395 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
397 Open
=IrpSp
->FileObject
->FsContext
;
399 // Reset the buffer size. This tells the dump thread to stop.
402 if( Open
->Bound
== FALSE
){
404 NdisWaitEvent(&Open
->IOEvent
,10000);
406 // Free the filter if it's present
407 if(Open
->bpfprogram
!= NULL
)
408 ExFreePool(Open
->bpfprogram
);
410 // Free the jitted filter if it's present
411 if(Open
->Filter
!= NULL
)
412 BPF_Destroy_JIT_Filter(Open
->Filter
);
416 if(Open
->Buffer
!= NULL
)ExFreePool(Open
->Buffer
);
419 Open
->mem_ex
.size
= 0;
420 if(Open
->mem_ex
.buffer
!= NULL
)ExFreePool(Open
->mem_ex
.buffer
);
422 NdisFreePacketPool(Open
->PacketPool
);
424 // Free the string with the name of the dump file
425 if(Open
->DumpFileName
.Buffer
!=NULL
)
426 ExFreePool(Open
->DumpFileName
.Buffer
);
428 ExFreePool(Open
->ReadEventName
.Buffer
);
431 Irp
->IoStatus
.Information
= 0;
432 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
433 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
435 return(STATUS_SUCCESS
);
438 // Unfreeze the consumer
439 if(Open
->mode
& MODE_DUMP
)
440 NdisSetEvent(&Open
->DumpEvent
);
442 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
445 Open
->OpenCloseIrp
= Irp
;
447 IoMarkIrpPending(Irp
);
449 // If this instance is in dump mode, complete the dump and close the file
450 if((Open
->mode
& MODE_DUMP
) && Open
->DumpFileHandle
!= NULL
){
453 ThreadDelay
.QuadPart
= -50000000;
454 // Wait the completion of the thread
455 wres
= KeWaitForSingleObject(Open
->DumpThreadObject
,
461 ObDereferenceObject(Open
->DumpThreadObject
);
464 // Flush and close the dump file
465 NPF_CloseDumpFile(Open
);
468 // Destroy the read Event
469 ZwClose(Open
->ReadEventHandle
);
477 if (Status
!= NDIS_STATUS_PENDING
) {
479 NPF_CloseAdapterComplete(
483 return STATUS_SUCCESS
;
487 return(STATUS_PENDING
);
490 //-------------------------------------------------------------------
493 NPF_CloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext
,IN NDIS_STATUS Status
)
498 IF_LOUD(DbgPrint("NPF: CloseAdapterComplete\n");)
500 Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
502 // free the allocated structures only if the instance is still bound to the adapter
503 if(Open
->Bound
== TRUE
){
505 // Free the filter if it's present
506 if(Open
->bpfprogram
!= NULL
)
507 ExFreePool(Open
->bpfprogram
);
509 // Free the jitted filter if it's present
510 if(Open
->Filter
!= NULL
)
511 BPF_Destroy_JIT_Filter(Open
->Filter
);
515 if(Open
->Buffer
!=NULL
)ExFreePool(Open
->Buffer
);
518 Open
->mem_ex
.size
= 0;
519 if(Open
->mem_ex
.buffer
!= NULL
)ExFreePool(Open
->mem_ex
.buffer
);
521 NdisFreePacketPool(Open
->PacketPool
);
523 Irp
=Open
->OpenCloseIrp
;
525 // Free the string with the name of the dump file
526 if(Open
->DumpFileName
.Buffer
!=NULL
)
527 ExFreePool(Open
->DumpFileName
.Buffer
);
529 ExFreePool(Open
->ReadEventName
.Buffer
);
532 // Complete the request only if the instance is still bound to the adapter
533 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
534 Irp
->IoStatus
.Information
= 0;
535 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
538 NdisSetEvent(&Open
->IOEvent
);
540 // Decrease the counter of open instances
541 NdisAcquireSpinLock(&Opened_Instances_Lock
);
542 n_Opened_Instances
--;
543 NdisReleaseSpinLock(&Opened_Instances_Lock
);
545 IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances
);)
547 if(n_Opened_Instances
== 0){
548 // Force a synchronization at the next NPF_Open().
549 // This hopefully avoids the synchronization issues caused by hibernation or standby.
550 TIME_DESYNCHRONIZE(&G_Start_Time
);
556 //-------------------------------------------------------------------
560 NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext
, IN PNET_PNP_EVENT pNetPnPEvent
)
562 IF_LOUD(DbgPrint("NPF: PowerChange\n");)
564 TIME_DESYNCHRONIZE(&G_Start_Time
);
566 TIME_SYNCHRONIZE(&G_Start_Time
);
568 return STATUS_SUCCESS
;
572 //-------------------------------------------------------------------
576 OUT PNDIS_STATUS Status
,
577 IN NDIS_HANDLE BindContext
,
578 IN PNDIS_STRING DeviceName
,
579 IN PVOID SystemSpecific1
,
580 IN PVOID SystemSpecific2
583 IF_LOUD(DbgPrint("NPF: NPF_BindAdapter\n");)
586 //-------------------------------------------------------------------
590 OUT PNDIS_STATUS Status
,
591 IN NDIS_HANDLE ProtocolBindingContext
,
592 IN NDIS_HANDLE UnbindContext
595 POPEN_INSTANCE Open
=(POPEN_INSTANCE
)ProtocolBindingContext
;
598 IF_LOUD(DbgPrint("NPF: NPF_UnbindAdapter\n");)
600 // Reset the buffer size. This tells the dump thread to stop.
603 NdisResetEvent(&Open
->IOEvent
);
605 // This open instance is no more bound to the adapter, set Bound to False
606 InterlockedExchange( (PLONG
) &Open
->Bound
, FALSE
);
608 // Awake a possible pending read on this instance
609 if(Open
->mode
& MODE_DUMP
)
610 NdisSetEvent(&Open
->DumpEvent
);
612 KeSetEvent(Open
->ReadEvent
,0,FALSE
);
614 // If this instance is in dump mode, complete the dump and close the file
615 if((Open
->mode
& MODE_DUMP
) && Open
->DumpFileHandle
!= NULL
)
616 NPF_CloseDumpFile(Open
);
618 // Destroy the read Event
619 ZwClose(Open
->ReadEventHandle
);
627 if (lStatus
!= NDIS_STATUS_PENDING
) {
629 NPF_CloseAdapterComplete(
634 *Status
= NDIS_STATUS_SUCCESS
;
639 *Status
= NDIS_STATUS_SUCCESS
;
643 //-------------------------------------------------------------------
646 NPF_ResetComplete(IN NDIS_HANDLE ProtocolBindingContext
,IN NDIS_STATUS Status
)
652 PLIST_ENTRY ResetListEntry
;
654 IF_LOUD(DbgPrint("NPF: PacketResetComplte\n");)
656 Open
= (POPEN_INSTANCE
)ProtocolBindingContext
;
660 // remove the reset IRP from the list
662 ResetListEntry
=ExInterlockedRemoveHeadList(
664 &Open
->RequestSpinLock
668 if (ResetListEntry
== NULL
) {
674 Irp
=CONTAINING_RECORD(ResetListEntry
,IRP
,Tail
.Overlay
.ListEntry
);
676 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
677 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
679 IF_LOUD(DbgPrint("NPF: PacketResetComplte exit\n");)