2198 lines
56 KiB
C
2198 lines
56 KiB
C
/*++
|
|
|
|
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
|
|
|
|
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;
|
|
}
|
|
|
|
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_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
|
|
//
|
|
// Save this translation entry in the correct spot.
|
|
//
|
|
|
|
Miniport->MapRegisters[Miniport->CurrentMapRegister].MapRegister = MapRegisterBase;
|
|
|
|
//
|
|
// This will free the thread that is waiting for this callback.
|
|
//
|
|
|
|
SET_EVENT(Miniport->AllocationEvent);
|
|
|
|
return DeallocateObjectKeepRegisters;
|
|
}
|
|
|
|
|
|
VOID __cdecl
|
|
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_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
|
|
UINT i, StringSize;
|
|
PWCH baseFileName;
|
|
ULONG ulErrorLogSize = 0;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("==>NdisWriteErrorLogEntry\n"));
|
|
|
|
if (Miniport == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
baseFileName = Miniport->pAdapterInstanceName->Buffer;
|
|
StringSize = Miniport->pAdapterInstanceName->MaximumLength;
|
|
|
|
ulErrorLogSize = sizeof(IO_ERROR_LOG_PACKET) + NumberOfErrorValues * sizeof(ULONG) + StringSize;
|
|
|
|
//
|
|
// If the size is too large , use the MiniportName instead (\Device\{GUID} )
|
|
//
|
|
if (ulErrorLogSize > ERROR_LOG_MAXIMUM_SIZE )
|
|
{
|
|
baseFileName = Miniport->MiniportName.Buffer;
|
|
StringSize = Miniport->MiniportName.MaximumLength;
|
|
|
|
ulErrorLogSize = sizeof(IO_ERROR_LOG_PACKET) + NumberOfErrorValues * sizeof(ULONG) + StringSize;
|
|
|
|
}
|
|
|
|
if (ulErrorLogSize > ERROR_LOG_MAXIMUM_SIZE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(Miniport->DeviceObject, (UCHAR)ulErrorLogSize);
|
|
|
|
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 = (USHORT)(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);
|
|
}
|
|
|
|
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
|
|
("<==NdisWriteErrorLogEntry\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisSend(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
*Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->SendHandler)(
|
|
(PNDIS_OPEN_BLOCK)NdisBindingHandle,
|
|
Packet);
|
|
}
|
|
|
|
VOID
|
|
NdisSendPackets(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
{
|
|
(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->SendPacketsHandler)(
|
|
(PNDIS_OPEN_BLOCK)NdisBindingHandle,
|
|
PacketArray,
|
|
NumberOfPackets);
|
|
}
|
|
|
|
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,
|
|
MacReceiveContext,
|
|
ByteOffset,
|
|
BytesToTransfer,
|
|
Packet,
|
|
BytesTransferred);
|
|
}
|
|
|
|
VOID
|
|
NdisReset(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle
|
|
)
|
|
{
|
|
*Status = NDIS_STATUS_NOT_RESETTABLE;
|
|
if (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->ResetHandler != NULL)
|
|
{
|
|
*Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->ResetHandler)(
|
|
(PNDIS_OPEN_BLOCK)NdisBindingHandle);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NdisRequest(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
{
|
|
*Status = (((PNDIS_OPEN_BLOCK)NdisBindingHandle)->RequestHandler)(
|
|
(PNDIS_OPEN_BLOCK)NdisBindingHandle,
|
|
NdisRequest);
|
|
}
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
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_RAW(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);
|
|
}
|
|
}
|
|
ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
|
|
|
|
if (RefP->Closing)
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
else
|
|
{
|
|
++(RefP->ReferenceCount);
|
|
|
|
if (RefP->ReferenceCount == 0)
|
|
{
|
|
--(RefP->ReferenceCount);
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisReferenceRef\n"));
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
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_RAW(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);
|
|
}
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
|
|
|
|
--(RefP->ReferenceCount);
|
|
|
|
if (RefP->ReferenceCount == 0)
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisDereferenceRef\n"));
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
ndisInitializeRef(
|
|
IN PREFERENCE RefP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize a reference count structure.
|
|
|
|
Arguments:
|
|
|
|
RefP - The structure to be initialized.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGPRINT_RAW(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;
|
|
INITIALIZE_SPIN_LOCK(&RefP->SpinLock);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisInitializeRef\n"));
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
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_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisCloseRef\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
|
|
|
|
if (RefP->Closing)
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
else RefP->Closing = TRUE;
|
|
|
|
RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisCloseRef\n"));
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisReferenceULongRef(
|
|
IN PULONG_REFERENCE 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_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisReferenceULongRef\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
|
|
|
|
if (RefP->Closing)
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
else
|
|
{
|
|
++(RefP->ReferenceCount);
|
|
|
|
if (RefP->ReferenceCount == 0)
|
|
{
|
|
--(RefP->ReferenceCount);
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisReferenceULongRef\n"));
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
ndisReferenceULongRefNoCheck(
|
|
IN PULONG_REFERENCE RefP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a reference to an object.
|
|
|
|
Arguments:
|
|
|
|
RefP - A pointer to the REFERENCE portion of the object.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisReferenceULongRefNoCheck\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
|
|
|
|
++(RefP->ReferenceCount);
|
|
|
|
RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisReferenceULongRefNoCheck\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisDereferenceULongRef(
|
|
IN PULONG_REFERENCE 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_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisDereferenceULongRef\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
|
|
|
|
--(RefP->ReferenceCount);
|
|
|
|
if (RefP->ReferenceCount == 0)
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisDereferenceULongRef\n"));
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
ndisInitializeULongRef(
|
|
IN PULONG_REFERENCE RefP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize a reference count structure.
|
|
|
|
Arguments:
|
|
|
|
RefP - The structure to be initialized.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisInitializeULongRef\n"));
|
|
|
|
RefP->Closing = FALSE;
|
|
RefP->ReferenceCount = 1;
|
|
INITIALIZE_SPIN_LOCK(&RefP->SpinLock);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisInitializeULongRef\n"));
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
ndisCloseULongRef(
|
|
IN PULONG_REFERENCE 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_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisCloseULongRef\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK(&RefP->SpinLock, &OldIrql);
|
|
|
|
if (RefP->Closing)
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
else RefP->Closing = TRUE;
|
|
|
|
RELEASE_SPIN_LOCK(&RefP->SpinLock, OldIrql);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisCloseULongRef\n"));
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
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;
|
|
PNDIS_USER_OPEN_CONTEXT OpenContext = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS, SecurityStatus;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
KIRQL OldIrql;
|
|
BOOLEAN fRef = FALSE;
|
|
BOOLEAN fWait;
|
|
BOOLEAN fUserModeRef = FALSE;
|
|
BOOLEAN AdminAccessAllowed = FALSE;
|
|
BOOLEAN DerefAdminOpenCount = FALSE, DerefUserOpenCount = FALSE;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("==>ndisCreateIrpHandler\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
if (IrpSp->FileObject == NULL)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
|
|
|
|
if (Miniport->Signature != (PVOID)MINIPORT_DEVICE_MAGIC_VALUE)
|
|
{
|
|
return (ndisDummyIrpHandler(DeviceObject, Irp));
|
|
}
|
|
|
|
AdminAccessAllowed = ndisCheckAccess(Irp,
|
|
IrpSp,
|
|
&SecurityStatus,
|
|
Miniport->SecurityDescriptor);
|
|
|
|
do
|
|
{
|
|
|
|
ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock, &OldIrql);
|
|
|
|
if ((AdminAccessAllowed && (Miniport->NumAdminOpens >= NDIS_MAX_ADMIN_OPEN_HANDLES)) ||
|
|
((!AdminAccessAllowed) && (Miniport->NumUserOpens >= NDIS_MAX_USER_OPEN_HANDLES)))
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock, OldIrql);
|
|
break;
|
|
}
|
|
|
|
if (AdminAccessAllowed)
|
|
{
|
|
Miniport->NumAdminOpens++;
|
|
DerefAdminOpenCount = TRUE;;
|
|
}
|
|
else
|
|
{
|
|
Miniport->NumUserOpens++;
|
|
DerefUserOpenCount = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock, OldIrql);
|
|
|
|
|
|
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_FAILED |
|
|
fMINIPORT_REJECT_REQUESTS))
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
|
|
fWait = NdisWaitEvent(&Miniport->OpenReadyEvent, NDIS_USER_OPEN_WAIT_TIME);
|
|
if (fWait)
|
|
{
|
|
fRef = MINIPORT_INCREMENT_REF_CREATE(Miniport, Irp);
|
|
}
|
|
|
|
if (!fWait || !fRef)
|
|
{
|
|
if (!fWait && (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING) ||
|
|
!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED)))
|
|
{
|
|
Status = STATUS_DEVICE_POWERED_OFF;
|
|
}
|
|
else
|
|
{
|
|
Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Lock down this code since we are about to take a spinlock.
|
|
//
|
|
PnPReferencePackage();
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
if (Miniport->PnPDeviceState == NdisPnPDeviceQueryStopped)
|
|
{
|
|
Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
PnPDereferencePackage();
|
|
break;
|
|
}
|
|
Miniport->UserModeOpenReferences++;
|
|
fUserModeRef = TRUE;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
PnPDereferencePackage();
|
|
|
|
OpenContext = (PNDIS_USER_OPEN_CONTEXT)ALLOC_FROM_POOL(sizeof(NDIS_USER_OPEN_CONTEXT),
|
|
NDIS_TAG_OPEN_CONTEXT);
|
|
if (OpenContext == NULL)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
OpenContext->DeviceObject = DeviceObject;
|
|
OpenContext->Miniport = Miniport;
|
|
OpenContext->OidList = NULL;
|
|
OpenContext->AdminAccessAllowed = AdminAccessAllowed;
|
|
|
|
IrpSp->FileObject->FsContext = OpenContext;
|
|
|
|
//
|
|
// Checked if we already cached OidList, if so just set it here.
|
|
//
|
|
if (Miniport->OidList != NULL)
|
|
{
|
|
OpenContext->OidList = Miniport->OidList;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (OpenContext->OidList == NULL)
|
|
{
|
|
Status = ndisQueryOidList(OpenContext);
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Some drivers return some bogus non-zero error
|
|
//
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (NT_SUCCESS(Status) && MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SWENUM))
|
|
{
|
|
PBUS_INTERFACE_REFERENCE BusInterface;
|
|
|
|
BusInterface = (PBUS_INTERFACE_REFERENCE)(Miniport->BusInterface);
|
|
|
|
ASSERT(BusInterface != NULL);
|
|
|
|
if (BusInterface)
|
|
{
|
|
BusInterface->ReferenceDeviceObject(BusInterface->Interface.Context);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (DerefAdminOpenCount)
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock, &OldIrql);
|
|
Miniport->NumAdminOpens--;
|
|
RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock, OldIrql);
|
|
}
|
|
if (DerefUserOpenCount)
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock, &OldIrql);
|
|
Miniport->NumUserOpens--;
|
|
RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock, OldIrql);
|
|
}
|
|
|
|
if (fUserModeRef)
|
|
{
|
|
PnPReferencePackage();
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
Miniport->UserModeOpenReferences--;
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
PnPDereferencePackage();
|
|
}
|
|
|
|
if (fRef)
|
|
{
|
|
MINIPORT_DECREMENT_REF_CLOSE(Miniport, Irp);
|
|
}
|
|
|
|
if (OpenContext)
|
|
{
|
|
FREE_POOL(OpenContext);
|
|
}
|
|
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("<==NdisCreateIrplHandler\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisQueryOidList(
|
|
IN PNDIS_USER_OPEN_CONTEXT OpenContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will take care of querying the complete OID list for the MAC and filling in
|
|
OpenContext->OidList->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.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if it should be.
|
|
|
|
--*/
|
|
{
|
|
NDIS_REQUEST Request;
|
|
NDIS_STATUS Status;
|
|
PNDIS_OID Buffer;
|
|
ULONG BufferLength;
|
|
|
|
Status = ndisQueryDeviceOid(OpenContext,
|
|
&Request,
|
|
OID_GEN_SUPPORTED_LIST,
|
|
NULL,
|
|
0);
|
|
if ((Status != NDIS_STATUS_INVALID_LENGTH) && (Status != NDIS_STATUS_BUFFER_TOO_SHORT))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Now we know how much is needed, allocate temp storage...
|
|
//
|
|
BufferLength = Request.DATA.QUERY_INFORMATION.BytesNeeded;
|
|
Buffer = ALLOC_FROM_POOL(BufferLength, NDIS_TAG_DEFAULT);
|
|
|
|
if (Buffer == NULL)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
Status = ndisQueryDeviceOid(OpenContext,
|
|
&Request,
|
|
OID_GEN_SUPPORTED_LIST,
|
|
Buffer,
|
|
BufferLength);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Status = ndisSplitStatisticsOids(OpenContext,
|
|
Buffer,
|
|
BufferLength/sizeof(NDIS_OID));
|
|
}
|
|
|
|
FREE_POOL(Buffer);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisSplitStatisticsOids(
|
|
IN PNDIS_USER_OPEN_CONTEXT OpenContext,
|
|
IN PNDIS_OID OidList,
|
|
IN ULONG NumOids
|
|
)
|
|
{
|
|
ULONG i, j;
|
|
ULONG StatsOids;
|
|
|
|
//
|
|
// Go through the buffer, counting the statistics OIDs.
|
|
// Ignore all the custom oids which match the statistics
|
|
// criteria
|
|
//
|
|
for (i = StatsOids = 0; i < NumOids; i++)
|
|
{
|
|
if (((OidList[i] & 0x00ff0000) == 0x00020000) &&
|
|
((OidList[i] & 0xff000000) != 0xff000000))
|
|
{
|
|
StatsOids++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now allocate storage for the stat and non-stat OID arrays.
|
|
//
|
|
OpenContext->OidList = (POID_LIST)ALLOC_FROM_POOL(sizeof(OID_LIST) + ((StatsOids + NumOids)*sizeof(NDIS_OID)),
|
|
NDIS_TAG_OID_ARRAY);
|
|
if (OpenContext->OidList == NULL)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
OpenContext->OidList->FullOidCount = NumOids;
|
|
OpenContext->OidList->FullOidArray = (PNDIS_OID)(OpenContext->OidList + 1);
|
|
OpenContext->OidList->StatsOidCount = StatsOids;
|
|
OpenContext->OidList->StatsOidArray = OpenContext->OidList->FullOidArray + NumOids;
|
|
|
|
//
|
|
// 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) &&
|
|
((OidList[i] & 0xff000000) != 0xff000000))
|
|
{
|
|
OpenContext->OidList->StatsOidArray[j++] = OidList[i];
|
|
}
|
|
OpenContext->OidList->FullOidArray[i] = OidList[i];
|
|
}
|
|
|
|
ASSERT (j == OpenContext->OidList->StatsOidCount);
|
|
|
|
//
|
|
// Save it in the miniport
|
|
//
|
|
OpenContext->Miniport->OidList = OpenContext->OidList;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisCancelLogIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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_MINIPORT_BLOCK Miniport;
|
|
KIRQL OldIrql;
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
OpenContext = IrpSp->FileObject->FsContext;
|
|
ASSERT(OpenContext != NULL);
|
|
Miniport = OpenContext->Miniport;
|
|
|
|
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);
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
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;
|
|
NDIS_REQUEST Request;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
UINT OidCount;
|
|
PNDIS_OID OidArray;
|
|
PUCHAR OidBuffer = NULL;
|
|
ULONG BytesWritten = 0;
|
|
PUCHAR Buffer;
|
|
ULONG BufferLength;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
BOOLEAN fWaitComplete = FALSE;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisDeviceControlIrpHandler\n"));
|
|
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
if (IrpSp->FileObject == NULL)
|
|
{
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
|
|
|
|
if (Miniport->Signature != (PVOID)MINIPORT_DEVICE_MAGIC_VALUE)
|
|
{
|
|
return (ndisDummyIrpHandler(DeviceObject, Irp));
|
|
}
|
|
|
|
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_REMOVE_IN_PROGRESS | fMINIPORT_PM_HALTED))
|
|
{
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
IoMarkIrpPending (Irp);
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
OpenContext = IrpSp->FileObject->FsContext;
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_NDIS_GET_LOG_DATA:
|
|
|
|
if (Irp->MdlAddress == NULL)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
NdisStatus = Status = ndisMGetLogData(Miniport, Irp);
|
|
|
|
if (Status != STATUS_PENDING)
|
|
{
|
|
fWaitComplete = TRUE;
|
|
}
|
|
break;
|
|
|
|
//1this actually lets all the OIDs (set and query) to go to
|
|
//1 miniport's QueryInformationHandler and not only
|
|
//1 stats or query OIDs.
|
|
case IOCTL_NDIS_QUERY_GLOBAL_STATS:
|
|
|
|
//
|
|
// check for a minimum length, alignment and valid OIDs
|
|
//
|
|
if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(NDIS_OID)) ||
|
|
((ULONG_PTR)Irp->AssociatedIrp.SystemBuffer & (sizeof(NDIS_OID)-1)) ||
|
|
!ndisValidOid(OpenContext,
|
|
*((PULONG)(Irp->AssociatedIrp.SystemBuffer))))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
Buffer = (Irp->MdlAddress != NULL) ? MDL_ADDRESS_SAFE(Irp->MdlAddress, LowPagePriority) : NULL;
|
|
if ((Irp->MdlAddress != NULL) && (Buffer == NULL))
|
|
{
|
|
NdisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// check for alignment on output buffer
|
|
//
|
|
if ((ULONG_PTR)Buffer & (MAX_NATURAL_ALIGNMENT -1))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//1 we can potentially send a set OID down with requestType = RequestTypeQueryInformation
|
|
NdisStatus = ndisQueryDeviceOid(OpenContext,
|
|
&Request,
|
|
*((PNDIS_OID)Irp->AssociatedIrp.SystemBuffer),
|
|
Buffer,
|
|
(Irp->MdlAddress != NULL) ? MDL_SIZE(Irp->MdlAddress) : 0);
|
|
BytesWritten = Request.DATA.QUERY_INFORMATION.BytesWritten;
|
|
Irp->IoStatus.Information = BytesWritten;
|
|
fWaitComplete = TRUE;
|
|
break;
|
|
|
|
case IOCTL_NDIS_QUERY_ALL_STATS:
|
|
|
|
OidCount = OpenContext->OidList->StatsOidCount;
|
|
OidArray = OpenContext->OidList->StatsOidArray;
|
|
goto common;
|
|
break;
|
|
|
|
case IOCTL_NDIS_QUERY_SELECTED_STATS:
|
|
|
|
//
|
|
// This is essentially a combination of QUERY_ALL_STATS and QUERY_GLOBAL_STATS.
|
|
// Start off by verifying input parameters.
|
|
//
|
|
if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(NDIS_OID)) ||
|
|
((IrpSp->Parameters.DeviceIoControl.InputBufferLength % sizeof(NDIS_OID)) != 0) ||
|
|
((ULONG_PTR)Irp->AssociatedIrp.SystemBuffer & (sizeof(NDIS_OID)-1)))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
OidCount = IrpSp->Parameters.DeviceIoControl.InputBufferLength / sizeof(NDIS_OID);
|
|
OidArray = (PNDIS_OID)(Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
OidBuffer = (PUCHAR)ALLOC_FROM_POOL(OidCount * sizeof(NDIS_OID), NDIS_TAG_ALLOC_MEM);
|
|
if (OidBuffer == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
NdisMoveMemory(OidBuffer, (PUCHAR)OidArray, OidCount * sizeof(NDIS_OID));
|
|
|
|
OidArray = (PNDIS_OID)OidBuffer;
|
|
|
|
common:
|
|
BufferLength = (Irp->MdlAddress != NULL) ? MDL_SIZE(Irp->MdlAddress) : 0;
|
|
Buffer = (BufferLength != 0) ? (PUCHAR)MDL_ADDRESS_SAFE (Irp->MdlAddress, LowPagePriority) : NULL;
|
|
if (Buffer == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
if ((ULONG_PTR)Buffer & (MAX_NATURAL_ALIGNMENT-1))
|
|
{
|
|
|
|
DBGPRINT_RAW(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("ndisDeviceControlIrpHandler: Misaligned data.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
NdisStatus = ndisQueryStatisticsOids(Miniport,
|
|
OpenContext,
|
|
OidArray,
|
|
OidCount,
|
|
Buffer,
|
|
BufferLength,
|
|
&BytesWritten,
|
|
FALSE);
|
|
|
|
Irp->IoStatus.Information = BytesWritten;
|
|
fWaitComplete = TRUE;
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
if (fWaitComplete)
|
|
{
|
|
if (NdisStatus == NDIS_STATUS_INVALID_LENGTH)
|
|
{
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else if (NdisStatus == NDIS_STATUS_RESOURCES)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
else if (NdisStatus == NDIS_STATUS_NOT_SUPPORTED)
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else if (NdisStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
if (Status != STATUS_PENDING)
|
|
{
|
|
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
|
}
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisDeviceControlIrpHandler\n"));
|
|
|
|
if (OidBuffer)
|
|
{
|
|
FREE_POOL(OidBuffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
FASTCALL
|
|
ndisQueryDeviceOid(
|
|
IN PNDIS_USER_OPEN_CONTEXT OpenContext,
|
|
IN PNDIS_REQUEST Request,
|
|
IN NDIS_OID Oid,
|
|
IN PVOID Buffer,
|
|
IN UINT BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
Status of operation
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS NdisStatus;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
|
|
do
|
|
{
|
|
Miniport = OpenContext->Miniport;
|
|
|
|
Request->RequestType = NdisRequestQueryStatistics;
|
|
Request->DATA.QUERY_INFORMATION.Oid = Oid;
|
|
Request->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength;
|
|
Request->DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
|
|
Request->DATA.QUERY_INFORMATION.BytesWritten = 0;
|
|
Request->DATA.QUERY_INFORMATION.BytesNeeded = 0;
|
|
|
|
NdisStatus = ndisQuerySetMiniport(Miniport,
|
|
NULL,
|
|
FALSE,
|
|
Request,
|
|
NULL);
|
|
|
|
} while (FALSE);
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FASTCALL
|
|
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;
|
|
|
|
//
|
|
// Always allow this range since it is vendor specific
|
|
//
|
|
//1 replace with (Oid & 0xFF000000) == 0xff000000
|
|
//1 this seems unnecessary
|
|
if ((Oid & 0xFF000000) != 0)
|
|
return(TRUE);
|
|
|
|
for (i = 0; i < OpenContext->OidList->FullOidCount; i++)
|
|
{
|
|
if (OpenContext->OidList->FullOidArray[i] == Oid)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (i < OpenContext->OidList->FullOidCount);
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PNDIS_USER_OPEN_CONTEXT OpenContext;
|
|
KIRQL OldIrql;
|
|
|
|
//1 investigate moving this to CLEAN_UP IRP
|
|
DBGPRINT_RAW(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);
|
|
}
|
|
}
|
|
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
|
|
|
|
if (Miniport->Signature != (PVOID)MINIPORT_DEVICE_MAGIC_VALUE)
|
|
{
|
|
return (ndisDummyIrpHandler(DeviceObject, Irp));
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
|
|
OpenContext = IrpSp->FileObject->FsContext;
|
|
IrpSp->FileObject->FsContext = NULL;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock, &OldIrql);
|
|
if (OpenContext->AdminAccessAllowed)
|
|
{
|
|
Miniport->NumAdminOpens--;
|
|
}
|
|
else
|
|
{
|
|
Miniport->NumUserOpens--;
|
|
}
|
|
RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock, OldIrql);
|
|
|
|
FREE_POOL(OpenContext);
|
|
|
|
PnPReferencePackage();
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
Miniport->UserModeOpenReferences--;
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
PnPDereferencePackage();
|
|
|
|
MINIPORT_DECREMENT_REF_CLOSE(Miniport, Irp);
|
|
|
|
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SWENUM))
|
|
{
|
|
PBUS_INTERFACE_REFERENCE BusInterface;
|
|
|
|
BusInterface = (PBUS_INTERFACE_REFERENCE)(Miniport->BusInterface);
|
|
|
|
ASSERT(BusInterface != NULL);
|
|
|
|
if (BusInterface)
|
|
{
|
|
BusInterface->DereferenceDeviceObject(BusInterface->Interface.Context);
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==NdisCloseIrpHandler\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ndisDummyIrpHandler(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Default handler. If this is a NDIS device, then we simply succeed. If not and we have a
|
|
custom handler, we pass it on. Else we succeed.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The adapter's device object.
|
|
Irp - The IRP.
|
|
|
|
Return Value:
|
|
|
|
Always STATUS_SUCCESS.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_DEVICE_LIST DeviceList;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
NTSTATUS Status;
|
|
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisDummyIrpHandler\n"));
|
|
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
DeviceList = (PNDIS_DEVICE_LIST)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)DeviceList;
|
|
|
|
do
|
|
{
|
|
//
|
|
// This is a miniport
|
|
//
|
|
if (Miniport->Signature == (PVOID)MINIPORT_DEVICE_MAGIC_VALUE)
|
|
{
|
|
if (IrpSp->MajorFunction == IRP_MJ_CLEANUP)
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
break;
|
|
}
|
|
else if (DeviceList->Signature == (PVOID)CUSTOM_DEVICE_MAGIC_VALUE)
|
|
{
|
|
if (DeviceList->MajorFunctions[IrpSp->MajorFunction] == NULL)
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
return((*DeviceList->MajorFunctions[IrpSp->MajorFunction])(DeviceObject, Irp));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
} while (FALSE);
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisDummyIrpHandler\n"));
|
|
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisQueryStatisticsOids(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_USER_OPEN_CONTEXT OpenContext,
|
|
IN PNDIS_OID OidArray,
|
|
IN UINT OidCount,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG BufferLength,
|
|
IN PULONG pBytesWritten,
|
|
IN BOOLEAN AlignOutput
|
|
)
|
|
{
|
|
NDIS_STATUS NdisStatus;
|
|
ULONG CurrentOid;
|
|
NDIS_OID Oid;
|
|
NDIS_REQUEST Request;
|
|
ULONG DataLength;
|
|
ULONG BufferLengthRemained = BufferLength;
|
|
ULONG BytesWrittenThisOid = 0;
|
|
// ULONG BytesWrittenAlignedThisOid = 0;
|
|
ULONG NdisStatisticsHeaderSize;
|
|
ULONG BytesWritten = 0;
|
|
PNDIS_STATISTICS_VALUE StatisticsValue;
|
|
// PNDIS_STATISTICS_VALUE_EX StatisticsValueEx;
|
|
PUCHAR DoubleBuffer = NULL;
|
|
PVOID SourceBuffer;
|
|
ULONG SourceLength;
|
|
ULONG GenericULong;
|
|
TIME CurrTicks;
|
|
ULONG InfoFlags = 0;
|
|
BOOLEAN fPrv, fInt;
|
|
|
|
|
|
DBGPRINT_RAW(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("==>ndisQueryStatisticsOids\n"));
|
|
|
|
*pBytesWritten = 0;
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
if (AlignOutput)
|
|
{
|
|
//
|
|
// activate for longhorn
|
|
//
|
|
ASSERT(FALSE);
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
// NdisStatisticsHeaderSize = NDIS_STATISTICS_EX_HEADER_SIZE;
|
|
// ZeroMemory(Buffer, BufferLength);
|
|
}
|
|
else
|
|
{
|
|
DoubleBuffer = (PUCHAR)ALLOC_FROM_POOL(BufferLength, NDIS_TAG_ALLOC_MEM);
|
|
|
|
if (DoubleBuffer == NULL)
|
|
{
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
NdisStatisticsHeaderSize = NDIS_STATISTICS_HEADER_SIZE;
|
|
}
|
|
|
|
for (CurrentOid = 0; CurrentOid < OidCount; CurrentOid++)
|
|
{
|
|
SourceLength = 0;
|
|
SourceBuffer = NULL;
|
|
|
|
NdisZeroMemory(&Request, sizeof(NDIS_REQUEST));
|
|
|
|
//
|
|
// We need room for an NDIS_STATISTICS_VALUE (OID, Length, Data).
|
|
//
|
|
//1 check to see if having room for a ULONG is not good enough.
|
|
if (BufferLengthRemained < (ULONG)(NdisStatisticsHeaderSize + sizeof(ULONG)))
|
|
{
|
|
NdisStatus = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
DataLength = BufferLengthRemained - NdisStatisticsHeaderSize;
|
|
|
|
//
|
|
// Check if the OID is part of supported list - if not do not
|
|
// error out but ignore
|
|
//
|
|
Oid = OidArray[CurrentOid];
|
|
|
|
//1 choose another name for NDIS_OID_PRIVATE. This is here
|
|
//1 to be backward compatible for those apps that send statistics
|
|
//1 OIDs with 0x80000000 bit set.
|
|
fPrv = ((Oid & NDIS_OID_MASK) == NDIS_OID_PRIVATE);
|
|
|
|
if (fPrv)
|
|
{
|
|
Oid &= ~NDIS_OID_PRIVATE;
|
|
}
|
|
|
|
//1 find a better way to find out if an OID is internal or not.
|
|
fInt = (
|
|
(Oid == OID_GEN_DIRECTED_FRAMES_RCV) ||
|
|
(Oid == OID_GEN_DIRECTED_FRAMES_XMIT) ||
|
|
(Oid == OID_GEN_MEDIA_IN_USE) ||
|
|
(Oid == OID_GEN_PHYSICAL_MEDIUM) ||
|
|
(Oid == OID_GEN_INIT_TIME_MS) ||
|
|
(Oid == OID_GEN_RESET_COUNTS) ||
|
|
(Oid == OID_GEN_MEDIA_SENSE_COUNTS) ||
|
|
(Oid == OID_GEN_ELAPSED_TIME) ||
|
|
(Oid == OID_GEN_RESET_VERIFY_PARAMETERS) ||
|
|
(Oid == OID_GEN_MINIPORT_INFO) ||
|
|
(Oid == OID_PNP_ENABLE_WAKE_UP));
|
|
|
|
if (fInt)
|
|
{
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
switch (Oid)
|
|
{
|
|
case OID_GEN_DIRECTED_FRAMES_RCV:
|
|
SourceBuffer = &Miniport->NdisStats.DirectedPacketsIn;
|
|
|
|
if (DataLength >= sizeof(ULONG64))
|
|
{
|
|
SourceLength = sizeof(ULONG64);
|
|
}
|
|
else
|
|
{
|
|
SourceLength = sizeof(ULONG);
|
|
}
|
|
break;
|
|
|
|
case OID_GEN_DIRECTED_FRAMES_XMIT:
|
|
SourceBuffer = &Miniport->NdisStats.DirectedPacketsOut;
|
|
|
|
if (DataLength >= sizeof(ULONG64))
|
|
{
|
|
SourceLength = sizeof(ULONG64);
|
|
}
|
|
else
|
|
{
|
|
SourceLength = sizeof(ULONG);
|
|
}
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_IN_USE:
|
|
SourceBuffer = &Miniport->MediaType;
|
|
SourceLength = sizeof(ULONG);
|
|
|
|
break;
|
|
|
|
case OID_PNP_ENABLE_WAKE_UP:
|
|
SourceBuffer = &Miniport->WakeUpEnable;
|
|
SourceLength = sizeof(ULONG);
|
|
break;
|
|
|
|
case OID_GEN_PHYSICAL_MEDIUM:
|
|
SourceBuffer = &Miniport->PhysicalMediumType;
|
|
SourceLength = sizeof(ULONG);
|
|
break;
|
|
|
|
case OID_GEN_INIT_TIME_MS:
|
|
SourceBuffer = &Miniport->InitTimeMs;
|
|
SourceLength = sizeof(ULONG);
|
|
break;
|
|
|
|
case OID_GEN_RESET_COUNTS:
|
|
GenericULong = (Miniport->InternalResetCount + Miniport->MiniportResetCount);
|
|
SourceBuffer = &GenericULong;
|
|
SourceLength = sizeof(ULONG);
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_SENSE_COUNTS:
|
|
GenericULong = (Miniport->MediaSenseDisconnectCount + (Miniport->MediaSenseConnectCount << 16));
|
|
SourceBuffer = &GenericULong;
|
|
SourceLength = sizeof(ULONG);
|
|
break;
|
|
|
|
case OID_GEN_ELAPSED_TIME:
|
|
{
|
|
|
|
KeQueryTickCount(&CurrTicks);
|
|
CurrTicks.QuadPart -= Miniport->NdisStats.StartTicks.QuadPart;
|
|
CurrTicks.QuadPart = CurrTicks.QuadPart*KeQueryTimeIncrement()/(10*1000*1000);
|
|
|
|
SourceBuffer = &CurrTicks.LowPart;
|
|
SourceLength = sizeof(ULONG);
|
|
|
|
}
|
|
break;
|
|
|
|
case OID_GEN_RESET_VERIFY_PARAMETERS:
|
|
MoveMemory((PUCHAR)&ndisFlags, Buffer + NdisStatisticsHeaderSize, sizeof(ULONG));
|
|
SourceBuffer = NULL;
|
|
SourceLength = sizeof(ULONG);
|
|
|
|
ndisVerifierInitialization();
|
|
//
|
|
// when ndisFlags is set by ndis tester vs. reading it from
|
|
// registry, let it -clear- the verifier flags if necessary
|
|
// ndisVerifierInit takes care of -setting- them if necessary
|
|
//
|
|
if (!(ndisFlags & NDIS_GFLAG_INJECT_ALLOCATION_FAILURE))
|
|
ndisVerifierLevel &= ~DRIVER_VERIFIER_INJECT_ALLOCATION_FAILURES;
|
|
|
|
if (!(ndisFlags & NDIS_GFLAG_SPECIAL_POOL_ALLOCATION))
|
|
ndisVerifierLevel &= ~DRIVER_VERIFIER_SPECIAL_POOLING;
|
|
|
|
Request.DATA.SET_INFORMATION.BytesRead = sizeof(ULONG);
|
|
break;
|
|
|
|
case OID_GEN_MINIPORT_INFO:
|
|
{
|
|
InfoFlags = Miniport->InfoFlags;
|
|
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_64BITS_DMA))
|
|
InfoFlags |= NDIS_MINIPORT_64BITS_DMA;
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
|
|
InfoFlags |= NDIS_MINIPORT_IS_CO;
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING))
|
|
InfoFlags |= NDIS_MINIPORT_REQUIRES_MEDIA_POLLING;
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SUPPORTS_MEDIA_SENSE))
|
|
InfoFlags |= NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE;
|
|
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_SUPPORTED))
|
|
InfoFlags |= NDIS_MINIPORT_PM_SUPPORTED;
|
|
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HIDDEN))
|
|
InfoFlags |= NDIS_MINIPORT_HIDDEN;
|
|
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SWENUM))
|
|
InfoFlags |= NDIS_MINIPORT_SWENUM;
|
|
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HARDWARE_DEVICE))
|
|
InfoFlags |= NDIS_MINIPORT_HARDWARE_DEVICE;
|
|
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_NDIS_WDM_DRIVER))
|
|
InfoFlags |= NDIS_MINIPORT_WDM_DRIVER;
|
|
|
|
if (Miniport->DriverHandle->MiniportCharacteristics.CancelSendPacketsHandler)
|
|
{
|
|
InfoFlags |= NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS;
|
|
}
|
|
|
|
SourceBuffer = &InfoFlags;
|
|
SourceLength = sizeof(ULONG);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// not an "internal" OID
|
|
//
|
|
if (!ndisValidOid(OpenContext, Oid))
|
|
{
|
|
//
|
|
// not a valid OID either
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Transform OID based on media-type
|
|
//
|
|
if (Oid == OID_802_3_CURRENT_ADDRESS)
|
|
{
|
|
switch (Miniport->MediaType)
|
|
{
|
|
case NdisMedium802_5:
|
|
Oid = OID_802_5_CURRENT_ADDRESS;
|
|
break;
|
|
case NdisMediumFddi:
|
|
Oid = OID_FDDI_LONG_CURRENT_ADDR;
|
|
break;
|
|
case NdisMediumAtm:
|
|
Oid = OID_ATM_HW_CURRENT_ADDRESS;
|
|
break;
|
|
case NdisMediumWan:
|
|
Oid = OID_WAN_CURRENT_ADDRESS;
|
|
break;
|
|
#if ARCNET
|
|
case NdisMediumArcnetRaw:
|
|
Oid = OID_ARCNET_CURRENT_ADDRESS;
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
else if (Oid == OID_802_3_PERMANENT_ADDRESS)
|
|
{
|
|
switch (Miniport->MediaType)
|
|
{
|
|
case NdisMedium802_5:
|
|
Oid = OID_802_5_PERMANENT_ADDRESS;
|
|
break;
|
|
case NdisMediumFddi:
|
|
Oid = OID_FDDI_LONG_PERMANENT_ADDR;
|
|
break;
|
|
case NdisMediumAtm:
|
|
Oid = OID_ATM_HW_CURRENT_ADDRESS;
|
|
break;
|
|
case NdisMediumWan:
|
|
Oid = OID_WAN_PERMANENT_ADDRESS;
|
|
break;
|
|
#if ARCNET
|
|
case NdisMediumArcnetRaw:
|
|
Oid = OID_ARCNET_PERMANENT_ADDRESS;
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SYSTEM_SLEEPING))
|
|
{
|
|
//1 eventually we need to find a way to check for the length ourselves
|
|
|
|
if (AlignOutput)
|
|
{
|
|
SourceBuffer = Buffer + NdisStatisticsHeaderSize;
|
|
}
|
|
else
|
|
{
|
|
SourceBuffer = DoubleBuffer;
|
|
}
|
|
|
|
|
|
NdisStatus = ndisQueryDeviceOid(OpenContext,
|
|
&Request,
|
|
Oid,
|
|
SourceBuffer,
|
|
BufferLengthRemained - NdisStatisticsHeaderSize);
|
|
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
SourceLength = Request.DATA.QUERY_INFORMATION.BytesWritten;
|
|
}
|
|
else
|
|
{
|
|
SourceLength = 0;
|
|
}
|
|
|
|
if (AlignOutput)
|
|
{
|
|
SourceBuffer = NULL; // to avoid the copy since the data is already at the right place
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NdisStatus = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
if ((SourceLength > 0) && (SourceBuffer != NULL))
|
|
{
|
|
MoveMemory(Buffer + NdisStatisticsHeaderSize, SourceBuffer, SourceLength);
|
|
}
|
|
|
|
//
|
|
// Advance our pointers.
|
|
//
|
|
|
|
BytesWrittenThisOid = SourceLength + NdisStatisticsHeaderSize;
|
|
|
|
if (AlignOutput)
|
|
{
|
|
//
|
|
// activate for longhorn
|
|
//
|
|
|
|
ASSERT(FALSE);
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
|
|
|
|
#if 0
|
|
//
|
|
// Create the equivalent of an NDIS_STATISTICS_VALUE element for this OID value
|
|
// (the data itself was already written in the right place.
|
|
//
|
|
StatisticsValueEx = (PNDIS_STATISTICS_VALUE_EX)Buffer;
|
|
StatisticsValueEx->Oid = OidArray[CurrentOid]; // Not Oid since we map some
|
|
StatisticsValueEx->DataLength = SourceLength;
|
|
|
|
BytesWrittenAlignedThisOid = ALIGN_UP_MAX_NATURAL_ALIGNMENT_LENGTH(BytesWrittenThisOid);
|
|
if ((BufferLengthRemained - BytesWrittenAlignedThisOid) < (ULONG)(NdisStatisticsHeaderSize + sizeof(ULONG)))
|
|
{
|
|
//
|
|
// this is the last statistics we can report.
|
|
// report the Length without any padding
|
|
//
|
|
StatisticsValueEx->Length = BytesWrittenThisOid;
|
|
BufferLengthRemained -= BytesWrittenThisOid;
|
|
Buffer += BytesWrittenThisOid;
|
|
BytesWritten += BytesWrittenThisOid;
|
|
}
|
|
else
|
|
{
|
|
StatisticsValueEx->Length = BytesWrittenAlignedThisOid;
|
|
BufferLengthRemained -= BytesWrittenAlignedThisOid;
|
|
Buffer += BytesWrittenAlignedThisOid;
|
|
BytesWritten += BytesWrittenAlignedThisOid;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create the equivalent of an NDIS_STATISTICS_VALUE element for this OID value
|
|
// (the data itself was already written in the right place.
|
|
//
|
|
StatisticsValue = (PNDIS_STATISTICS_VALUE)Buffer;
|
|
StatisticsValue->Oid = OidArray[CurrentOid]; // Not Oid since we map some
|
|
StatisticsValue->DataLength = SourceLength;
|
|
BufferLengthRemained -= BytesWrittenThisOid;
|
|
Buffer += BytesWrittenThisOid;
|
|
BytesWritten += BytesWrittenThisOid;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
*pBytesWritten = BytesWritten;
|
|
|
|
if (NdisStatus == NDIS_STATUS_NOT_SUPPORTED)
|
|
{
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (DoubleBuffer)
|
|
{
|
|
FREE_POOL(DoubleBuffer);
|
|
}
|
|
|
|
DBGPRINT_RAW(DBG_COMP_REQUEST, DBG_LEVEL_INFO,
|
|
("<==ndisQueryStatisticsOids\n"));
|
|
|
|
return NdisStatus;
|
|
}
|
|
|