Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3591 lines
72 KiB

/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
mac.c
Abstract:
NDIS wrapper functions for full mac drivers
Author:
Adam Barr (adamba) 11-Jul-1990
Environment:
Kernel mode, FSD
Revision History:
26-Feb-1991 JohnsonA Added Debugging Code
10-Jul-1991 JohnsonA Implement revised Ndis Specs
01-Jun-1995 JameelH Re-organized
--*/
#include <precomp.h>
#pragma hdrstop
#include <stdarg.h>
//
// Define the module number for debug code.
//
#define MODULE_NUMBER MODULE_MAC
VOID
ndisLastCountRemovedFunction(
IN struct _KDPC * Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
Queued from ndisIsr if the refcount is zero and we need to
set the event, since we can't do that from an ISR.
Arguments:
Dpc - Will be NdisInterrupt->InterruptDpc.
DeferredContext - Points to the event to set.
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
SET_EVENT((PKEVENT)DeferredContext);
}
VOID
ndisUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This routine is called when a driver is supposed to unload. Ndis
converts this into a set of calls to MacRemoveAdapter() for each
adapter that the Mac has open. When the last adapter deregisters
itself it will call MacUnload().
Arguments:
DriverObject - the driver object for the mac that is to unload.
Return Value:
None.
--*/
{
PNDIS_MAC_BLOCK MacP;
PNDIS_ADAPTER_BLOCK Adapter, NextAdapter;
KIRQL OldIrql;
ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
//
// Search for the MacP
//
MacP = ndisMacDriverList;
while (MacP != (PNDIS_MAC_BLOCK)NULL)
{
if (MacP->NdisMacInfo->NdisWrapperDriver == DriverObject)
{
break;
}
MacP = MacP->NextMac;
}
RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
if (MacP == (PNDIS_MAC_BLOCK)NULL)
{
//
// It is already gone. Just return.
//
return;
}
MacP->Unloading = TRUE;
//
// Now call MACRemoveAdapter() for each Adapter.
//
Adapter = MacP->AdapterQueue;
while (Adapter != (PNDIS_ADAPTER_BLOCK)NULL)
{
NextAdapter = Adapter->NextAdapter; // since queue may change
(MacP->MacCharacteristics.RemoveAdapterHandler)(
Adapter->MacAdapterContext);
//
// If a shutdown handler was registered then deregister it.
//
NdisDeregisterAdapterShutdownHandler(Adapter);
Adapter = NextAdapter;
}
//
// Wait for all adapters to be gonzo.
//
WAIT_FOR_OBJECT(&MacP->AdaptersRemovedEvent, NULL);
RESET_EVENT(&MacP->AdaptersRemovedEvent);
//
// Now call the MACUnload routine
//
(MacP->MacCharacteristics.UnloadMacHandler)(MacP->MacMacContext);
//
// Now remove the last reference (this will remove it from the list)
//
ASSERT(MacP->Ref.ReferenceCount == 1);
ndisDereferenceMac(MacP);
}
NTSTATUS
ndisShutdown(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
shutdown routine, if one is registered.
Arguments:
DeviceObject - The adapter's device object.
Irp - The IRP.
Return Value:
Always STATUS_SUCCESS.
--*/
{
PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
PNDIS_ADAPTER_BLOCK Miniport = (PNDIS_ADAPTER_BLOCK)(WrapperContext + 1);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisShutdown\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Null Irp\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Irp not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
if (WrapperContext->ShutdownHandler != NULL)
{
//
// Call the shutdown routine
//
WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisShutdown\n"));
return STATUS_SUCCESS;
}
IO_ALLOCATION_ACTION
ndisDmaExecutionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID MapRegisterBase,
IN PVOID Context
)
/*++
Routine Description:
This routine is an execution routine for AllocateAdapterChannel,
if is called when an adapter channel allocated by
NdisAllocateDmaChannel is available.
Arguments:
DeviceObject - The device object of the adapter.
Irp - ??.
MapRegisterBase - The address of the first translation table
assigned to us.
Context - A pointer to the NDIS_DMA_BLOCK in question.
Return Value:
None.
--*/
{
PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)Context;
UNREFERENCED_PARAMETER (Irp);
UNREFERENCED_PARAMETER (DeviceObject);
//
// Save the map register base.
//
DmaBlock->MapRegisterBase = MapRegisterBase;
//
// This will free the thread that is waiting for this callback.
//
SET_EVENT(&DmaBlock->AllocationEvent);
return KeepObject;
}
NDIS_STATUS
ndisMacReceiveHandler(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookaheadBuffer,
IN UINT LookaheadBufferSize,
IN UINT PacketSize
)
{
PNDIS_OPEN_BLOCK Open;
NDIS_STATUS Status;
KIRQL oldIrql;
RAISE_IRQL_TO_DISPATCH(&oldIrql);
//
// Find protocol binding context and get associated open for it.
//
Open = ndisGetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
ASSERT(Open != NULL);
Status = (Open->PostNt31ReceiveHandler)(ProtocolBindingContext,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookaheadBuffer,
LookaheadBufferSize,
PacketSize);
LOWER_IRQL(oldIrql);
return Status;
}
VOID
ndisMacReceiveCompleteHandler(
IN NDIS_HANDLE ProtocolBindingContext
)
{
PNDIS_OPEN_BLOCK Open;
KIRQL oldIrql;
RAISE_IRQL_TO_DISPATCH(&oldIrql);
//
// Find protocol binding context and get associated open for it.
//
Open = ndisGetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
ASSERT(Open != NULL);
(Open->PostNt31ReceiveCompleteHandler)(ProtocolBindingContext);
LOWER_IRQL(oldIrql);
}
PNDIS_OPEN_BLOCK
ndisGetOpenBlockFromProtocolBindingContext(
IN NDIS_HANDLE ProtocolBindingContext
)
{
PNDIS_OPEN_BLOCK *ppOpen;
ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
for (ppOpen = &ndisGlobalOpenList;
*ppOpen != NULL;
ppOpen = &(*ppOpen)->NextGlobalOpen)
{
if ((*ppOpen)->ProtocolBindingContext == ProtocolBindingContext)
{
break;
}
}
RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
return *ppOpen;
}
IO_ALLOCATION_ACTION
ndisAllocationExecutionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID MapRegisterBase,
IN PVOID Context
)
/*++
Routine Description:
This routine is the execution routine for AllocateAdapterChannel,
if is called when the map registers have been assigned.
Arguments:
DeviceObject - The device object of the adapter.
Irp - ??.
MapRegisterBase - The address of the first translation table
assigned to us.
Context - A pointer to the Adapter in question.
Return Value:
None.
--*/
{
PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)Context;
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
Irp; DeviceObject;
//
// Save this translation entry in the correct spot.
//
if (AdaptP->DeviceObject == NULL)
{
Miniport->MapRegisters[Miniport->CurrentMapRegister].MapRegister = MapRegisterBase;
}
else
{
AdaptP->MapRegisters[AdaptP->CurrentMapRegister].MapRegister = MapRegisterBase;
}
//
// This will free the thread that is waiting for this callback.
//
SET_EVENT(((AdaptP->DeviceObject == NULL) ?
&Miniport->AllocationEvent :
&AdaptP->AllocationEvent));
return DeallocateObjectKeepRegisters;
}
VOID
NdisReleaseAdapterResources(
IN NDIS_HANDLE NdisAdapterHandle
)
/*++
Routine Description:
Informs the wrapper that the resources (such as interrupt,
I/O ports, etc.) have been shut down in some way such that
they will not interfere with other devices in the system.
Arguments:
NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
Return Value:
None.
--*/
{
PCM_RESOURCE_LIST Resources;
BOOLEAN Conflict;
NTSTATUS NtStatus;
PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
Resources = AdptrP->Resources;
//
// Clear count
//
Resources->List[0].PartialResourceList.Count = 0;
//
// Make the call
//
NtStatus = IoReportResourceUsage(NULL,
AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver,
NULL,
0,
AdptrP->DeviceObject,
Resources,
sizeof(CM_RESOURCE_LIST)+sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
TRUE,
&Conflict);
}
VOID
NdisWriteErrorLogEntry(
IN NDIS_HANDLE NdisAdapterHandle,
IN NDIS_ERROR_CODE ErrorCode,
IN ULONG NumberOfErrorValues,
...
)
/*++
Routine Description:
This function allocates an I/O error log record, fills it in and writes it
to the I/O error log.
Arguments:
NdisAdapterHandle - points to the adapter block.
ErrorCode - Ndis code mapped to a string.
NumberOfErrorValues - number of ULONGS to store for the error.
Return Value:
None.
--*/
{
va_list ArgumentPointer;
PIO_ERROR_LOG_PACKET errorLogEntry;
PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
PDEVICE_OBJECT DeviceObject;
ULONG i;
ULONG StringSize;
PWCH baseFileName;
if (AdapterBlock == NULL)
{
return;
}
DeviceObject = AdapterBlock->DeviceObject;
if (DeviceObject != NULL)
{
baseFileName = AdapterBlock->AdapterName.Buffer;
}
else
{
baseFileName = Miniport->MiniportName.Buffer;
}
//
// Parse out the path name, leaving only the device name.
//
for (i = 0;
i < ((DeviceObject != NULL) ?
AdapterBlock->AdapterName.Length :
Miniport->MiniportName.Length) / sizeof(WCHAR); i++)
{
//
// If s points to a directory separator, set baseFileName to
// the character after the separator.
//
if (((DeviceObject != NULL) ?
AdapterBlock->AdapterName.Buffer[i] :
Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR)
{
baseFileName = ((DeviceObject != NULL) ?
&(AdapterBlock->AdapterName.Buffer[++i]) :
&(Miniport->MiniportName.Buffer[++i]));
}
}
StringSize = ((DeviceObject != NULL) ?
AdapterBlock->AdapterName.MaximumLength :
Miniport->MiniportName.MaximumLength) -
(((ULONG)baseFileName) -
((DeviceObject != NULL) ?
((ULONG)AdapterBlock->AdapterName.Buffer) :
((ULONG)Miniport->MiniportName.Buffer)));
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
((DeviceObject != NULL) ? AdapterBlock->DeviceObject : Miniport->DeviceObject),
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
NumberOfErrorValues * sizeof(ULONG) + StringSize));
if (errorLogEntry != NULL)
{
errorLogEntry->ErrorCode = ErrorCode;
//
// store the time
//
errorLogEntry->MajorFunctionCode = 0;
errorLogEntry->RetryCount = 0;
errorLogEntry->UniqueErrorValue = 0;
errorLogEntry->FinalStatus = 0;
errorLogEntry->SequenceNumber = 0;
errorLogEntry->IoControlCode = 0;
//
// Store Data
//
errorLogEntry->DumpDataSize = (USHORT)(NumberOfErrorValues * sizeof(ULONG));
va_start(ArgumentPointer, NumberOfErrorValues);
for (i = 0; i < NumberOfErrorValues; i++)
{
errorLogEntry->DumpData[i] = va_arg(ArgumentPointer, ULONG);
}
va_end(ArgumentPointer);
//
// Set string information
//
if (StringSize != 0)
{
errorLogEntry->NumberOfStrings = 1;
errorLogEntry->StringOffset =
sizeof(IO_ERROR_LOG_PACKET) +
NumberOfErrorValues * sizeof(ULONG);
CopyMemory(((PUCHAR)errorLogEntry) + (sizeof(IO_ERROR_LOG_PACKET) +
NumberOfErrorValues * sizeof(ULONG)),
baseFileName,
StringSize);
}
else
{
errorLogEntry->NumberOfStrings = 0;
}
//
// write it out
//
IoWriteErrorLogEntry(errorLogEntry);
}
}
VOID
NdisCompleteOpenAdapter(
IN NDIS_HANDLE NdisBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus
)
{
PNDIS_OPEN_BLOCK OpenP = (PNDIS_OPEN_BLOCK)NdisBindingContext;
PQUEUED_OPEN_CLOSE pQoC = NULL;
QUEUED_OPEN_CLOSE QoC;
KIRQL OldIrql;
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
("==>NdisCompleteOpenAdapter\n"));
IF_DBG(DBG_COMP_OPEN, DBG_LEVEL_ERR)
{
if (!DbgIsNonPaged(NdisBindingContext))
{
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
("NdisCompleteOpenAdapter: Handle not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(NdisBindingContext))
{
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
("NdisCompleteOpenAdapter: Binding Context not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
}
}
if (Status == NDIS_STATUS_SUCCESS)
{
if (!NdisFinishOpen(OpenP))
{
Status = NDIS_STATUS_CLOSING;
}
}
if (KeGetCurrentIrql() == DISPATCH_LEVEL)
{
pQoC = (PQUEUED_OPEN_CLOSE)ALLOC_FROM_POOL(sizeof(QUEUED_OPEN_CLOSE), NDIS_TAG_DEFAULT);
if (pQoC != NULL)
{
pQoC->FreeIt = TRUE;
}
}
if (pQoC == NULL)
{
pQoC = &QoC;
pQoC->FreeIt = FALSE;
}
pQoC->OpenP = OpenP;
pQoC->Status = Status;
pQoC->OpenErrorStatus = OpenErrorStatus;
if (pQoC->FreeIt)
{
INITIALIZE_WORK_ITEM(&pQoC->WorkItem,
ndisQueuedCompleteOpenAdapter,
pQoC);
QUEUE_WORK_ITEM(&pQoC->WorkItem, HyperCriticalWorkQueue);
}
else
{
ndisQueuedCompleteOpenAdapter(pQoC);
}
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
("<==NdisCompleteOpenAdapter\n"));
}
VOID
ndisQueuedCompleteOpenAdapter(
IN PQUEUED_OPEN_CLOSE pQoC
)
{
PNDIS_OPEN_BLOCK *ppOpen;
KIRQL OldIrql;
(pQoC->OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler)(
pQoC->OpenP->ProtocolBindingContext,
pQoC->Status,
pQoC->OpenErrorStatus);
if (pQoC->Status != NDIS_STATUS_SUCCESS)
{
//
// Something went wrong, clean up and exit.
//
ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
for (ppOpen = &ndisGlobalOpenList;
*ppOpen != NULL;
ppOpen = &(*ppOpen)->NextGlobalOpen)
{
if (*ppOpen == pQoC->OpenP)
{
*ppOpen = pQoC->OpenP->NextGlobalOpen;
break;
}
}
RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
ObDereferenceObject(pQoC->OpenP->FileObject);
ndisDereferenceAdapter(pQoC->OpenP->AdapterHandle);
ndisDereferenceProtocol(pQoC->OpenP->ProtocolHandle);
FREE_POOL(pQoC->OpenP);
}
if (pQoC->FreeIt)
{
FREE_POOL(pQoC);
}
}
VOID
NdisCompleteCloseAdapter(
IN NDIS_HANDLE NdisBindingContext,
IN NDIS_STATUS Status
)
{
PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK) NdisBindingContext;
PQUEUED_OPEN_CLOSE pQoC = NULL;
QUEUED_OPEN_CLOSE QoC;
KIRQL OldIrql;
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
("==>NdisCompleteCloseAdapter\n"));
IF_DBG(DBG_COMP_OPEN, DBG_LEVEL_ERR)
{
if (!DbgIsNonPaged(NdisBindingContext))
{
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
("NdisCompleteCloseAdapter: Handle not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(NdisBindingContext))
{
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_ERR,
("NdisCompleteCloseAdapter: Binding Context not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_OPEN, DBG_LEVEL_ERR);
}
}
if (KeGetCurrentIrql() == DISPATCH_LEVEL)
{
pQoC = (PQUEUED_OPEN_CLOSE)ALLOC_FROM_POOL(sizeof(QUEUED_OPEN_CLOSE), NDIS_TAG_DEFAULT);
if (pQoC != NULL)
{
pQoC->FreeIt = TRUE;
}
}
if (pQoC == NULL)
{
pQoC = &QoC;
pQoC->FreeIt = FALSE;
}
pQoC->OpenP = Open;
pQoC->Status = Status;
if (pQoC->FreeIt)
{
INITIALIZE_WORK_ITEM(&pQoC->WorkItem,
ndisQueuedCompleteCloseAdapter,
pQoC);
QUEUE_WORK_ITEM(&pQoC->WorkItem, CriticalWorkQueue);
}
else
{
ndisQueuedCompleteCloseAdapter(pQoC);
}
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
("<==NdisCompleteCloseAdapter\n"));
}
VOID
ndisQueuedCompleteCloseAdapter(
IN PQUEUED_OPEN_CLOSE pQoC
)
{
PNDIS_OPEN_BLOCK OpenP, *ppOpen;
KIRQL OldIrql;
OpenP = pQoC->OpenP;
(OpenP->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
OpenP->ProtocolBindingContext,
pQoC->Status);
ndisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle);
ndisDeQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle);
ndisDereferenceProtocol(OpenP->ProtocolHandle);
ndisDereferenceAdapter(OpenP->AdapterHandle);
NdisFreeSpinLock(&OpenP->SpinLock);
//
// This sends an IRP_MJ_CLOSE IRP.
//
ObDereferenceObject((OpenP->FileObject));
//
// Remove from global list
//
ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
for (ppOpen = &ndisGlobalOpenList;
*ppOpen != NULL;
ppOpen = &(*ppOpen)->NextGlobalOpen)
{
if (*ppOpen == pQoC->OpenP)
{
*ppOpen = pQoC->OpenP->NextGlobalOpen;
break;
}
}
RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
FREE_POOL(pQoC->OpenP);
if (pQoC->FreeIt)
{
FREE_POOL(pQoC);
}
}
#undef NdisSend
VOID
NdisSend(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE NdisBindingHandle,
IN PNDIS_PACKET Packet
)
{
*Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->SendHandler)(
((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
Packet);
}
#undef NdisSendPackets
VOID
NdisSendPackets(
IN NDIS_HANDLE NdisBindingHandle,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets
)
{
(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->SendPacketsHandler)(
((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
PacketArray,
NumberOfPackets);
}
#undef NdisTransferData
VOID
NdisTransferData(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE NdisBindingHandle,
IN NDIS_HANDLE MacReceiveContext,
IN UINT ByteOffset,
IN UINT BytesToTransfer,
OUT PNDIS_PACKET Packet,
OUT PUINT BytesTransferred
)
{
*Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->TransferDataHandler)(
((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
MacReceiveContext,
ByteOffset,
BytesToTransfer,
Packet,
BytesTransferred);
}
#undef NdisReset
VOID
NdisReset(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE NdisBindingHandle
)
{
*Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacHandle->MacCharacteristics.ResetHandler)(
((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
}
#undef NdisRequest
VOID
NdisRequest(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE NdisBindingHandle,
IN PNDIS_REQUEST NdisRequest
)
{
*Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacHandle->MacCharacteristics.RequestHandler)(
((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle,
NdisRequest);
}
BOOLEAN
NdisReferenceRef(
IN PREFERENCE RefP
)
/*++
Routine Description:
Adds a reference to an object.
Arguments:
RefP - A pointer to the REFERENCE portion of the object.
Return Value:
TRUE if the reference was added.
FALSE if the object was closing.
--*/
{
BOOLEAN rc = TRUE;
KIRQL OldIrql;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>NdisReferenceRef\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(RefP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisReferenceRef: NULL Reference address\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(RefP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisReferenceRef: Reference not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
if (RefP->Closing)
{
rc = FALSE;
}
else
{
++(RefP->ReferenceCount);
}
NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisReferenceRef\n"));
return(rc);
}
BOOLEAN
NdisDereferenceRef(
IN PREFERENCE RefP
)
/*++
Routine Description:
Removes a reference to an object.
Arguments:
RefP - A pointer to the REFERENCE portion of the object.
Return Value:
TRUE if the reference count is now 0.
FALSE otherwise.
--*/
{
BOOLEAN rc = FALSE;
KIRQL OldIrql;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>NdisDereferenceRef\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(RefP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisDereferenceRef: NULL Reference address\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(RefP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisDereferenceRef: Reference not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
--(RefP->ReferenceCount);
if (RefP->ReferenceCount == 0)
{
rc = TRUE;
}
NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisDereferenceRef\n"));
return rc;
}
VOID
NdisInitializeRef(
IN PREFERENCE RefP
)
/*++
Routine Description:
Initialize a reference count structure.
Arguments:
RefP - The structure to be initialized.
Return Value:
None.
--*/
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>NdisInitializeRef\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(RefP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisInitializeRef: NULL Reference address\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(RefP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisInitializeRef: Reference not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
RefP->Closing = FALSE;
RefP->ReferenceCount = 1;
NdisAllocateSpinLock(&RefP->SpinLock);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisInitializeRef\n"));
}
BOOLEAN
NdisCloseRef(
IN PREFERENCE RefP
)
/*++
Routine Description:
Closes a reference count structure.
Arguments:
RefP - The structure to be closed.
Return Value:
FALSE if it was already closing.
TRUE otherwise.
--*/
{
KIRQL OldIrql;
BOOLEAN rc = TRUE;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>NdisCloseRef\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(RefP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisCloseRef: NULL Reference address\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(RefP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisCloseRef: Reference not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
NDIS_ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
if (RefP->Closing)
{
rc = FALSE;
}
else RefP->Closing = TRUE;
NDIS_RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisCloseRef\n"));
return rc;
}
BOOLEAN
NdisFinishOpen(
IN PNDIS_OPEN_BLOCK OpenP
)
/*++
Routine Description:
Performs the final functions of NdisOpenAdapter. Called when
MacOpenAdapter is done.
Arguments:
OpenP - The open block to finish up.
Return Value:
FALSE if the adapter or the protocol is closing.
TRUE otherwise.
--*/
{
//
// Add us to the adapter's queue of opens.
//
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>NdisFinishOpen\n"));
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
(" Protocol %wZ is being bound to Adapter %wZ\n",
&(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
&OpenP->AdapterHandle->AdapterName));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisFinishOpen: Null Open Block\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisFinishOpen: Open Block not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
if (!ndisQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle))
{
//
// The adapter is closing.
//
// Call MacCloseAdapter(), don't worry about it completing.
//
(OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
OpenP->MacBindingHandle);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisFinishOpen\n"));
return FALSE;
}
//
// Add us to the protocol's queue of opens.
//
if (!ndisQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle))
{
//
// The protocol is closing.
//
// Call MacCloseAdapter(), don't worry about it completing.
//
(OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
OpenP->MacBindingHandle);
//
// Undo the queueing we just did.
//
ndisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisFinishOpen\n"));
return FALSE;
}
//
// Both queueings succeeded.
//
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisFinishOpen\n"));
return TRUE;
}
NTSTATUS
ndisCreateIrpHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The handle for IRP_MJ_CREATE IRPs.
Arguments:
DeviceObject - The adapter's device object.
Irp - The IRP.
Return Value:
STATUS_SUCCESS if it should be.
--*/
{
PIO_STACK_LOCATION IrpSp;
PFILE_FULL_EA_INFORMATION IrpEaInfo;
PNDIS_USER_OPEN_CONTEXT OpenContext;
NTSTATUS Status = STATUS_SUCCESS;
PNDIS_ADAPTER_BLOCK AdapterBlock;
PNDIS_MINIPORT_BLOCK Miniport;
BOOLEAN IsAMiniport;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisCreateIrpHandler\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Null Irp\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Irp not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
AdapterBlock = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
Miniport = (PNDIS_MINIPORT_BLOCK)AdapterBlock;
IsAMiniport = (AdapterBlock->DeviceObject == NULL);
IrpSp = IoGetCurrentIrpStackLocation (Irp);
IrpEaInfo = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
if (IrpEaInfo == NULL)
{
//
// This is a user-mode open, do whatever.
//
OpenContext = (PNDIS_USER_OPEN_CONTEXT)ALLOC_FROM_POOL(sizeof(NDIS_USER_OPEN_CONTEXT),
NDIS_TAG_DEFAULT);
if (OpenContext == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
OpenContext->DeviceObject = DeviceObject;
OpenContext->AdapterBlock = AdapterBlock;
OpenContext->OidCount = 0;
OpenContext->FullOidCount = 0;
OpenContext->OidArray = NULL;
OpenContext->FullOidArray = NULL;
IrpSp->FileObject->FsContext = OpenContext;
IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_QUERY_STATISTICS;
if (IsAMiniport && !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
Status = ndisMQueryOidList(OpenContext, Irp);
}
else
{
//
// Handle full-macs and 4.1 miniports here
//
Status = ndisQueryOidList(OpenContext, Irp);
}
if (Status != STATUS_SUCCESS)
{
FREE_POOL(OpenContext);
}
else
{
PnPReferencePackage();
}
}
}
else
{
//
// This is an internal open, verify the EA.
//
if ((IrpEaInfo->EaNameLength != sizeof(ndisInternalEaName)) ||
(!RtlEqualMemory(IrpEaInfo->EaName, ndisInternalEaName, sizeof(ndisInternalEaName))) ||
(IrpEaInfo->EaValueLength != sizeof(ndisInternalEaValue)) ||
(!RtlEqualMemory(&IrpEaInfo->EaName[IrpEaInfo->EaNameLength+1],
ndisInternalEaValue, sizeof(ndisInternalEaValue))))
{
//
// Something is wrong, reject it.
//
Status = STATUS_UNSUCCESSFUL;
}
else
{
//
// It checks out, just return success and everything
// else is done directly using the device object.
//
IrpSp->FileObject->FsContext = NULL;
IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_INTERNAL;
}
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisCreateIrplHandler\n"));
return Status;
}
NTSTATUS
ndisQueryOidList(
IN PNDIS_USER_OPEN_CONTEXT OpenContext,
IN PIRP Irp
)
/*++
Routine Description:
This routine will take care of querying the complete OID
list for the MAC and filling in OpenContext->OidArray
with the ones that are statistics. It blocks when the
MAC pends and so is synchronous.
NOTE: We also handle co-ndis miniports here.
Arguments:
OpenContext - The open context.
Irp = The IRP that the open was done on (used at completion
to distinguish the request).
Return Value:
STATUS_SUCCESS if it should be.
--*/
{
PNDIS_MINIPORT_BLOCK Miniport;
PNDIS_COREQ_RESERVED ReqRsvd;
NDIS_QUERY_OPEN_REQUEST OpenRequest;
NDIS_STATUS NdisStatus;
PNDIS_OID TmpBuffer;
ULONG TmpBufferLength;
//
// First query the OID list with no buffer, to find out
// how big it should be.
//
INITIALIZE_EVENT(&OpenRequest.Event);
OpenRequest.Irp = Irp;
OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0;
OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
Miniport = (PNDIS_MINIPORT_BLOCK)OpenContext->AdapterBlock;
if (OpenContext->AdapterBlock->DeviceObject != NULL)
{
NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
OpenContext->AdapterBlock->MacAdapterContext,
&OpenRequest.Request);
}
else
{
OpenRequest.Request.RequestType = NdisRequestQueryInformation;
ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&OpenRequest.Request);
ReqRsvd->Open = NULL;
ReqRsvd->RequestCompleteHandler = NULL;
ReqRsvd->VcContext = NULL;
ReqRsvd->Flags = COREQ_QUERY_OIDS;
ReqRsvd->RealRequest = NULL;
//
// Call the miniport's CoRequest Handler
//
NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
Miniport->MiniportAdapterContext,
NULL,
&OpenRequest.Request);
}
if (NdisStatus == NDIS_STATUS_PENDING)
{
//
// The completion routine will set NdisRequestStatus.
//
WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
NdisStatus = OpenRequest.NdisStatus;
}
else if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
(NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT))
{
return NdisStatus;
}
//
// Now we know how much is needed, allocate temp storage...
//
TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
TmpBuffer = ALLOC_FROM_POOL(TmpBufferLength, NDIS_TAG_DEFAULT);
if (TmpBuffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// ...and query the real list.
//
RESET_EVENT(&OpenRequest.Event);
OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer;
OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength;
OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
if (OpenContext->AdapterBlock->DeviceObject != NULL)
{
NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
OpenContext->AdapterBlock->MacAdapterContext,
&OpenRequest.Request);
}
else
{
//
// Call the miniport's CoRequest Handler
//
NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
Miniport->MiniportAdapterContext,
NULL,
&OpenRequest.Request);
}
if (NdisStatus == NDIS_STATUS_PENDING)
{
//
// The completion routine will set NdisRequestStatus.
//
WAIT_FOR_OBJECT(&OpenRequest.Event, NULL);
NdisStatus = OpenRequest.NdisStatus;
}
ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
NdisStatus = ndisSplitStatisticsOids(OpenContext,
TmpBuffer,
TmpBufferLength/sizeof(NDIS_OID));
FREE_POOL(TmpBuffer);
return NdisStatus;
}
NDIS_STATUS
ndisSplitStatisticsOids(
IN PNDIS_USER_OPEN_CONTEXT OpenContext,
IN PNDIS_OID OidList,
IN ULONG NumOids
)
{
ULONG i, j;
//
// Go through the buffer, counting the statistics OIDs.
//
OpenContext->FullOidCount = NumOids;
for (i = 0; i < NumOids; i++)
{
if ((OidList[i] & 0x00ff0000) == 0x00020000)
{
++OpenContext->OidCount;
}
}
//
// Now allocate storage for the stat and non-stat OID arrays.
//
OpenContext->OidArray = ALLOC_FROM_POOL(OpenContext->OidCount*sizeof(NDIS_OID),
NDIS_TAG_DEFAULT);
if (OpenContext->OidArray == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
OpenContext->FullOidArray = ALLOC_FROM_POOL(OpenContext->FullOidCount*sizeof(NDIS_OID),
NDIS_TAG_DEFAULT);
if (OpenContext->FullOidArray == NULL)
{
FREE_POOL(OpenContext->OidArray);
OpenContext->OidArray = NULL;
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Now go through the buffer, copying the statistics and non-stat OIDs separately.
//
for (i = j = 0; i< NumOids; i++)
{
if ((OidList[i] & 0x00ff0000) == 0x00020000)
{
OpenContext->OidArray[j++] = OidList[i];
}
OpenContext->FullOidArray[i] = OidList[i];
}
ASSERT (j == OpenContext->OidCount);
return NDIS_STATUS_SUCCESS;
}
#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
VOID
ndisCancelLogIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION IrpSp;
PNDIS_USER_OPEN_CONTEXT OpenContext;
PNDIS_MINIPORT_BLOCK Miniport;
PNDIS_LOG Log;
KIRQL OldIrql;
IrpSp = IoGetCurrentIrpStackLocation (Irp);
OpenContext = IrpSp->FileObject->FsContext;
Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
ASSERT (Miniport->Log != NULL);
ASSERT (Miniport->Log->Irp == Irp);
Miniport->Log->Irp = NULL;
Irp->IoStatus.Status = STATUS_REQUEST_ABORTED;
Irp->IoStatus.Information = 0;
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
}
NTSTATUS
ndisDeviceControlIrpHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The handle for IRP_MJ_DEVICE_CONTROL IRPs.
Arguments:
DeviceObject - The adapter's device object.
Irp - The IRP.
Return Value:
STATUS_SUCCESS if it should be.
--*/
{
PIO_STACK_LOCATION IrpSp;
PNDIS_USER_OPEN_CONTEXT OpenContext;
PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
PNDIS_QUERY_ALL_REQUEST AllRequest;
NDIS_STATUS NdisStatus;
UINT CurrentOid;
ULONG BytesWritten, BytesWrittenThisOid;
PUCHAR Buffer;
ULONG BufferLength;
NTSTATUS Status = STATUS_SUCCESS;
PNDIS_MINIPORT_BLOCK Miniport;
BOOLEAN LocalLock;
KIRQL OldIrql;
PSINGLE_LIST_ENTRY Link;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisDeviceControlIrpHandler\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Null Irp\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Irp not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
IoMarkIrpPending (Irp);
Irp->IoStatus.Status = STATUS_PENDING;
Irp->IoStatus.Information = 0;
IrpSp = IoGetCurrentIrpStackLocation (Irp);
if (IrpSp->FileObject->FsContext2 != (PVOID)NDIS_OPEN_QUERY_STATISTICS)
{
return STATUS_UNSUCCESSFUL;
}
PnPReferencePackage();
OpenContext = IrpSp->FileObject->FsContext;
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_NDIS_GET_LOG_DATA:
//
// First verify that we have a miniport. This IOCTL is only
// valid for a miniport
//
if (OpenContext->AdapterBlock->DeviceObject != NULL)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
{
PNDIS_LOG Log;
UINT AmtToCopy;
if ((Log = Miniport->Log) != NULL)
{
ACQUIRE_SPIN_LOCK_DPC(&Log->LogLock);
if (Log->CurrentSize != 0)
{
//
// If the InPtr is lagging the OutPtr. then we can simply
// copy the data over in one shot.
//
AmtToCopy = MDL_SIZE(Irp->MdlAddress);
if (AmtToCopy > Log->CurrentSize)
AmtToCopy = Log->CurrentSize;
if ((Log->TotalSize - Log->OutPtr) >= AmtToCopy)
{
CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
Log->LogBuf+Log->OutPtr,
AmtToCopy);
}
else
{
CopyMemory(MDL_ADDRESS(Irp->MdlAddress),
Log->LogBuf+Log->OutPtr,
Log->TotalSize-Log->OutPtr);
CopyMemory((PUCHAR)MDL_ADDRESS(Irp->MdlAddress)+Log->TotalSize-Log->OutPtr,
Log->LogBuf,
AmtToCopy - (Log->TotalSize-Log->OutPtr));
}
Log->CurrentSize -= AmtToCopy;
Log->OutPtr += AmtToCopy;
if (Log->OutPtr >= Log->TotalSize)
Log->OutPtr -= Log->TotalSize;
Irp->IoStatus.Information = AmtToCopy;
Status = STATUS_SUCCESS;
}
else if (Log->Irp != NULL)
{
Status = STATUS_UNSUCCESSFUL;
}
else
{
KIRQL OldIrql;
IoAcquireCancelSpinLock(&OldIrql);
IoSetCancelRoutine(Irp, ndisCancelLogIrp);
IoReleaseCancelSpinLock(OldIrql);
Log->Irp = Irp;
Status = STATUS_PENDING;
}
RELEASE_SPIN_LOCK_DPC(&Log->LogLock);
}
}
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
break;
case IOCTL_NDIS_QUERY_GLOBAL_STATS:
if (!ndisValidOid(OpenContext,
*((PULONG)(Irp->AssociatedIrp.SystemBuffer))))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Allocate a request.
//
GlobalRequest = (PNDIS_QUERY_GLOBAL_REQUEST)ALLOC_FROM_POOL(sizeof(NDIS_QUERY_GLOBAL_REQUEST),
NDIS_TAG_DEFAULT);
if (GlobalRequest == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
GlobalRequest->Irp = Irp;
if (OpenContext->AdapterBlock->DeviceObject == NULL)
{
Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
//
// Do this for CL miniports only
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
LOCK_MINIPORT(Miniport, LocalLock);
}
}
else
{
Miniport = NULL;
}
//
// Fill in the NDIS request.
//
GlobalRequest->Request.RequestType = NdisRequestQueryStatistics;
GlobalRequest->Request.DATA.QUERY_INFORMATION.Oid = *((PULONG)(Irp->AssociatedIrp.SystemBuffer));
GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer = MDL_ADDRESS (Irp->MdlAddress);
GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = MDL_SIZE (Irp->MdlAddress);
GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
if (Miniport != NULL)
{
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
//
// Place the request on the queue.
//
ndisMQueueRequest(Miniport, &GlobalRequest->Request, NULL);
//
// Queue a work item if there is not one already queue'd.
//
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
//
// If we were able to grab the local lock then we can do some
// deferred processing now.
//
if (LocalLock)
{
NDISM_PROCESS_DEFERRED(Miniport);
}
UNLOCK_MINIPORT(Miniport, LocalLock);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
}
else
{
PNDIS_COREQ_RESERVED ReqRsvd;
ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&GlobalRequest->Request);
ReqRsvd->Open = NULL;
ReqRsvd->RequestCompleteHandler = NULL;
ReqRsvd->VcContext = NULL;
ReqRsvd->Flags = COREQ_GLOBAL_REQ;
ReqRsvd->RealRequest = NULL;
//
// Call the miniport's CoRequest Handler
//
Status = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
Miniport->MiniportAdapterContext,
NULL,
&GlobalRequest->Request);
if (Status != NDIS_STATUS_PENDING)
{
NdisMCoRequestComplete(Status,
Miniport,
&GlobalRequest->Request);
}
}
}
else
{
//
// Pass the request to the MAC.
//
NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
OpenContext->AdapterBlock->MacAdapterContext,
&GlobalRequest->Request);
//
// NdisCompleteQueryStatistics handles the completion.
//
if (NdisStatus != NDIS_STATUS_PENDING)
{
NdisCompleteQueryStatistics(OpenContext->AdapterBlock,
&GlobalRequest->Request,
NdisStatus);
}
}
Status = STATUS_PENDING;
break;
case IOCTL_NDIS_QUERY_ALL_STATS:
//
// Allocate a request.
//
AllRequest = (PNDIS_QUERY_ALL_REQUEST)ALLOC_FROM_POOL(sizeof(NDIS_QUERY_ALL_REQUEST),
NDIS_TAG_DEFAULT);
if (AllRequest == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
if (OpenContext->AdapterBlock->DeviceObject == NULL)
{
Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
//
// Do this for CL miniports only
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
LOCK_MINIPORT(Miniport, LocalLock);
}
}
else
{
Miniport = NULL;
}
AllRequest->Irp = Irp;
Buffer = (PUCHAR)MDL_ADDRESS (Irp->MdlAddress);
BufferLength = MDL_SIZE (Irp->MdlAddress);
BytesWritten = 0;
INITIALIZE_EVENT(&AllRequest->Event);
NdisStatus = NDIS_STATUS_SUCCESS;
for (CurrentOid = 0; CurrentOid<OpenContext->OidCount; CurrentOid++)
{
//
// We need room for an NDIS_STATISTICS_VALUE (OID,
// Length, Data).
//
if (BufferLength < (ULONG)NDIS_STATISTICS_HEADER_SIZE)
{
NdisStatus = NDIS_STATUS_INVALID_LENGTH;
break;
}
AllRequest->Request.RequestType = NdisRequestQueryStatistics;
AllRequest->Request.DATA.QUERY_INFORMATION.Oid = OpenContext->OidArray[CurrentOid];
AllRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer + NDIS_STATISTICS_HEADER_SIZE;
AllRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength - NDIS_STATISTICS_HEADER_SIZE;
AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
AllRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
if (Miniport != NULL)
{
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
//
// Queue the request.
//
ndisMQueueRequest(Miniport, &AllRequest->Request, NULL);
//
// Queue a work item if there is not one already queue'd.
//
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
//
// If we were able to grab the local lock then we can do some
// deferred processing now.
//
if (LocalLock)
{
NDISM_PROCESS_DEFERRED(Miniport);
}
NdisStatus = NDIS_STATUS_PENDING;
}
else
{
PNDIS_COREQ_RESERVED ReqRsvd;
ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(&AllRequest->Request);
ReqRsvd->Open = NULL;
ReqRsvd->RequestCompleteHandler = NULL;
ReqRsvd->VcContext = NULL;
ReqRsvd->Flags = COREQ_QUERY_STATS;
ReqRsvd->RealRequest = NULL;
//
// Call the miniport's CoRequest Handler
//
NdisStatus = (*Miniport->DriverHandle->MiniportCharacteristics.CoRequestHandler)(
Miniport->MiniportAdapterContext,
NULL,
&AllRequest->Request);
if (NdisStatus == NDIS_STATUS_PENDING)
{
//
// The completion routine will set NdisRequestStatus.
//
WAIT_FOR_OBJECT(&AllRequest->Event, NULL);
NdisStatus = AllRequest->NdisStatus;
}
}
}
else
{
NdisStatus = (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler)(
OpenContext->AdapterBlock->MacAdapterContext,
&AllRequest->Request);
}
if (NdisStatus == NDIS_STATUS_PENDING)
{
if ((Miniport != NULL) &&
!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
UNLOCK_MINIPORT(Miniport, LocalLock);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
}
//
// The completion routine will set NdisRequestStatus.
//
WAIT_FOR_OBJECT(&AllRequest->Event, NULL);
NdisStatus = AllRequest->NdisStatus;
if (Miniport != NULL)
{
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
LOCK_MINIPORT(Miniport, LocalLock);
}
}
if (NdisStatus == NDIS_STATUS_SUCCESS)
{
PNDIS_STATISTICS_VALUE StatisticsValue = (PNDIS_STATISTICS_VALUE)Buffer;
//
// Create the equivalent of an NDIS_STATISTICS_VALUE
// element for this OID value (the data itself was
// already written in the right place.
//
StatisticsValue->Oid = OpenContext->OidArray[CurrentOid];
StatisticsValue->DataLength = AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
//
// Advance our pointers.
//
BytesWrittenThisOid = AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten +
NDIS_STATISTICS_HEADER_SIZE;
Buffer += BytesWrittenThisOid;
BufferLength -= BytesWrittenThisOid;
BytesWritten += BytesWrittenThisOid;
}
else
{
break;
}
RESET_EVENT(&AllRequest->Event);
}
if (Miniport != NULL)
{
UNLOCK_MINIPORT(Miniport, LocalLock);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
}
if (NdisStatus == NDIS_STATUS_INVALID_LENGTH)
{
Status = STATUS_BUFFER_OVERFLOW;
}
else if (NdisStatus != NDIS_STATUS_SUCCESS)
{
Status = STATUS_UNSUCCESSFUL;
}
Irp->IoStatus.Information = BytesWritten;
Irp->IoStatus.Status = Status;
break;
default:
Status = STATUS_NOT_IMPLEMENTED;
break;
}
PnPDereferencePackage();
if (Status != STATUS_PENDING)
{
IrpSp->Control &= ~SL_PENDING_RETURNED;
Irp->IoStatus.Status = Status;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
}
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisDeviceControlIrpHandler\n"));
return Status;
}
BOOLEAN
ndisValidOid(
IN PNDIS_USER_OPEN_CONTEXT OpenContext,
IN NDIS_OID Oid
)
/*++
Routine Description:
Arguments:
Return Value:
TRUE if OID is valid, FALSE otherwise
--*/
{
UINT i;
for (i = 0; i < OpenContext->FullOidCount; i++)
{
if (OpenContext->FullOidArray[i] == Oid)
{
break;
}
}
return (i < OpenContext->FullOidCount);
}
VOID
NdisCompleteQueryStatistics(
IN NDIS_HANDLE NdisAdapterHandle,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS Status
)
/*++
Routine Description:
This routine is called by MACs when they have completed
processing of a MacQueryGlobalStatistics call.
Arguments:
NdisAdapterHandle - The NDIS adapter context.
NdisRequest - The request that has been completed.
Status - The status of the request.
Return Value:
None.
--*/
{
PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
PNDIS_QUERY_ALL_REQUEST AllRequest;
PNDIS_QUERY_OPEN_REQUEST OpenRequest;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
//
// Rely on the fact that all our request structures start with
// the same fields: Irp followed by the NdisRequest.
//
GlobalRequest = CONTAINING_RECORD (NdisRequest, NDIS_QUERY_GLOBAL_REQUEST, Request);
Irp = GlobalRequest->Irp;
IrpSp = IoGetCurrentIrpStackLocation (Irp);
switch (IrpSp->MajorFunction)
{
case IRP_MJ_CREATE:
//
// This request is one of the ones made during an open,
// while we are trying to determine the OID list. We
// set the event we are waiting for, the open code
// takes care of the rest.
//
OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
OpenRequest->NdisStatus = Status;
SET_EVENT(&OpenRequest->Event);
break;
case IRP_MJ_DEVICE_CONTROL:
//
// This is a real user request, process it as such.
//
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_NDIS_QUERY_GLOBAL_STATS:
//
// A single query, complete the IRP.
//
Irp->IoStatus.Information =
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
if (Status == NDIS_STATUS_SUCCESS)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
}
else if (Status == NDIS_STATUS_INVALID_LENGTH)
{
Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
}
else
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
FREE_POOL(GlobalRequest);
break;
case IOCTL_NDIS_QUERY_ALL_STATS:
//
// An "all" query.
//
AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
AllRequest->NdisStatus = Status;
SET_EVENT(&AllRequest->Event);
break;
}
break;
}
}
NTSTATUS
ndisCloseIrpHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The handle for IRP_MJ_CLOSE IRPs.
Arguments:
DeviceObject - The adapter's device object.
Irp - The IRP.
Return Value:
STATUS_SUCCESS if it should be.
--*/
{
PIO_STACK_LOCATION IrpSp;
PNDIS_USER_OPEN_CONTEXT OpenContext;
NTSTATUS Status = STATUS_SUCCESS;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisCloseIrpHandler\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Null Irp\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Irp not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
IrpSp = IoGetCurrentIrpStackLocation (Irp);
if (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS)
{
//
// Free the query context.
//
ASSERT (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS);
OpenContext = IrpSp->FileObject->FsContext;
if (OpenContext->OidArray != NULL)
{
FREE_POOL(OpenContext->OidArray);
}
if (OpenContext->FullOidArray != NULL)
{
FREE_POOL(OpenContext->FullOidArray);
}
FREE_POOL(OpenContext);
PnPDereferencePackage();
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisCloseIrpHandler\n"));
return Status;
}
NTSTATUS
ndisSuccessIrpHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The "success handler" for any IRPs that we can ignore.
Arguments:
DeviceObject - The adapter's device object.
Irp - The IRP.
Return Value:
Always STATUS_SUCCESS.
--*/
{
DeviceObject; // to avoid "unused formal parameter" warning
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>NdisSuccessIrpHandler\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Null Irp\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(Irp))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(": Irp not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisSuccessIrpHandler\n"));
return STATUS_SUCCESS;
}
VOID
ndisKillOpenAndNotifyProtocol(
IN PNDIS_OPEN_BLOCK OldOpenP
)
/*++
Routine Description:
Closes an open and notifies the protocol; used when the
close is internally generated by the NDIS wrapper (due to
a protocol or adapter deregistering with outstanding opens).
Arguments:
OldOpenP - The open to be closed.
Return Value:
None.
--*/
{
//
// Indicate the status to the protocol.
//
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisKillOpenAndNotifyProtocol\n"));
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
(" Closing Adapter %wZ and notifying Protocol %wZ\n",
&OldOpenP->AdapterHandle->AdapterName,
&(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(OldOpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisKillOpenAndNotifyProtocol: Null Open Block\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(OldOpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisKillOpenAndNotifyProtocol: Open Block not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
(OldOpenP->ProtocolHandle->ProtocolCharacteristics.StatusHandler)(
OldOpenP->ProtocolBindingContext,
NDIS_STATUS_CLOSING,
NULL,
0); // need real reason here
//
// Now KillOpen will do the real work.
//
if (OldOpenP->AdapterHandle->DeviceObject == NULL)
{
//
// Miniport
//
(void)ndisMKillOpen(OldOpenP);
}
else
{
//
// Mac
//
(void)ndisKillOpen(OldOpenP);
}
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisKillOpenAndNotifyProtocol\n"));
}
BOOLEAN
ndisKillOpen(
IN PNDIS_OPEN_BLOCK OldOpenP
)
/*++
Routine Description:
Closes an open. Used when NdisCloseAdapter is called, and also
for internally generated closes.
Arguments:
OldOpenP - The open to be closed.
Return Value:
TRUE if the open finished, FALSE if it pended.
--*/
{
KIRQL OldIrql;
PNDIS_OPEN_BLOCK *ppOpen;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisKillOpen\n"));
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
(" Closing Adapter %wZ as requested by %wZ\n",
&OldOpenP->AdapterHandle->AdapterName,
&(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(OldOpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisKillOpen: Null Open Block\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(OldOpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisKillOpen: Open Block not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
ACQUIRE_SPIN_LOCK(&OldOpenP->SpinLock, &OldIrql);
//
// See if this open is already closing.
//
if (OldOpenP->Closing)
{
RELEASE_SPIN_LOCK(&OldOpenP->SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisKillOpen\n"));
return TRUE;
}
//
// Indicate to others that this open is closing.
//
OldOpenP->Closing = TRUE;
RELEASE_SPIN_LOCK(&OldOpenP->SpinLock, OldIrql);
//
// Inform the MAC.
//
if ((OldOpenP->MacHandle->MacCharacteristics.CloseAdapterHandler)(
OldOpenP->MacBindingHandle) == NDIS_STATUS_PENDING)
{
//
// MacCloseAdapter pended, will complete later.
//
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisKillOpen\n"));
return FALSE;
}
//
// Remove the reference for this open.
//
ObDereferenceObject(OldOpenP->FileObject);
//
// Remove us from the adapter and protocol open queues.
//
ndisDeQueueOpenOnAdapter(OldOpenP, OldOpenP->AdapterHandle);
ndisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
//
// MacCloseAdapter did not pend; we ignore the return code.
//
ndisDereferenceProtocol(OldOpenP->ProtocolHandle);
ndisDereferenceAdapter(OldOpenP->AdapterHandle);
NdisFreeSpinLock(&OldOpenP->SpinLock);
//
// Remove from global open list
//
ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
for (ppOpen = &ndisGlobalOpenList;
*ppOpen != NULL;
ppOpen = &(*ppOpen)->NextGlobalOpen)
{
if (*ppOpen == OldOpenP)
{
*ppOpen = OldOpenP->NextGlobalOpen;
break;
}
}
ASSERT (*ppOpen == OldOpenP->NextGlobalOpen);
RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
FREE_POOL(OldOpenP);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisKillOpen\n"));
return TRUE;
}
BOOLEAN
ndisQueueAdapterOnMac(
IN PNDIS_ADAPTER_BLOCK AdaptP,
IN PNDIS_MAC_BLOCK MacP
)
/*++
Routine Description:
Adds an adapter to a list of adapters for a MAC.
Arguments:
AdaptP - The adapter block to queue.
MacP - The MAC block to queue it to.
Return Value:
FALSE if the MAC is closing.
TRUE otherwise.
--*/
{
KIRQL OldIrql;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisQueueAdapterOnMac\n"));
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
(" Adapter %wZ being added to MAC list\n",
&AdaptP->MacHandle->MacCharacteristics.Name));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
BOOLEAN f = FALSE;
if (DbgIsNull(AdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueAdapterOnMac: Null Adapter Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(AdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"));
f = TRUE;
}
if (DbgIsNull(MacP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueAdapterOnMac: Null Mac Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(MacP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"));
f = TRUE;
}
if (f)
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
NDIS_ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock, &OldIrql);
//
// Make sure the MAC is not closing.
//
if (MacP->Ref.Closing)
{
NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisQueueAdapterOnMac\n"));
return FALSE;
}
//
// Add this adapter at the head of the queue
//
AdaptP->NextAdapter = MacP->AdapterQueue;
MacP->AdapterQueue = AdaptP;
NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisQueueAdapterOnMac\n"));
return TRUE;
}
VOID
ndisDeQueueAdapterOnMac(
IN PNDIS_ADAPTER_BLOCK AdaptP,
IN PNDIS_MAC_BLOCK MacP
)
/*++
Routine Description:
Removes an adapter from a list of adapters for a MAC.
Arguments:
AdaptP - The adapter block to dequeue.
MacP - The MAC block to dequeue it from.
Return Value:
None.
--*/
{
KIRQL OldIrql;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisDeQueueAdapterOnMac\n"));
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
(" Adapter %wZ being removed from MAC list\n",
&AdaptP->MacHandle->MacCharacteristics.Name));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
BOOLEAN f = FALSE;
if (DbgIsNull(AdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueAdapterOnMac: Null Adapter Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(AdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"));
f = TRUE;
}
if (DbgIsNull(MacP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueAdapterOnMac: Null Mac Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(MacP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"));
f = TRUE;
}
if (f)
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
NDIS_ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock, &OldIrql);
//
// Find the MAC on the queue, and remove it.
//
if (MacP->AdapterQueue == AdaptP)
{
MacP->AdapterQueue = AdaptP->NextAdapter;
}
else
{
PNDIS_ADAPTER_BLOCK MP = MacP->AdapterQueue;
while (MP->NextAdapter != AdaptP)
{
MP = MP->NextAdapter;
}
MP->NextAdapter = MP->NextAdapter->NextAdapter;
}
NDIS_RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock, OldIrql);
if (MacP->Unloading && (MacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL))
{
SET_EVENT(&MacP->AdaptersRemovedEvent);
}
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisDeQueueAdapterOnMac\n"));
}
VOID
ndisKillAdapter(
IN PNDIS_ADAPTER_BLOCK OldAdaptP
)
/*++
Routine Description:
Removes an adapter. Called by NdisDeregisterAdapter and also
for internally generated deregistrations.
Arguments:
OldAdaptP - The adapter to be removed.
Return Value:
None.
--*/
{
//
// If the adapter is already closing, return.
//
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>ndisKillAdapter\n"));
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
(" Removing Adapter %s\n",OldAdaptP->AdapterName.Buffer));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(OldAdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisKillAdapter: Null Adapter Block\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(OldAdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisKillAdapter: Adapter Block not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
if (!NdisCloseRef(&OldAdaptP->Ref))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisKillAdapter\n"));
return;
}
//
// Kill all the opens for this adapter.
//
while (OldAdaptP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL)
{
//
// This removes it from the adapter's OpenQueue etc.
//
ndisKillOpenAndNotifyProtocol(OldAdaptP->OpenQueue);
}
//
// Remove the adapter from the MAC's list.
//
ndisDeQueueAdapterOnMac(OldAdaptP, OldAdaptP->MacHandle);
ndisDereferenceAdapter(OldAdaptP);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==ndisKillAdapter\n"));
}
VOID
ndisDereferenceAdapter(
IN PNDIS_ADAPTER_BLOCK AdaptP
)
/*++
Routine Description:
Dereferences an adapter. If the reference count goes to zero,
it frees resources associated with the adapter.
Arguments:
AdaptP - The adapter to be dereferenced.
Return Value:
None.
--*/
{
if (NdisDereferenceRef(&AdaptP->Ref))
{
//
// Free resource memory
//
if (AdaptP->Resources != NULL)
{
NdisReleaseAdapterResources(AdaptP);
FREE_POOL(AdaptP->Resources);
}
FREE_POOL(AdaptP->AdapterName.Buffer);
if (AdaptP->Master)
{
UINT i;
ULONG MapRegistersPerChannel =
((AdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
KIRQL OldIrql;
RAISE_IRQL_TO_DISPATCH(&OldIrql);
for (i=0; i<AdaptP->PhysicalMapRegistersNeeded; i++)
{
IoFreeMapRegisters(
AdaptP->SystemAdapterObject,
AdaptP->MapRegisters[i].MapRegister,
MapRegistersPerChannel);
}
LOWER_IRQL(OldIrql);
}
if ((AdaptP->NumberOfPorts > 0) && AdaptP->InitialPortMapped)
{
MmUnmapIoSpace (AdaptP->InitialPortMapping, AdaptP->NumberOfPorts);
}
//
// Delete the global db entry
//
if (AdaptP->BusId != 0)
{
ndisDeleteGlobalDb(AdaptP->BusType,
AdaptP->BusId,
AdaptP->BusNumber,
AdaptP->SlotNumber);
}
ndisDereferenceMac(AdaptP->MacHandle);
IoDeleteDevice(AdaptP->DeviceObject);
}
}
BOOLEAN
ndisQueueOpenOnAdapter(
IN PNDIS_OPEN_BLOCK OpenP,
IN PNDIS_ADAPTER_BLOCK AdaptP
)
/*++
Routine Description:
Adds an open to a list of opens for an adapter.
Arguments:
OpenP - The open block to queue.
AdaptP - The adapter block to queue it to.
Return Value:
None.
--*/
{
KIRQL OldIrql;
// attach ourselves to the adapter object linked list of opens
NDIS_ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock, &OldIrql);
//
// Make sure the adapter is not closing.
//
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>NdisQueueAdapterOnAdapter\n"));
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
(" Open being added to list for Adapter %s\n",AdaptP->AdapterName.Buffer));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
BOOLEAN f = FALSE;
if (DbgIsNull(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueOpenOnAdapter: Null Open Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"));
f = TRUE;
}
if (DbgIsNull(AdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueOpenOnAdapter: Null Adapter Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(AdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"));
f = TRUE;
}
if (f)
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (AdaptP->Ref.Closing)
{
NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisQueueAdapterOnAdapter\n"));
return FALSE;
}
//
// Attach this open at the head of the queue.
//
OpenP->AdapterNextOpen = AdaptP->OpenQueue;
AdaptP->OpenQueue = OpenP;
NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisQueueAdapterOnAdapter\n"));
return TRUE;
}
VOID
ndisDeQueueOpenOnAdapter(
IN PNDIS_OPEN_BLOCK OpenP,
IN PNDIS_ADAPTER_BLOCK AdaptP
)
/*++
Routine Description:
Removes an open from a list of opens for an adapter.
Arguments:
OpenP - The open block to dequeue.
AdaptP - The adapter block to dequeue it from.
Return Value:
None.
--*/
{
KIRQL OldIrql;
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("==>NdisDeQueueAdapterOnAdapter\n"));
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
(" Open being removed from list for Adapter %s\n",AdaptP->AdapterName.Buffer));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
BOOLEAN f = FALSE;
if (DbgIsNull(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueOpenOnAdapter: Null Open Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"));
f = TRUE;
}
if (DbgIsNull(AdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueOpenOnAdapter: Null Adapter Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(AdaptP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"));
f = TRUE;
}
if (f)
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
NDIS_ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock, &OldIrql);
//
// Find the open on the queue, and remove it.
//
if (AdaptP->OpenQueue == OpenP)
{
AdaptP->OpenQueue = OpenP->AdapterNextOpen;
}
else
{
PNDIS_OPEN_BLOCK AP = AdaptP->OpenQueue;
while (AP->AdapterNextOpen != OpenP)
{
AP = AP->AdapterNextOpen;
}
AP->AdapterNextOpen = AP->AdapterNextOpen->AdapterNextOpen;
}
NDIS_RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock, OldIrql);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("<==NdisDeQueueAdapterOnAdapter\n"));
}
VOID
ndisDereferenceMac(
IN PNDIS_MAC_BLOCK MacP
)
/*++
Routine Description:
Removes a reference from the mac, deleting it if the count goes to 0.
Arguments:
MacP - The Mac block to dereference.
Return Value:
None.
--*/
{
KIRQL OldIrql;
if (NdisDereferenceRef(&(MacP)->Ref))
{
//
// Remove it from the global list.
//
ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
if (ndisMacDriverList == MacP)
{
ndisMacDriverList = MacP->NextMac;
}
else
{
PNDIS_MAC_BLOCK TmpMacP = ndisMacDriverList;
while(TmpMacP->NextMac != MacP)
{
TmpMacP = TmpMacP->NextMac;
}
TmpMacP->NextMac = TmpMacP->NextMac->NextMac;
}
RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
if (MacP->PciAssignedResources != NULL)
{
FREE_POOL(MacP->PciAssignedResources);
}
FREE_POOL(MacP);
}
}
//
// Stubs to compile with Ndis 3.0 kernel.
//
NDIS_STATUS
EthAddFilterAddress()
{
return NDIS_STATUS_FAILURE;
}
NDIS_STATUS
EthDeleteFilterAddress()
{
return NDIS_STATUS_FAILURE;
}
NDIS_STATUS
NdisInitializePacketPool()
{
return NDIS_STATUS_FAILURE;
}
NDIS_STATUS
ndisUnloadMac(
IN PNDIS_ADAPTER_BLOCK Mac
)
/*++
Routine Description:
Unbind all protocols from this mac and finally unload it.
Arguments:
Mac - The Mac to unload.
Return Value:
None.
--*/
{
KIRQL OldIrql;
PNDIS_OPEN_BLOCK Open;
NDIS_BIND_CONTEXT UnbindContext;
NDIS_STATUS UnbindStatus;
//
// Walk the list of open bindings on this mac and ask the protocols to
// unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
//
NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
next:
for (Open = Mac->OpenQueue;
Open != NULL;
Open = Open->NextGlobalOpen)
{
if (!Open->Closing && !Open->Unloading &&
(Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler != NULL))
{
Open->Unloading = TRUE;
break;
}
}
if (Open != NULL)
{
NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
INITIALIZE_EVENT(&UnbindContext.Event);
WAIT_FOR_OBJECT(&Open->ProtocolHandle->Mutex, NULL);
(*Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler)(
&UnbindStatus,
Open->ProtocolBindingContext,
&UnbindContext);
if (UnbindStatus == NDIS_STATUS_PENDING)
{
WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
}
RELEASE_MUTEX(&Open->ProtocolHandle->Mutex);
NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
goto next;
}
NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
//
// The halt handler must be called when the last reference
// on the driver block goes away
//
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
ndisTranslateMacName(
IN PNDIS_ADAPTER_BLOCK Mac,
IN PUCHAR Buffer,
IN UINT BufferLength,
OUT PUINT AmountCopied
)
/*++
Routine Description:
Calls the PnP protocols to enumerate PnP ids for the given miniport.
Arguments:
Mac - The Mac in question.
Buffer, BufferLength - Buffer for a list of PnP Ids.
AmountCopied - How much buffer was used up.
Return Value:
None.
--*/
{
KIRQL OldIrql;
PNDIS_OPEN_BLOCK Open;
NDIS_STATUS Status;
UINT AmtCopied = 0, TotalAmtCopied = 0;
//
// Walk the list of open bindings on this mac and ask the protocols to
// unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
//
NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
for (Open = Mac->OpenQueue;
Open != NULL;
Open = Open->NextGlobalOpen)
{
if (!Open->Closing && !Open->Unloading &&
(Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler != NULL))
{
break;
}
}
if (Open != NULL)
{
NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
(*Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler)(
&Status,
Open->ProtocolBindingContext,
(PNET_PNP_ID)(Buffer + TotalAmtCopied),
BufferLength - TotalAmtCopied,
&AmtCopied);
if (Status == NDIS_STATUS_SUCCESS)
{
TotalAmtCopied += AmtCopied;
}
NDIS_ACQUIRE_SPIN_LOCK(&Mac->Ref.SpinLock, &OldIrql);
}
NDIS_RELEASE_SPIN_LOCK(&Mac->Ref.SpinLock, OldIrql);
*AmountCopied = TotalAmtCopied;
return NDIS_STATUS_SUCCESS;
}
#if defined(_ALPHA_)
VOID
NdisCreateLookaheadBufferFromSharedMemory(
IN PVOID pSharedMemory,
IN UINT LookaheadLength,
OUT PVOID * pLookaheadBuffer
)
/*++
Routine Description:
This routine creates a lookahead buffer from a pointer to shared
RAM because some architectures (like ALPHA) do not allow access
through a pointer to shared ram.
Arguments:
pSharedMemory - Pointer to shared ram space.
LookaheadLength - Amount of Lookahead to copy.
pLookaheadBuffer - Pointer to host memory space with a copy of the
stuff in pSharedMemory.
Return Value:
None.
--*/
{
KIRQL OldIrql;
PNDIS_LOOKAHEAD_ELEMENT TmpElement;
ACQUIRE_SPIN_LOCK(&ndisLookaheadBufferLock, &OldIrql);
if (ndisLookaheadBufferLength < (LookaheadLength +
sizeof(NDIS_LOOKAHEAD_ELEMENT)))
{
//
// Free current list
//
while (ndisLookaheadBufferList != NULL)
{
TmpElement = ndisLookaheadBufferList;
ndisLookaheadBufferList = ndisLookaheadBufferList->Next;
FREE_POOL(TmpElement);
}
ndisLookaheadBufferLength = LookaheadLength +
sizeof(NDIS_LOOKAHEAD_ELEMENT);
}
if (ndisLookaheadBufferList == NULL)
{
ndisLookaheadBufferList = (PNDIS_LOOKAHEAD_ELEMENT)ALLOC_FROM_POOL(ndisLookaheadBufferLength,
NDIS_TAG_LA_BUF);
if (ndisLookaheadBufferList == NULL)
{
*pLookaheadBuffer = NULL;
RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
return;
}
ndisLookaheadBufferList->Next = NULL;
ndisLookaheadBufferList->Length = ndisLookaheadBufferLength;
}
//
// Get the buffer
//
*pLookaheadBuffer = (ndisLookaheadBufferList + 1);
ndisLookaheadBufferList = ndisLookaheadBufferList->Next;
RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
//
// Copy the stuff across
//
READ_REGISTER_BUFFER_UCHAR(pSharedMemory, *pLookaheadBuffer, LookaheadLength);
}
VOID
NdisDestroyLookaheadBufferFromSharedMemory(
IN PVOID pLookaheadBuffer
)
/*++
Routine Description:
This routine returns resources associated with a lookahead buffer.
Arguments:
pLookaheadBuffer - Lookahead buffer created by
CreateLookaheadBufferFromSharedMemory.
Return Value:
None.
--*/
{
PNDIS_LOOKAHEAD_ELEMENT Element = (PNDIS_LOOKAHEAD_ELEMENT)pLookaheadBuffer;
KIRQL OldIrql;
Element--;
if (Element->Length != ndisLookaheadBufferLength)
{
FREE_POOL(Element);
}
else
{
ACQUIRE_SPIN_LOCK(&ndisLookaheadBufferLock, &OldIrql);
Element->Next = ndisLookaheadBufferList;
ndisLookaheadBufferList = Element;
RELEASE_SPIN_LOCK(&ndisLookaheadBufferLock, OldIrql);
}
}
#endif // _ALPHA_