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.
27 #include <ddk/ntddk.h>
33 static NDIS_MEDIUM MediumArray[] = {
37 NdisMediumArcnet878_2,
42 #define NUM_NDIS_MEDIA (sizeof MediumArray / sizeof MediumArray[0])
44 ULONG NamedEventsCounter=0;
46 //Itoa. Replaces the buggy RtlIntegerToUnicodeString
47 void PacketItoa(UINT n,PUCHAR buf){
58 /// Global start time. Used as an absolute reference for timestamp conversion.
59 struct time_conv G_Start_Time = {
64 UINT n_Opened_Instances = 0;
66 NDIS_SPIN_LOCK Opened_Instances_Lock;
68 //-------------------------------------------------------------------
70 NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
73 PDEVICE_EXTENSION DeviceExtension;
77 PIO_STACK_LOCATION IrpSp;
80 NDIS_STATUS ErrorStatus;
83 PLIST_ENTRY PacketListEntry;
86 IF_LOUD(DbgPrint("NPF: OpenAdapter\n");)
88 DeviceExtension = DeviceObject->DeviceExtension;
91 IrpSp = IoGetCurrentIrpStackLocation(Irp);
93 // allocate some memory for the open structure
94 #define NPF_TAG_OPENSTRUCT TAG('0', 'O', 'W', 'A')
95 Open=ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), NPF_TAG_OPENSTRUCT);
100 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
101 IoCompleteRequest(Irp, IO_NO_INCREMENT);
102 return STATUS_INSUFFICIENT_RESOURCES;
107 sizeof(OPEN_INSTANCE)
111 #define NPF_TAG_EVNAME TAG('1', 'O', 'W', 'A')
112 EvName=ExAllocatePoolWithTag(NonPagedPool, sizeof(L"\\BaseNamedObjects\\NPF0000000000"), NPF_TAG_EVNAME);
117 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
118 IoCompleteRequest(Irp, IO_NO_INCREMENT);
119 return STATUS_INSUFFICIENT_RESOURCES;
123 IrpSp->FileObject->FsContext=Open;
125 Open->DeviceExtension=DeviceExtension;
128 // Save the Irp here for the completeion routine to retrieve
129 Open->OpenCloseIrp=Irp;
131 // Allocate a packet pool for our xmit and receive packets
132 NdisAllocatePacketPool(
136 sizeof(PACKET_RESERVED));
139 if (Status != NDIS_STATUS_SUCCESS) {
141 IF_LOUD(DbgPrint("NPF: Failed to allocate packet pool\n");)
145 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
146 IoCompleteRequest(Irp, IO_NO_INCREMENT);
147 return STATUS_INSUFFICIENT_RESOURCES;
151 RtlCopyBytes(EvName,L"\\BaseNamedObjects\\NPF0000000000",sizeof(L"\\BaseNamedObjects\\NPF0000000000"));
153 //Create the string containing the name of the read event
154 RtlInitUnicodeString(&Open->ReadEventName,(PCWSTR) EvName);
156 PacketItoa(NamedEventsCounter,(PUCHAR)(Open->ReadEventName.Buffer+21));
158 InterlockedIncrement(&NamedEventsCounter);
160 IF_LOUD(DbgPrint("\nCreated the named event for the read; name=%ws, counter=%d\n", Open->ReadEventName.Buffer,NamedEventsCounter-1);)
162 //allocate the event objects
163 Open->ReadEvent=IoCreateNotificationEvent(&Open->ReadEventName,&Open->ReadEventHandle);
164 if(Open->ReadEvent==NULL){
167 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
168 IoCompleteRequest(Irp, IO_NO_INCREMENT);
169 return STATUS_INSUFFICIENT_RESOURCES;
172 KeInitializeEvent(Open->ReadEvent, NotificationEvent, FALSE);
173 KeClearEvent(Open->ReadEvent);
174 NdisInitializeEvent(&Open->WriteEvent);
175 NdisInitializeEvent(&Open->IOEvent);
176 NdisInitializeEvent(&Open->DumpEvent);
177 NdisInitializeEvent(&Open->IOEvent);
178 NdisAllocateSpinLock(&Open->machine_lock);
181 // list to hold irp's want to reset the adapter
182 InitializeListHead(&Open->ResetIrpList);
185 // Initialize the request list
186 KeInitializeSpinLock(&Open->RequestSpinLock);
187 InitializeListHead(&Open->RequestList);
189 // Initializes the extended memory of the NPF machine
190 #define NPF_TAG_MACHINE TAG('2', 'O', 'W', 'A')
191 Open->mem_ex.buffer = ExAllocatePoolWithTag(NonPagedPool, DEFAULT_MEM_EX_SIZE, NPF_TAG_MACHINE);
192 if((Open->mem_ex.buffer) == NULL)
197 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
198 IoCompleteRequest(Irp, IO_NO_INCREMENT);
199 return STATUS_INSUFFICIENT_RESOURCES;
202 Open->mem_ex.size = DEFAULT_MEM_EX_SIZE;
203 RtlZeroMemory(Open->mem_ex.buffer, DEFAULT_MEM_EX_SIZE);
206 // Initialize the open instance
212 (INT)Open->BLastByte = -1;
213 Open->Dropped = 0; //reset the dropped packets counter
214 Open->Received = 0; //reset the received packets counter
215 Open->Accepted = 0; //reset the accepted packets counter
216 Open->bpfprogram = NULL; //reset the filter
217 Open->mode = MODE_CAPT;
218 Open->Nbytes.QuadPart = 0;
219 Open->Npackets.QuadPart = 0;
221 Open->Multiple_Write_Counter = 0;
223 Open->TimeOut.QuadPart = (LONGLONG)1;
225 Open->DumpFileName.Buffer = NULL;
226 Open->DumpFileHandle = NULL;
227 Open->tme.active = TME_NONE_ACTIVE;
228 Open->DumpLimitReached = FALSE;
229 Open->MaxFrameSize = 0;
231 //allocate the spinlock for the statistic counters
232 NdisAllocateSpinLock(&Open->CountersLock);
234 //allocate the spinlock for the buffer pointers
235 NdisAllocateSpinLock(&Open->BufLock);
238 // link up the request stored in our open block
240 for (i=0;i<MAX_REQUESTS;i++) {
241 ExInterlockedInsertTailList(
243 &Open->Requests[i].ListElement,
244 &Open->RequestSpinLock);
249 IoMarkIrpPending(Irp);
252 // Try to open the MAC
254 IF_LOUD(DbgPrint("NPF: Openinig the device %ws, BindingContext=%d\n",DeviceExtension->AdapterName.Buffer, Open);)
259 &Open->AdapterHandle,
263 DeviceExtension->NdisProtocolHandle,
265 &DeviceExtension->AdapterName,
269 IF_LOUD(DbgPrint("NPF: Opened the device, Status=%x\n",Status);)
271 if (Status != NDIS_STATUS_PENDING)
273 NPF_OpenAdapterComplete(Open,Status,NDIS_STATUS_SUCCESS);
276 return(STATUS_PENDING);
279 //-------------------------------------------------------------------
281 VOID NPF_OpenAdapterComplete(
282 IN NDIS_HANDLE ProtocolBindingContext,
283 IN NDIS_STATUS Status,
284 IN NDIS_STATUS OpenErrorStatus)
289 PLIST_ENTRY RequestListEntry;
290 PINTERNAL_REQUEST MaxSizeReq;
291 NDIS_STATUS ReqStatus;
294 IF_LOUD(DbgPrint("NPF: OpenAdapterComplete\n");)
296 Open= (POPEN_INSTANCE)ProtocolBindingContext;
301 Irp=Open->OpenCloseIrp;
303 if (Status != NDIS_STATUS_SUCCESS) {
305 IF_LOUD(DbgPrint("NPF: OpenAdapterComplete-FAILURE\n");)
307 NdisFreePacketPool(Open->PacketPool);
310 Open->mem_ex.size = 0;
311 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
313 ExFreePool(Open->ReadEventName.Buffer);
315 ZwClose(Open->ReadEventHandle);
321 NdisAcquireSpinLock(&Opened_Instances_Lock);
322 n_Opened_Instances++;
323 NdisReleaseSpinLock(&Opened_Instances_Lock);
325 IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
327 // Get the absolute value of the system boot time.
328 // This is used for timestamp conversion.
329 TIME_SYNCHRONIZE(&G_Start_Time);
331 // Extract a request from the list of free ones
332 RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList, &Open->RequestSpinLock);
334 if (RequestListEntry == NULL)
337 Open->MaxFrameSize = 1514; // Assume Ethernet
339 Irp->IoStatus.Status = Status;
340 Irp->IoStatus.Information = 0;
341 IoCompleteRequest(Irp, IO_NO_INCREMENT);
346 MaxSizeReq = CONTAINING_RECORD(RequestListEntry, INTERNAL_REQUEST, ListElement);
347 MaxSizeReq->Irp = Irp;
348 MaxSizeReq->Internal = TRUE;
351 MaxSizeReq->Request.RequestType = NdisRequestQueryInformation;
352 MaxSizeReq->Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
355 MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBuffer = &Open->MaxFrameSize;
356 MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
358 // submit the request
362 &MaxSizeReq->Request);
365 if (ReqStatus != NDIS_STATUS_PENDING) {
366 NPF_RequestComplete(Open, &MaxSizeReq->Request, ReqStatus);
373 Irp->IoStatus.Status = Status;
374 Irp->IoStatus.Information = 0;
375 IoCompleteRequest(Irp, IO_NO_INCREMENT);
381 //-------------------------------------------------------------------
384 NPF_Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
389 PIO_STACK_LOCATION IrpSp;
390 LARGE_INTEGER ThreadDelay;
392 IF_LOUD(DbgPrint("NPF: CloseAdapter\n");)
394 IrpSp = IoGetCurrentIrpStackLocation(Irp);
396 Open=IrpSp->FileObject->FsContext;
398 // Reset the buffer size. This tells the dump thread to stop.
401 if( Open->Bound == FALSE){
403 NdisWaitEvent(&Open->IOEvent,10000);
405 // Free the filter if it's present
406 if(Open->bpfprogram != NULL)
407 ExFreePool(Open->bpfprogram);
409 // Free the jitted filter if it's present
410 if(Open->Filter != NULL)
411 BPF_Destroy_JIT_Filter(Open->Filter);
415 if(Open->Buffer != NULL)ExFreePool(Open->Buffer);
418 Open->mem_ex.size = 0;
419 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
421 NdisFreePacketPool(Open->PacketPool);
423 // Free the string with the name of the dump file
424 if(Open->DumpFileName.Buffer!=NULL)
425 ExFreePool(Open->DumpFileName.Buffer);
427 ExFreePool(Open->ReadEventName.Buffer);
430 Irp->IoStatus.Information = 0;
431 Irp->IoStatus.Status = STATUS_SUCCESS;
432 IoCompleteRequest(Irp, IO_NO_INCREMENT);
434 return(STATUS_SUCCESS);
437 // Unfreeze the consumer
438 if(Open->mode & MODE_DUMP)
439 NdisSetEvent(&Open->DumpEvent);
441 KeSetEvent(Open->ReadEvent,0,FALSE);
444 Open->OpenCloseIrp = Irp;
446 IoMarkIrpPending(Irp);
448 // If this instance is in dump mode, complete the dump and close the file
449 if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL){
452 ThreadDelay.QuadPart = -50000000;
453 // Wait the completion of the thread
454 wres = KeWaitForSingleObject(Open->DumpThreadObject,
460 ObDereferenceObject(Open->DumpThreadObject);
463 // Flush and close the dump file
464 NPF_CloseDumpFile(Open);
467 // Destroy the read Event
468 ZwClose(Open->ReadEventHandle);
476 if (Status != NDIS_STATUS_PENDING) {
478 NPF_CloseAdapterComplete(
482 return STATUS_SUCCESS;
486 return(STATUS_PENDING);
489 //-------------------------------------------------------------------
492 NPF_CloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status)
497 IF_LOUD(DbgPrint("NPF: CloseAdapterComplete\n");)
499 Open= (POPEN_INSTANCE)ProtocolBindingContext;
501 // free the allocated structures only if the instance is still bound to the adapter
502 if(Open->Bound == TRUE){
504 // Free the filter if it's present
505 if(Open->bpfprogram != NULL)
506 ExFreePool(Open->bpfprogram);
508 // Free the jitted filter if it's present
509 if(Open->Filter != NULL)
510 BPF_Destroy_JIT_Filter(Open->Filter);
514 if(Open->Buffer!=NULL)ExFreePool(Open->Buffer);
517 Open->mem_ex.size = 0;
518 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
520 NdisFreePacketPool(Open->PacketPool);
522 Irp=Open->OpenCloseIrp;
524 // Free the string with the name of the dump file
525 if(Open->DumpFileName.Buffer!=NULL)
526 ExFreePool(Open->DumpFileName.Buffer);
528 ExFreePool(Open->ReadEventName.Buffer);
531 // Complete the request only if the instance is still bound to the adapter
532 Irp->IoStatus.Status = STATUS_SUCCESS;
533 Irp->IoStatus.Information = 0;
534 IoCompleteRequest(Irp, IO_NO_INCREMENT);
537 NdisSetEvent(&Open->IOEvent);
539 // Decrease the counter of open instances
540 NdisAcquireSpinLock(&Opened_Instances_Lock);
541 n_Opened_Instances--;
542 NdisReleaseSpinLock(&Opened_Instances_Lock);
544 IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
546 if(n_Opened_Instances == 0){
547 // Force a synchronization at the next NPF_Open().
548 // This hopefully avoids the synchronization issues caused by hibernation or standby.
549 TIME_DESYNCHRONIZE(&G_Start_Time);
555 //-------------------------------------------------------------------
559 NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent)
561 IF_LOUD(DbgPrint("NPF: PowerChange\n");)
563 TIME_DESYNCHRONIZE(&G_Start_Time);
565 TIME_SYNCHRONIZE(&G_Start_Time);
567 return STATUS_SUCCESS;
571 //-------------------------------------------------------------------
575 OUT PNDIS_STATUS Status,
576 IN NDIS_HANDLE BindContext,
577 IN PNDIS_STRING DeviceName,
578 IN PVOID SystemSpecific1,
579 IN PVOID SystemSpecific2
582 IF_LOUD(DbgPrint("NPF: NPF_BindAdapter\n");)
585 //-------------------------------------------------------------------
589 OUT PNDIS_STATUS Status,
590 IN NDIS_HANDLE ProtocolBindingContext,
591 IN NDIS_HANDLE UnbindContext
594 POPEN_INSTANCE Open =(POPEN_INSTANCE)ProtocolBindingContext;
597 IF_LOUD(DbgPrint("NPF: NPF_UnbindAdapter\n");)
599 // Reset the buffer size. This tells the dump thread to stop.
602 NdisResetEvent(&Open->IOEvent);
604 // This open instance is no more bound to the adapter, set Bound to False
605 InterlockedExchange( (PLONG) &Open->Bound, FALSE );
607 // Awake a possible pending read on this instance
608 if(Open->mode & MODE_DUMP)
609 NdisSetEvent(&Open->DumpEvent);
611 KeSetEvent(Open->ReadEvent,0,FALSE);
613 // If this instance is in dump mode, complete the dump and close the file
614 if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL)
615 NPF_CloseDumpFile(Open);
617 // Destroy the read Event
618 ZwClose(Open->ReadEventHandle);
626 if (lStatus != NDIS_STATUS_PENDING) {
628 NPF_CloseAdapterComplete(
633 *Status = NDIS_STATUS_SUCCESS;
638 *Status = NDIS_STATUS_SUCCESS;
642 //-------------------------------------------------------------------
645 NPF_ResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status)
651 PLIST_ENTRY ResetListEntry;
653 IF_LOUD(DbgPrint("NPF: PacketResetComplte\n");)
655 Open= (POPEN_INSTANCE)ProtocolBindingContext;
659 // remove the reset IRP from the list
661 ResetListEntry=ExInterlockedRemoveHeadList(
663 &Open->RequestSpinLock
667 if (ResetListEntry == NULL) {
673 Irp=CONTAINING_RECORD(ResetListEntry,IRP,Tail.Overlay.ListEntry);
675 Irp->IoStatus.Status = STATUS_SUCCESS;
676 IoCompleteRequest(Irp, IO_NO_INCREMENT);
678 IF_LOUD(DbgPrint("NPF: PacketResetComplte exit\n");)