From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/ndis/ndis30/wrapper.c | 17480 +++++++++++++++++++++++++++++++++++ 1 file changed, 17480 insertions(+) create mode 100644 private/ntos/ndis/ndis30/wrapper.c (limited to 'private/ntos/ndis/ndis30/wrapper.c') diff --git a/private/ntos/ndis/ndis30/wrapper.c b/private/ntos/ndis/ndis30/wrapper.c new file mode 100644 index 000000000..9373647c4 --- /dev/null +++ b/private/ntos/ndis/ndis30/wrapper.c @@ -0,0 +1,17480 @@ +/*++ +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + wrapper.c + +Abstract: + + NDIS wrapper functions + +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 + +--*/ + + +#include +#pragma hdrstop + +#include + +// +// The following are counters used for debugging +// + +#if NDISDBG +BOOLEAN NdisChkErrorFlag=TRUE; // parameter checking on +int NdisMsgLevel=TRACE_ALL; // no trace +#endif + +PNDIS_MAC_BLOCK NdisMacList = (PNDIS_MAC_BLOCK)NULL; +NDIS_SPIN_LOCK NdisMacListLock = {0}; + +BOOLEAN NdisInitialInitNeeded = TRUE; +BOOLEAN NdisUpOnlyEventLogged = FALSE; + +// +// Global variables for tracking memory allocated for shared memory +// +ERESOURCE SharedMemoryResource = {0}; + +// +// Global variables for tracking on NT 3.1 protocols that do not +// use any of the filter packages. +// +PNDIS_OPEN_BLOCK GlobalOpenList = NULL; +NDIS_SPIN_LOCK GlobalOpenListLock = {0}; + +// +// Debug variable for filter packages +// +#if DBG +BOOLEAN NdisCheckBadDrivers = FALSE; + +extern NDIS_SPIN_LOCK PacketLogSpinLock; +#endif + +// +// Arcnet specific stuff +// +#define WRAPPER_ARC_BUFFERS 8 +#define WRAPPER_ARC_HEADER_SIZE 4 + +// +// Define constants used internally to identify regular opens from +// query global statistics ones. +// + +#define NDIS_OPEN_INTERNAL 1 +#define NDIS_OPEN_QUERY_STATISTICS 2 + +// +// This is the structure pointed to by the FsContext of an +// open used for query statistics. +// +// NOTE: THIS STRUCTURE MUST, MUST, MUST ALIGN WITH THE +// NDIS_M_USER_OPEN_CONTEXT STRUCTURE!!! +// + +typedef struct _NDIS_USER_OPEN_CONTEXT { + PDEVICE_OBJECT DeviceObject; + PNDIS_ADAPTER_BLOCK AdapterBlock; + ULONG OidCount; + PNDIS_OID OidArray; +} NDIS_USER_OPEN_CONTEXT, *PNDIS_USER_OPEN_CONTEXT; + +// +// An active query single statistic request. +// + +typedef struct _NDIS_QUERY_GLOBAL_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; +} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST; + + +// +// An active query all statistics request. +// + +typedef struct _NDIS_QUERY_ALL_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; + NDIS_STATUS NdisStatus; + KEVENT Event; +} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST; + + +// +// An temporary request used during an open. +// + +typedef struct _NDIS_QUERY_OPEN_REQUEST { + PIRP Irp; + NDIS_REQUEST Request; + NDIS_STATUS NdisStatus; + KEVENT Event; +} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST; + + +// +// Used to queue configuration parameters +// + +typedef struct _NDIS_CONFIGURATION_PARAMETER_QUEUE { + struct _NDIS_CONFIGURATION_PARAMETER_QUEUE* Next; + NDIS_CONFIGURATION_PARAMETER Parameter; +} NDIS_CONFIGURATION_PARAMETER_QUEUE, *PNDIS_CONFIGURATION_PARAMETER_QUEUE; + +// +// Configuration Handle +// + +typedef struct _NDIS_CONFIGURATION_HANDLE { + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable; + PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterList; +} NDIS_CONFIGURATION_HANDLE, *PNDIS_CONFIGURATION_HANDLE; + +// +// This is used during addadapter/miniportinitialize so that when the +// driver calls any NdisImmediatexxx routines we can access its driverobj. +// +typedef struct _NDIS_WRAPPER_CONFIGURATION_HANDLE +{ + RTL_QUERY_REGISTRY_TABLE ParametersQueryTable[4]; + PDRIVER_OBJECT DriverObject; +} + NDIS_WRAPPER_CONFIGURATION_HANDLE, + *PNDIS_WRAPPER_CONFIGURATION_HANDLE; + +// +// Describes an open NDIS file +// + +typedef struct _NDIS_FILE_DESCRIPTOR { + PVOID Data; + NDIS_SPIN_LOCK Lock; + BOOLEAN Mapped; +} NDIS_FILE_DESCRIPTOR, *PNDIS_FILE_DESCRIPTOR; + +// +// IRP handlers established on behalf of NDIS devices by +// the wrapper. +// + +NTSTATUS +NdisCreateIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisDeviceControlIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisCloseIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +NTSTATUS +NdisSuccessIrpHandler( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + + +NTSTATUS +NdisQueryOidList( + PNDIS_USER_OPEN_CONTEXT OpenContext, + PIRP Irp + ); + +NTSTATUS +NdisMQueryOidList( + PNDIS_M_USER_OPEN_CONTEXT OpenContext, + PIRP Irp + ); + +VOID +NdisLastCountRemovedFunction( + IN struct _KDPC *Dpc, + IN PVOID DeferredContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ); + + +BOOLEAN +NdisQueueOpenOnProtocol( + IN PNDIS_OPEN_BLOCK OpenP, + IN PNDIS_PROTOCOL_BLOCK ProtP + ); + +NDIS_STATUS +MiniportAdjustMaximumLookahead( + IN PNDIS_MINIPORT_BLOCK Miniport + ); + +BOOLEAN +NdisMKillOpen( + PNDIS_OPEN_BLOCK OldOpenP + ); + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NDIS_STATUS +NdisMacReceiveHandler( + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_HANDLE MacReceiveContext, + IN PVOID HeaderBuffer, + IN UINT HeaderBufferSize, + IN PVOID LookaheadBuffer, + IN UINT LookaheadBufferSize, + IN UINT PacketSize + ); + +VOID +NdisMacReceiveCompleteHandler( + IN NDIS_HANDLE NdisBindingContext + ); + +PNDIS_OPEN_BLOCK +GetOpenBlockFromProtocolBindingContext( + IN NDIS_HANDLE ProtocolBindingContext + ); + +NTSTATUS +NdisShutdown( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ); + +VOID +NdisUnload( + IN PDRIVER_OBJECT DriverObject + ); + +BOOLEAN +NdisIsr( + IN PKINTERRUPT Interrupt, + IN PVOID Context + ); + +VOID +NdisDpc( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +VOID +NdisOpenConfiguration( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE ConfigurationHandle, + IN NDIS_HANDLE WrapperConfigurationContext + ); + +NTSTATUS +WrapperSaveParameters( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +VOID +NdisReadNetworkAddress( + OUT PNDIS_STATUS Status, + OUT PVOID * NetworkAddress, + OUT PUINT NetworkAddressLength, + IN NDIS_HANDLE ConfigurationHandle + ); + +VOID +NdisReadEisaSlotInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData + ); + +VOID +NdisReadEisaSlotInformationEx( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData, + OUT PUINT NumberOfFunctions + ); + +VOID +NdisReadMcaPosInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT ChannelNumber, + OUT PNDIS_MCA_POS_DATA McaData + ); + +NDIS_STATUS +NdisCallDriverAddAdapter( + IN PNDIS_MAC_BLOCK NewMacP + ); + +NDIS_STATUS +NdisMWanSend( + IN NDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE NdisLinkHandle, + IN PVOID Packet + ); + + +CCHAR NdisMacAdapterDpcTargetProcessor = -1; + +// +// Routines for dealing with making the MAC specific routines pagable +// + +NDIS_SPIN_LOCK NdisMacReferenceLock = {0}; +KEVENT NdisMacPagedInEvent = {0}; +ULONG NdisMacReferenceCount = 0; +PVOID NdisMacImageHandle = {0}; + +VOID +NdisMacInitializePackage(VOID) +{ + // + // Allocate the spin lock + // + NdisAllocateSpinLock(&NdisMacReferenceLock); + + // + // Initialize the "in page" event. + // + KeInitializeEvent( + &NdisMacPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +NdisMacReferencePackage(VOID) +{ + + // + // Grab the spin lock + // + ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock); + + // + // Increment the reference count + // + NdisMacReferenceCount++; + + if (NdisMacReferenceCount == 1) { + + // + // We are the first reference. Page everything in. + // + + // + // Clear the event + // + KeResetEvent( + &NdisMacPagedInEvent + ); + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&NdisMacReferenceLock); + + // + // Page in all the functions + // + NdisMacImageHandle = MmLockPagableCodeSection(NdisIsr); + + // + // Signal to everyone to go + // + KeSetEvent( + &NdisMacPagedInEvent, + 0L, + FALSE + ); + + } else { + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&NdisMacReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &NdisMacPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +NdisMacDereferencePackage(VOID) +{ + + // + // Get the spin lock + // + ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock); + + NdisMacReferenceCount--; + + if (NdisMacReferenceCount == 0) { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&NdisMacReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(NdisMacImageHandle); + + } else { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&NdisMacReferenceLock); + + } + +} + + + +// +// Routines for dealing with making the initialization routines pagable +// + +NDIS_SPIN_LOCK NdisInitReferenceLock = {0}; +KEVENT NdisInitPagedInEvent = {0}; +ULONG NdisInitReferenceCount = 0; +PVOID NdisInitImageHandle = {0}; + +VOID +NdisInitInitializePackage(VOID) +{ + // + // Allocate the spin lock + // + NdisAllocateSpinLock(&NdisInitReferenceLock); + + // + // Initialize the "in page" event. + // + KeInitializeEvent( + &NdisInitPagedInEvent, + NotificationEvent, + FALSE + ); +} + +VOID +NdisInitReferencePackage(VOID) +{ + + // + // Grab the spin lock + // + ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock); + + // + // Increment the reference count + // + NdisInitReferenceCount++; + + if (NdisInitReferenceCount == 1) { + + // + // We are the first reference. Page everything in. + // + + // + // Clear the event + // + KeResetEvent( + &NdisInitPagedInEvent + ); + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&NdisInitReferenceLock); + + // + // Page in all the functions + // + NdisInitImageHandle = MmLockPagableCodeSection(NdisReadConfiguration); + + // + // Signal to everyone to go + // + KeSetEvent( + &NdisInitPagedInEvent, + 0L, + FALSE + ); + + } else { + + // + // Set the spin lock free + // + RELEASE_SPIN_LOCK(&NdisInitReferenceLock); + + // + // Wait for everything to be paged in + // + KeWaitForSingleObject( + &NdisInitPagedInEvent, + Executive, + KernelMode, + TRUE, + NULL + ); + + } + +} + +VOID +NdisInitDereferencePackage(VOID) +{ + + // + // Get the spin lock + // + ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock); + + NdisInitReferenceCount--; + + if (NdisInitReferenceCount == 0) { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&NdisInitReferenceLock); + + // + // Page out all the functions + // + MmUnlockPagableImageSection(NdisInitImageHandle); + + } else { + + // + // Let next one in + // + RELEASE_SPIN_LOCK(&NdisInitReferenceLock); + + } +} + + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGENDSI, NdisPciAssignResources) +#pragma alloc_text(PAGENDSI, NdisReadMcaPosInformation) +#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformationEx) +#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformation) +#pragma alloc_text(PAGENDSI, NdisCallDriverAddAdapter) +#pragma alloc_text(PAGENDSW, NdisDereferenceMac) +#pragma alloc_text(PAGENDSW, NdisDereferenceAdapter) +#pragma alloc_text(PAGENDSW, NdisKillAdapter) +#pragma alloc_text(PAGENDSW, NdisDeQueueAdapterOnMac) +#pragma alloc_text(PAGENDSW, NdisQueueAdapterOnMac) +#pragma alloc_text(PAGENDSW, NdisKillOpen) +#pragma alloc_text(PAGENDSW, NdisKillOpenAndNotifyProtocol) +#pragma alloc_text(PAGENDSW, NdisCloseIrpHandler) +#pragma alloc_text(PAGENDSW, NdisCompleteQueryStatistics) +#pragma alloc_text(PAGENDSW, NdisQueryOidList) +#pragma alloc_text(PAGENDSW, NdisFinishOpen) +#pragma alloc_text(PAGENDSW, NdisCompleteCloseAdapter) +#pragma alloc_text(PAGENDSW, NdisCompleteOpenAdapter) +#pragma alloc_text(PAGENDSI, NdisRegisterAdapterShutdownHandler) +#pragma alloc_text(PAGENDSI, NdisRegisterAdapter) +#pragma alloc_text(PAGENDSI, NdisInitializeWrapper) +#pragma alloc_text(PAGENDSW, NdisMacReceiveCompleteHandler) +#pragma alloc_text(PAGENDSW, NdisMacReceiveHandler) +#pragma alloc_text(PAGENDSW, GetOpenBlockFromProtocolBindingContext) +#pragma alloc_text(PAGENDSI, NdisAllocateDmaChannel) +#pragma alloc_text(PAGENDSW, NdisShutdown) +#pragma alloc_text(PAGENDSW, NdisUnload) +#pragma alloc_text(PAGENDSI, NdisInitializeInterrupt) +#pragma alloc_text(PAGENDSW, NdisDpc) +#pragma alloc_text(PAGENDSW, NdisIsr) +#pragma alloc_text(PAGENDSI, NdisMapIoSpace) +#pragma alloc_text(PAGENDSI, NdisReadNetworkAddress) +#pragma alloc_text(PAGENDSI, NdisCloseConfiguration) +#pragma alloc_text(PAGENDSI, NdisReadConfiguration) +#pragma alloc_text(PAGENDSI, WrapperSaveParameters) +#pragma alloc_text(PAGENDSI, NdisOpenConfiguration) +#pragma alloc_text(PAGENDSI, NdisOverrideBusNumber) +#pragma alloc_text(INIT, DriverEntry) + +#endif + + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + +#if defined(_ALPHA_) + +typedef struct _NDIS_LOOKAHEAD_ELEMENT { + + ULONG Length; + struct _NDIS_LOOKAHEAD_ELEMENT *Next; + +} NDIS_LOOKAHEAD_ELEMENT, *PNDIS_LOOKAHEAD_ELEMENT; + +NDIS_SPIN_LOCK NdisLookaheadBufferLock = {0}; +ULONG NdisLookaheadBufferLength = 0; +PNDIS_LOOKAHEAD_ELEMENT NdisLookaheadBufferList = NULL; + +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + Temporary entry point needed to initialize the NDIS wrapper driver. + +Arguments: + + DriverObject - Pointer to the driver object created by the system. + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + UNREFERENCED_PARAMETER(RegistryPath); + + return STATUS_SUCCESS; + +} // DriverEntry + + +NDIS_STATUS +NdisInitialInit( + IN PDRIVER_OBJECT Driver OPTIONAL + ) +/*++ + +Routine Description: + + This routine is used for all one time initialization of NDIS variables. + It seems that DriverEntry is *not* called for ndis.sys due to its type. + +Arguments: + + Driver - Optional pointer to an NT driver object. Used to log an error, + if necessary. + +Return Value: + + NTSTATUS - Status of initialization. Currently, this routine can only + fail if built for UP and loaded on MP. + +--*/ + +{ + Driver; + + if (NdisInitialInitNeeded) { + +#if defined(UP_DRIVER) + // + // If built for UP, ensure that this is a UP system. + // + + if (*KeNumberProcessors != 1) { + + if (ARGUMENT_PRESENT(Driver) && !NdisUpOnlyEventLogged) { + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + + errorLogEntry = IoAllocateErrorLogEntry( Driver, sizeof(IO_ERROR_LOG_PACKET) ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_UP_DRIVER_ON_MP; + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + errorLogEntry->NumberOfStrings = 0; + + IoWriteErrorLogEntry(errorLogEntry); + + NdisUpOnlyEventLogged = TRUE; + } + + } + + return NDIS_STATUS_BAD_VERSION; //!!! better status? + } + +#endif // defined(UP_DRIVER) + + NdisInitialInitNeeded = FALSE; + NdisAllocateSpinLock(&NdisMacListLock); + + ArcInitializePackage(); + EthInitializePackage(); + FddiInitializePackage(); + TrInitializePackage(); + MiniportInitializePackage(); + NdisInitInitializePackage(); + NdisMacInitializePackage(); + +#if defined(_ALPHA_) + NdisAllocateSpinLock(&NdisLookaheadBufferLock); +#endif + + ExInitializeResource(&SharedMemoryResource); + + NdisAllocateSpinLock(&GlobalOpenListLock); + +#if DBG + NdisAllocateSpinLock(&PacketLogSpinLock); +#endif + } + + return NDIS_STATUS_SUCCESS; +} + + +// +// Configuration Requests +// + +VOID +NdisOpenConfiguration( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE ConfigurationHandle, + IN NDIS_HANDLE WrapperConfigurationContext + ) +/*++ + +Routine Description: + + This routine is used to open the parameter subkey of the + adapter registry tree. + +Arguments: + + Status - Returns the status of the request. + + ConfigurationHandle - Returns a handle which is used in calls to + NdisReadConfiguration and NdisCloseConfiguration. + + WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE + that is set up for this driver's parameters. + +Return Value: + + None. + +--*/ + +{ + // + // Handle to be returned + // + PNDIS_CONFIGURATION_HANDLE HandleToReturn; + + + // + // Allocate the configuration handle + // + + *Status = NdisAllocateMemory( + (PVOID*) &HandleToReturn, + sizeof(NDIS_CONFIGURATION_HANDLE), + 0, + HighestAcceptableMax); + + if (*Status != NDIS_STATUS_SUCCESS) { + return; + } + + HandleToReturn->KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + HandleToReturn->ParameterList = NULL; + *ConfigurationHandle = (NDIS_HANDLE) HandleToReturn; + + return; +} + + +NTSTATUS +WrapperSaveParameters( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) + +/*++ + +Routine Description: + + This routine is a callback routine for RtlQueryRegistryValues + It is called with the value for a specified parameter. It allocates + memory to hold the data and copies it over. + +Arguments: + + ValueName - The name of the value (ignored). + + ValueType - The type of the value. + + ValueData - The null-terminated data for the value. + + ValueLength - The length of ValueData. + + Context - Points to the head of the parameter chain. + + EntryContext - A pointer to + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + NDIS_STATUS Status; + + // + // Obtain the actual configuration handle structure + // + + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE)Context; + + // + // Where the user wants a pointer returned to the data. + // + + PNDIS_CONFIGURATION_PARAMETER *ParameterValue = + (PNDIS_CONFIGURATION_PARAMETER *)EntryContext; + + // + // Use this to link parameters allocated to this open + // + + PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode; + + + + // + // Allocate our parameter node + // + + Status = NdisAllocateMemory( + (PVOID*)&ParameterNode, + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), + 0, + HighestAcceptableMax); + + if (Status != NDIS_STATUS_SUCCESS) { + return (NTSTATUS)Status; + } + + + *ParameterValue = &ParameterNode->Parameter; + + // + // Map registry datatypes to ndis data types + // + + if (ValueType == REG_DWORD) { + + // + // The registry says that the data is in a dword boundary. + // + + (*ParameterValue)->ParameterType = NdisParameterInteger; + (*ParameterValue)->ParameterData.IntegerData = + *((PULONG) ValueData); + + } else if ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ)) { + + (*ParameterValue)->ParameterType = + (ValueType == REG_SZ) ? NdisParameterString : NdisParameterMultiString; + + (*ParameterValue)->ParameterData.StringData.Buffer = + ExAllocatePoolWithTag(NonPagedPool, ValueLength, ' DN'); + + if (((*ParameterValue)->ParameterData.StringData.Buffer) == NULL) { + NdisFreeMemory (ParameterNode, sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), 0); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory ((*ParameterValue)->ParameterData.StringData.Buffer, + ValueData, ValueLength); + (*ParameterValue)->ParameterData.StringData.Length = (USHORT)ValueLength; + (*ParameterValue)->ParameterData.StringData.MaximumLength = (USHORT)ValueLength; + + // + // Special fix; if a string ends in a NULL and that is included + // in the length, remove it. + // + + if (ValueType == REG_SZ) { + if ((((PUCHAR)ValueData)[ValueLength-1] == 0) && + (((PUCHAR)ValueData)[ValueLength-2] == 0)) { + (*ParameterValue)->ParameterData.StringData.Length -= 2; + } + } + + } else { + + NdisFreeMemory( + ParameterNode, + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), + 0 + ); + + return STATUS_OBJECT_NAME_NOT_FOUND; + + } + + + // + // Queue this parameter node + // + + ParameterNode->Next = NdisConfigHandle->ParameterList; + NdisConfigHandle->ParameterList = ParameterNode; + + return STATUS_SUCCESS; + +} + + +VOID +NdisReadConfiguration( + OUT PNDIS_STATUS Status, + OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING Keyword, + IN NDIS_PARAMETER_TYPE ParameterType + ) +/*++ + +Routine Description: + + This routine is used to read the parameter for a configuration + keyword from the configuration database. + +Arguments: + + Status - Returns the status of the request. + + ParameterValue - Returns the value for this keyword. + + ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points + to the parameter subkey. + + Keyword - The keyword to search for. + + ParameterType - Ignored on NT, specifies the type of the value. + +Return Value: + + None. + +--*/ +{ + + // + // Status of our requests + // + NTSTATUS RegistryStatus; + + // + // There are some built-in parameters which can always be + // read, even if not present in the registry. This is the + // number of them. + // + +#define BUILT_IN_COUNT 2 + + // + // The names of the built-in parameters. + // + + static NDIS_STRING BuiltInStrings[BUILT_IN_COUNT] = + { NDIS_STRING_CONST ("Environment"), + NDIS_STRING_CONST ("ProcessorType") }; + + // + // The values to return for the built-in parameters. + // + + static NDIS_CONFIGURATION_PARAMETER BuiltInParameters[BUILT_IN_COUNT] = + { { NdisParameterInteger, NdisEnvironmentWindowsNt }, + { NdisParameterInteger, +#if defined(_M_IX86) + NdisProcessorX86 +#elif defined(_M_MRX000) + NdisProcessorMips +#elif defined(_ALPHA_) + NdisProcessorAlpha +#else + NdisProcessorPpc +#endif + } }; + + + // + // Holds a null-terminated version of the keyword. + // + PWSTR KeywordBuffer; + + // + // index variable + // + UINT i; + + // + // Obtain the actual configuration handle structure + // + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + + + // + // First check if this is one of the built-in parameters. + // + + for (i = 0; i < BUILT_IN_COUNT; i++) { + if (RtlEqualUnicodeString(Keyword, &BuiltInStrings[i], TRUE)) { + *Status = NDIS_STATUS_SUCCESS; + *ParameterValue = &BuiltInParameters[i]; + return; + } + } + + + // + // Allocate room for a null-terminated version of the keyword + // + + KeywordBuffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + Keyword->Length + sizeof(WCHAR), + ' DN'); + if (KeywordBuffer == NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length); + *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0'; + + + // + // Finish initializing the table for this query. + // + + NdisConfigHandle->KeyQueryTable[1].Name = KeywordBuffer; + NdisConfigHandle->KeyQueryTable[1].EntryContext = ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfigHandle. + // + + RegistryStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfigHandle->KeyQueryTable[3].Name, + NdisConfigHandle->KeyQueryTable, + NdisConfigHandle, // context + NULL); + + + ExFreePool (KeywordBuffer); // no longer needed + + if (!NT_SUCCESS(RegistryStatus)) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + *Status = NDIS_STATUS_SUCCESS; + return; + +} + + +VOID +NdisWriteConfiguration( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE ConfigurationHandle, + IN PNDIS_STRING Keyword, + PNDIS_CONFIGURATION_PARAMETER ParameterValue + ) +/*++ + +Routine Description: + + This routine is used to write a parameter to the configuration database. + +Arguments: + + Status - Returns the status of the request. + + ConfigurationHandle - Handle passed to the driver's AddAdapter routine. + + Keyword - The keyword to set. + + ParameterValue - Specifies the new value for this keyword. + +Return Value: + + None. + +--*/ +{ + + // + // Status of our requests + // + NTSTATUS RegistryStatus; + + // + // The ConfigurationHandle is really a pointer to a registry query table. + // + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + // + // The name of the Parameters key. + // + PWSTR Parameters = L"\\Parameters"; + ULONG ParametersLength = (wcslen(Parameters) + 1) * sizeof(WCHAR); + + ULONG DriverLength = wcslen(NdisConfigHandle->KeyQueryTable[3].Name) * sizeof(WCHAR); + + // + // Holds a null-terminated version of the name of the Parameters key. + // + PWSTR KeyNameBuffer; + + // + // Holds a null-terminated version of the keyword. + // + PWSTR KeywordBuffer; + + // + // Variables describing the parameter value. + // + PVOID ValueData; + ULONG ValueLength; + ULONG ValueType; + + // + // Get the value data. + // + if ( ParameterValue->ParameterType == NdisParameterInteger ) { + ValueData = &ParameterValue->ParameterData.IntegerData; + ValueLength = sizeof(ParameterValue->ParameterData.IntegerData); + ValueType = REG_DWORD; + } else if ( (ParameterValue->ParameterType == NdisParameterString) || + (ParameterValue->ParameterType == NdisParameterMultiString) ) { + ValueData = ParameterValue->ParameterData.StringData.Buffer; + ValueLength = ParameterValue->ParameterData.StringData.Length; + ValueType = ParameterValue->ParameterType == NdisParameterString ? + REG_SZ : REG_MULTI_SZ; + } else { + *Status = NDIS_STATUS_NOT_SUPPORTED; + return; + } + + // + // Allocate room for the Parameters key name (e.g., L"Elnk3\Parameters"). + // + + KeyNameBuffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + DriverLength + ParametersLength, + ' DN'); + if (KeyNameBuffer == NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + RtlCopyMemory (KeyNameBuffer, NdisConfigHandle->KeyQueryTable[3].Name, DriverLength); + RtlCopyMemory ((PCHAR)KeyNameBuffer + DriverLength, Parameters, ParametersLength); + + // + // Allocate room for a null-terminated version of the keyword + // + + KeywordBuffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + Keyword->Length + sizeof(WCHAR), + ' DN'); + if (KeywordBuffer == NULL) { + ExFreePool (KeyNameBuffer); + *Status = NDIS_STATUS_RESOURCES; + return; + } + + RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length); + *(PWCHAR)((PUCHAR)KeywordBuffer+Keyword->Length) = (WCHAR)L'\0'; + + // + // Write the value to the registry. + // + + RegistryStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + KeyNameBuffer, + KeywordBuffer, + ValueType, + ValueData, + ValueLength + ); + + ExFreePool (KeywordBuffer); // no longer needed + ExFreePool (KeyNameBuffer); + + if (!NT_SUCCESS(RegistryStatus)) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + *Status = NDIS_STATUS_SUCCESS; + return; + +} + + + +VOID +NdisCloseConfiguration( + IN NDIS_HANDLE ConfigurationHandle + ) +/*++ + +Routine Description: + + This routine is used to close a configuration database opened by + NdisOpenConfiguration. + +Arguments: + + ConfigurationHandle - Handle returned by NdisOpenConfiguration. + +Return Value: + + None. + +--*/ +{ + // + // Obtain the actual configuration handle structure + // + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + // + // Pointer to a parameter node + // + PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode; + + // + // deallocate the parameter nodes + // + + ParameterNode = NdisConfigHandle->ParameterList; + + while (ParameterNode != NULL) { + + NdisConfigHandle->ParameterList = ParameterNode->Next; + + if ((ParameterNode->Parameter.ParameterType == NdisParameterString) || + (ParameterNode->Parameter.ParameterType == NdisParameterMultiString)) { + ExFreePool (ParameterNode->Parameter.ParameterData.StringData.Buffer); + } + + NdisFreeMemory( + ParameterNode, + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), + 0 + ); + + ParameterNode = NdisConfigHandle->ParameterList; + } + + NdisFreeMemory( + ConfigurationHandle, + sizeof(NDIS_CONFIGURATION_HANDLE), + 0); +} + + + +VOID +NdisReadNetworkAddress( + OUT PNDIS_STATUS Status, + OUT PVOID * NetworkAddress, + OUT PUINT NetworkAddressLength, + IN NDIS_HANDLE ConfigurationHandle + ) + +/*++ + +Routine Description: + + This routine is used to read the "NetworkAddress" parameter + from the configuration database. It reads the value as a + string separated by hyphens, then converts it to a binary + array and stores the result. + +Arguments: + + Status - Returns the status of the request. + + NetworkAddress - Returns a pointer to the address. + + NetworkAddressLength - Returns the length of the address. + + ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points + to the parameter subkey. + +Return Value: + + None. + +--*/ + +{ + // + // Convert the handle to its real value + // + + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + // + // Variables used in reading the data from the registry + // + + NTSTATUS NtStatus; + PWSTR NetworkAddressString = L"NetworkAddress"; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + + // + // Variables used in converting the address + // + + UCHAR ConvertArray[3]; + PWSTR CurrentReadLoc; + PWSTR AddressEnd; + PUCHAR CurrentWriteLoc; + UINT TotalBytesRead; + ULONG TempUlong; + ULONG AddressLength; + + + // + // Finish initializing the table for this query. + // + + NdisConfigHandle->KeyQueryTable[1].Name = NetworkAddressString; + NdisConfigHandle->KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfigHandle. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfigHandle->KeyQueryTable[3].Name, + NdisConfigHandle->KeyQueryTable, + NdisConfigHandle, // context + NULL); + + if (NtStatus != NDIS_STATUS_SUCCESS) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + if (ParameterValue->ParameterType != NdisParameterString) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + + // + // Now convert the address to binary (we do this + // in-place, since this allows us to use the memory + // already allocated which is automatically freed + // by NdisCloseConfiguration). + // + + ConvertArray[2] = '\0'; + CurrentReadLoc = (PWSTR)ParameterValue->ParameterData.StringData.Buffer; + CurrentWriteLoc = (PUCHAR)CurrentReadLoc; + TotalBytesRead = ParameterValue->ParameterData.StringData.Length; + AddressEnd = CurrentReadLoc + (TotalBytesRead / sizeof(WCHAR)); + AddressLength = 0; + + while ((CurrentReadLoc+2) <= AddressEnd) { + + // + // Copy the current two-character value into ConvertArray + // + + ConvertArray[0] = (UCHAR)(*(CurrentReadLoc++)); + ConvertArray[1] = (UCHAR)(*(CurrentReadLoc++)); + + // + // Convert it to a Ulong and update + // + + NtStatus = RtlCharToInteger ( + ConvertArray, + 16, + &TempUlong); + + if (!NT_SUCCESS(NtStatus)) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + *(CurrentWriteLoc++) = (UCHAR)TempUlong; + ++AddressLength; + + // + // If the next character is a hyphen, skip it. + // + + if (CurrentReadLoc < AddressEnd) { + if (*CurrentReadLoc == (WCHAR)L'-') { + ++CurrentReadLoc; + } + } + } + + + *Status = STATUS_SUCCESS; + *NetworkAddress = ParameterValue->ParameterData.StringData.Buffer; + *NetworkAddressLength = AddressLength; + +} + + +VOID +NdisReadBindingInformation( + OUT PNDIS_STATUS Status, + OUT PNDIS_STRING * Binding, + IN NDIS_HANDLE ConfigurationHandle + ) + +/*++ + +Routine Description: + + This routine is used to read the binding information for + this adapter from the configuration database. The value + returned is a pointer to a string containing the bind + that matches the export for the current AddAdapter call. + + This function is meant for NDIS drivers that are layered + on top of other NDIS drivers. Binding would be passed to + NdisOpenAdapter as the AdapterName. + +Arguments: + + Status - Returns the status of the request. + + Binding - Returns the binding data. + + ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points + to the parameter subkey. + +Return Value: + + None. + +--*/ + +{ + + // + // Convert the handle to its real value + // + + PNDIS_CONFIGURATION_HANDLE NdisConfigHandle = + (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle; + + // + // Use this to link parameters allocated to this open + // + + PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode; + + + // + // For layered drivers, this points to the binding. For + // non-layered drivers, it is NULL. This is set up before + // the call to AddAdapter. + // + + if (NdisConfigHandle->KeyQueryTable[3].EntryContext == NULL) { + *Status = NDIS_STATUS_FAILURE; + return; + } + + + // + // Allocate our parameter node + // + + *Status = NdisAllocateMemory( + (PVOID*)&ParameterNode, + sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), + 0, + HighestAcceptableMax); + + if (*Status != NDIS_STATUS_SUCCESS) { + return; + } + + + // + // We set this to Integer because if we set it to String + // then CloseConfiguration would try to free the string, + // which we don't want. + // + + ParameterNode->Parameter.ParameterType = NdisParameterInteger; + + RtlInitUnicodeString( + &ParameterNode->Parameter.ParameterData.StringData, + NdisConfigHandle->KeyQueryTable[3].EntryContext); + + // + // Queue this parameter node + // + + ParameterNode->Next = NdisConfigHandle->ParameterList; + NdisConfigHandle->ParameterList = ParameterNode; + + *Binding = &ParameterNode->Parameter.ParameterData.StringData; + *Status = NDIS_STATUS_SUCCESS; + +} + +// +// Packet and Buffer requests +// + + +VOID +NdisAllocatePacketPool( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE PoolHandle, + IN UINT NumberOfDescriptors, + IN UINT ProtocolReservedLength + ) + +/*++ + +Routine Description: + + Initializes a packet pool. All packets are the same + size for a given pool (as determined by ProtocolReservedLength), + so a simple linked list of free packets is set up initially. + +Arguments: + + Status - Returns the final status (always NDIS_STATUS_SUCCESS). + PoolHandle - Returns a pointer to the pool. + NumberOfDescriptors - Number of packet descriptors needed. + ProtocolReservedLength - How long the ProtocolReserved field + should be for packets in this pool. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PACKET_POOL TmpPool; + PUCHAR FreeEntry; + UINT PacketLength; + UINT i; + + // + // Set up the size of packets in this pool (rounded + // up to sizeof(ULONG) for alignment). + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisAllocatePacketPool\n"); + + PacketLength = sizeof(NDIS_PACKET) - 1 + ProtocolReservedLength; + PacketLength = ((PacketLength+(sizeof(ULONG)-1)) / sizeof(ULONG)) + * sizeof(ULONG); + + // + // Allocate space needed + // + TmpPool = (PNDIS_PACKET_POOL) ExAllocatePoolWithTag( + NonPagedPool, + sizeof(NDIS_PACKET_POOL) + + PacketLength * NumberOfDescriptors - + 1, + 'ppDN' + ); + + if (TmpPool == NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + TmpPool->PacketLength = PacketLength; + + // + // First entry in free list is at beginning of pool space. + // + + TmpPool->FreeList = (PNDIS_PACKET)TmpPool->Buffer; + FreeEntry = TmpPool->Buffer; + + for (i = 1; i < NumberOfDescriptors; i++) { + + // + // Each entry is linked to the "packet" PacketLength bytes + // ahead of it, using the Private.Head field. + // + + ((PNDIS_PACKET)FreeEntry)->Private.Head = + (PNDIS_BUFFER)(FreeEntry + PacketLength); + FreeEntry += PacketLength; + } + + // + // Final free list entry. + // + + ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)NULL; + + + NdisAllocateSpinLock(&TmpPool->SpinLock); + + *Status = NDIS_STATUS_SUCCESS; + *PoolHandle = (NDIS_HANDLE)TmpPool; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisAllocatePacketPool\n"); +} + + + +VOID +NdisAllocateBufferPool( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE PoolHandle, + IN UINT NumberOfDescriptors + ) +/*++ + +Routine Description: + + Initializes a block of storage so that buffer descriptors can be + allocated. + +Arguments: + + Status - status of the request. + PoolHandle - handle that is used to specify the pool + NumberOfDescriptors - Number of buffer descriptors in the pool. + +Return Value: + + None. + +--*/ +{ + + // + // A nop for NT + // + UNREFERENCED_PARAMETER(NumberOfDescriptors); + *PoolHandle = NULL; + *Status = NDIS_STATUS_SUCCESS; + +} + +VOID +NdisFreeBufferPool( + IN NDIS_HANDLE PoolHandle + ) +/*++ + +Routine Description: + + Terminates usage of a buffer descriptor pool. + +Arguments: + + PoolHandle - handle that is used to specify the pool + +Return Value: + + None. + +--*/ +{ + UNREFERENCED_PARAMETER(PoolHandle); +} + +VOID +NdisAllocateBuffer( + OUT PNDIS_STATUS Status, + OUT PNDIS_BUFFER * Buffer, + IN NDIS_HANDLE PoolHandle, + IN PVOID VirtualAddress, + IN UINT Length + ) +/*++ + +Routine Description: + + Creates a buffer descriptor to describe a segment of virtual memory + allocated via NdisAllocateMemory (which always allocates nonpaged). + +Arguments: + + Status - Status of the request. + Buffer - Pointer to the allocated buffer descriptor. + PoolHandle - Handle that is used to specify the pool. + VirtualAddress - The virtual address of the buffer. + Length - The Length of the buffer. + +Return Value: + + None. + +--*/ +{ + + UNREFERENCED_PARAMETER(PoolHandle); + + if ((*Buffer = IoAllocateMdl( + VirtualAddress, + Length, + FALSE, + FALSE, + NULL + )) == NULL) { + + *Status = NDIS_STATUS_FAILURE; + + } else { + + MmBuildMdlForNonPagedPool(*Buffer); + (*Buffer)->Next = NULL; + *Status = NDIS_STATUS_SUCCESS; + + } + +} + + +VOID +NdisCopyBuffer( + OUT PNDIS_STATUS Status, + OUT PNDIS_BUFFER * Buffer, + IN NDIS_HANDLE PoolHandle, + IN PVOID MemoryDescriptor, + IN UINT Offset, + IN UINT Length + ) +/*++ + +Routine Description: + + Used to create a buffer descriptor given a memory descriptor. + +Arguments: + + Status - Status of the request. + Buffer - Pointer to the allocated buffer descriptor. + PoolHandle - Handle that is used to specify the pool. + MemoryDescriptor - Pointer to the descriptor of the source memory. + Offset - The Offset in the sources memory from which the copy is to + begin + Length - Number of Bytes to copy. + +Return Value: + + None. + +--*/ +{ + + PNDIS_BUFFER SourceDescriptor = (PNDIS_BUFFER)MemoryDescriptor; + PVOID BaseVa = (((PUCHAR)MmGetMdlVirtualAddress(SourceDescriptor)) + Offset); + + UNREFERENCED_PARAMETER(PoolHandle); + + if ((*Buffer = IoAllocateMdl( + BaseVa, + Length, + FALSE, + FALSE, + NULL + )) == NULL ) { + + *Status = NDIS_STATUS_FAILURE; + + } else { + + IoBuildPartialMdl( + SourceDescriptor, + *Buffer, + BaseVa, + Length); + + (*Buffer)->Next = NULL; + *Status = NDIS_STATUS_SUCCESS; + + } + +} + + +VOID +NdisAllocatePacket( + OUT PNDIS_STATUS Status, + OUT PNDIS_PACKET * Packet, + IN NDIS_HANDLE PoolHandle + ) + +/*++ + +Routine Description: + + Allocates a packet out of a packet pool. + +Arguments: + + Status - Returns the final status. + Packet - Return a pointer to the packet. + PoolHandle - The packet pool to allocate from. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PACKET_POOL TmpPool = (PNDIS_PACKET_POOL)PoolHandle; + + ACQUIRE_SPIN_LOCK(&TmpPool->SpinLock); + + + // + // See if any packets are on pool free list. + // + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisAllocatePacket\n"); + + IF_ERROR_CHK { + if (DbgIsNull(PoolHandle)) { + NdisPrint1("AllocatePacket: NULL Pool address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(PoolHandle)) { + NdisPrint1("AllocatePacket: Pool not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + if (TmpPool->FreeList == (PNDIS_PACKET)NULL) { + + // + // No, cannot satisfy request. + // + + RELEASE_SPIN_LOCK(&TmpPool->SpinLock); + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n"); + return; + } + + // + // Yes, take free packet off head of list and return it. + // + + *Packet = TmpPool->FreeList; + TmpPool->FreeList = (PNDIS_PACKET)(*Packet)->Private.Head; + RELEASE_SPIN_LOCK(&TmpPool->SpinLock); + + + // + // Clear packet elements. + // + + RtlZeroMemory((PVOID)*Packet, TmpPool->PacketLength); + (*Packet)->Private.Head = (PNDIS_BUFFER)NULL; // don't need to set Tail + (*Packet)->Private.Pool = (PNDIS_PACKET_POOL)PoolHandle; + (*Packet)->Private.Count = 0; + (*Packet)->Private.PhysicalCount = 0; + (*Packet)->Private.TotalLength = 0; + (*Packet)->Private.ValidCounts = TRUE; + + *Status = NDIS_STATUS_SUCCESS; + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n"); +} + + +VOID +NdisUnchainBufferAtFront( + IN OUT PNDIS_PACKET Packet, + OUT PNDIS_BUFFER * Buffer + ) + +/*++ + +Routine Description: + + Takes a buffer off the front of a packet. + +Arguments: + + Packet - The packet to be modified. + Buffer - Returns the packet on the front, or NULL. + +Return Value: + + None. + +--*/ + +{ + *Buffer = Packet->Private.Head; + + // + // If packet is not empty, remove head buffer. + // + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtFront\n"); + + IF_ERROR_CHK { + if (DbgIsNull(Packet)) { + NdisPrint1("UnchainBufferAtFront: Null Packet Pointer\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Packet)) { + NdisPrint1("UnchainBufferAtFront: Packet not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (!DbgIsPacket(Packet)) { + NdisPrint1("UnchainBufferAtFront: Illegal Packet Size\n"); + DbgBreakPoint(); + } + } + + if (*Buffer != (PNDIS_BUFFER)NULL) { + Packet->Private.Head = (*Buffer)->Next; // may be NULL + (*Buffer)->Next = (PNDIS_BUFFER)NULL; + Packet->Private.ValidCounts = FALSE; + } + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtFront\n"); +} + +VOID +NdisUnchainBufferAtBack( + IN OUT PNDIS_PACKET Packet, + OUT PNDIS_BUFFER * Buffer + ) + +/*++ + +Routine Description: + + Takes a buffer off the end of a packet. + +Arguments: + + Packet - The packet to be modified. + Buffer - Returns the packet on the end, or NULL. + +Return Value: + + None. + +--*/ + +{ + PNDIS_BUFFER TmpBufP = Packet->Private.Head; + PNDIS_BUFFER Result; + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtBack\n"); + IF_ERROR_CHK { + if (DbgIsNull(Packet)) { + NdisPrint1("UnchainBufferAtBack: Null Packet Pointer\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Packet)) { + NdisPrint1("UnchainBufferAtBack: Packet not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (!DbgIsPacket(Packet)) { + NdisPrint1("UnchainBufferAtBack: Illegal Packet Size\n"); + DbgBreakPoint(); + } + } + if (TmpBufP != (PNDIS_BUFFER)NULL) { + + // + // The packet is not empty, return the tail buffer. + // + + Result = Packet->Private.Tail; + if (TmpBufP == Result) { + + // + // There was only one buffer on the queue. + // + + Packet->Private.Head = (PNDIS_BUFFER)NULL; + } else { + + // + // Determine the new tail buffer. + // + + while (TmpBufP->Next != Result) { + TmpBufP = TmpBufP->Next; + } + Packet->Private.Tail = TmpBufP; + TmpBufP->Next = NULL; + } + + Result->Next = (PNDIS_BUFFER)NULL; + Packet->Private.ValidCounts = FALSE; + } else { + + // + // Packet is empty. + // + + Result = (PNDIS_BUFFER)NULL; + } + + *Buffer = Result; + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtBack\n"); +} + + + +VOID +NdisCopyFromPacketToPacket( + IN PNDIS_PACKET Destination, + IN UINT DestinationOffset, + IN UINT BytesToCopy, + IN PNDIS_PACKET Source, + IN UINT SourceOffset, + OUT PUINT BytesCopied + ) + +/*++ + +Routine Description: + + Copy from an ndis packet to an ndis packet. + +Arguments: + + Destination - The packet should be copied in to. + + DestinationOffset - The offset from the beginning of the packet + into which the data should start being placed. + + BytesToCopy - The number of bytes to copy from the source packet. + + Source - The ndis packet from which to copy data. + + SourceOffset - The offset from the start of the packet from which + to start copying data. + + BytesCopied - The number of bytes actually copied from the source + packet. This can be less than BytesToCopy if the source or destination + packet is too short. + +Return Value: + + None + +--*/ + +{ + + // + // Holds the count of the number of ndis buffers comprising the + // destination packet. + // + UINT DestinationBufferCount; + + // + // Holds the count of the number of ndis buffers comprising the + // source packet. + // + UINT SourceBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Points to the buffer from which we are extracting data. + // + PNDIS_BUFFER SourceCurrentBuffer; + + // + // Holds the virtual address of the current destination buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the virtual address of the current source buffer. + // + PVOID SourceVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Holds the length of the current source buffer. + // + UINT SourceCurrentLength; + + // + // Keep a local variable of BytesCopied so we aren't referencing + // through a pointer. + // + UINT LocalBytesCopied = 0; + + // + // Take care of boundary condition of zero length copy. + // + + *BytesCopied = 0; + if (!BytesToCopy) return; + + // + // Get the first buffer of the destination. + // + + NdisQueryPacket( + Destination, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!DestinationBufferCount) return; + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Get the first buffer of the source. + // + + NdisQueryPacket( + Source, + NULL, + &SourceBufferCount, + &SourceCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + + if (!SourceBufferCount) return; + + NdisQueryBuffer( + SourceCurrentBuffer, + &SourceVirtualAddress, + &SourceCurrentLength + ); + + while (LocalBytesCopied < BytesToCopy) { + + // + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + + if (!DestinationCurrentLength) { + + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (!DestinationCurrentBuffer) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + continue; + + } + + + // + // Check to see whether we've exhausted the current source + // buffer. If so, move onto the next one. + // + + if (!SourceCurrentLength) { + + NdisGetNextBuffer( + SourceCurrentBuffer, + &SourceCurrentBuffer + ); + + if (!SourceCurrentBuffer) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + + break; + + } + + NdisQueryBuffer( + SourceCurrentBuffer, + &SourceVirtualAddress, + &SourceCurrentLength + ); + continue; + + } + + // + // Try to get us up to the point to start the copy. + // + + if (DestinationOffset) { + + if (DestinationOffset > DestinationCurrentLength) { + + // + // What we want isn't in this buffer. + // + + DestinationOffset -= DestinationCurrentLength; + DestinationCurrentLength = 0; + continue; + + } else { + + DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress + + DestinationOffset; + DestinationCurrentLength -= DestinationOffset; + DestinationOffset = 0; + + } + + } + + // + // Try to get us up to the point to start the copy. + // + + if (SourceOffset) { + + if (SourceOffset > SourceCurrentLength) { + + // + // What we want isn't in this buffer. + // + + SourceOffset -= SourceCurrentLength; + SourceCurrentLength = 0; + continue; + + } else { + + SourceVirtualAddress = (PCHAR)SourceVirtualAddress + + SourceOffset; + SourceCurrentLength -= SourceOffset; + SourceOffset = 0; + + } + + } + + // + // Copy the data. + // + + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToCopy - LocalBytesCopied; + + AmountToMove = + ((SourceCurrentLength <= DestinationCurrentLength)? + (SourceCurrentLength):(DestinationCurrentLength)); + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + RtlCopyMemory( + DestinationVirtualAddress, + SourceVirtualAddress, + AmountToMove + ); + + DestinationVirtualAddress = + (PCHAR)DestinationVirtualAddress + AmountToMove; + SourceVirtualAddress = + (PCHAR)SourceVirtualAddress + AmountToMove; + + LocalBytesCopied += AmountToMove; + SourceCurrentLength -= AmountToMove; + DestinationCurrentLength -= AmountToMove; + + } + + } + + *BytesCopied = LocalBytesCopied; + +} + +// +// Operating System Requests +// +// + + +VOID +NdisMapIoSpace( + OUT PNDIS_STATUS Status, + OUT PVOID * VirtualAddress, + IN NDIS_HANDLE NdisAdapterHandle, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress, + IN UINT Length + ) +/*++ + +Routine Description: + + Map virtual memory address space onto a physical address. + +Arguments: + + Status - resulting status + VirtualAddress - resulting address in virtual space. + NdisAdapterHandle - value returned by NdisRegisterAdapter. + PhysicalAddress - Physical address. + Length - Size of requested memory mapping + +Return Value: + + none. + +--*/ +{ + ULONG addressSpace = 0; + ULONG NumberOfElements; + PHYSICAL_ADDRESS PhysicalTemp; + PCM_RESOURCE_LIST Resources; + BOOLEAN Conflict; + NTSTATUS NtStatus; + PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle); + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle); + + // + // First check if any bus access is allowed + // + + if ((((AdptrP->DeviceObject != NULL) ? + AdptrP->BusType : + Miniport->BusType) == (NDIS_INTERFACE_TYPE)-1) || + (((AdptrP->DeviceObject != NULL) ? + AdptrP->BusNumber : + Miniport->BusNumber) == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + if (((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources : + Miniport->Resources) != NULL) { + + NumberOfElements = ((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources->List[0].PartialResourceList.Count + 1: + Miniport->Resources->List[0].PartialResourceList.Count + 1); + + } else { + + NumberOfElements = 1; + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + NumberOfElements, + 'lrDN' + ); + + if (Resources == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + if (((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources : + Miniport->Resources) != NULL) { + + RtlCopyMemory (Resources, + ((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources: + Miniport->Resources), + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (NumberOfElements-1) + ); + } else { + + // + // Setup initial resource info -- NOTE: This is definitely a mini-port + // + ASSERT(AdptrP->DeviceObject == NULL); + Resources->Count = 1; + Resources->List[0].InterfaceType = Miniport->AdapterType; + Resources->List[0].BusNumber = Miniport->BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup memory + // + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypeMemory; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + CM_RESOURCE_MEMORY_READ_WRITE; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Start = + PhysicalAddress; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Length = + Length; + Resources->List[0].PartialResourceList.Count++; + + + // + // Make the call + // + + NtStatus = IoReportResourceUsage( + NULL, + ((AdptrP->DeviceObject != NULL) ? + AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver : + Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver), + NULL, + 0, + ((AdptrP->DeviceObject != NULL) ? + AdptrP->DeviceObject: + Miniport->DeviceObject), + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Check for conflict. + // + + if (((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources : + Miniport->Resources) != NULL) { + ExFreePool(((AdptrP->DeviceObject != NULL) ? + AdptrP->Resources: + Miniport->Resources)); + } + + if (AdptrP->DeviceObject != NULL) { + AdptrP->Resources = Resources; + } else { + Miniport->Resources = Resources; + } + + if (Conflict || (NtStatus != STATUS_SUCCESS)) { + + + if (Conflict) { + + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + volatile ULONG i; + ULONG StringSize; + PUCHAR Place; + PWCH baseFileName; + WCHAR Character; + ULONG Value; + + baseFileName = ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Buffer : + Miniport->MiniportName.Buffer); + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; + i < ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Length : + Miniport->MiniportName.Length) / sizeof(WCHAR); + i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Buffer[i] : + Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = ((AdptrP->DeviceObject != NULL) ? + &(AdptrP->AdapterName.Buffer[++i]): + &(Miniport->MiniportName.Buffer[++i])); + } + + } + + StringSize = ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.MaximumLength : + Miniport->MiniportName.MaximumLength) - + (((ULONG)baseFileName) - + ((AdptrP->DeviceObject != NULL) ? + ((ULONG)AdptrP->AdapterName.Buffer) : + ((ULONG)Miniport->MiniportName.Buffer))); + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + ((AdptrP->DeviceObject != NULL) ? + AdptrP->DeviceObject: + Miniport->DeviceObject), + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize + + 34) // wstrlen("FFFFFFFFFFFFFFFF") * sizeof(WHCAR) + sizeof(UNICODE_NULL) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET) + + StringSize; + + } else { + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET); + + errorLogEntry->NumberOfStrings = 0; + + } + + errorLogEntry->NumberOfStrings++; + + // + // Put in memory address + // + + for (StringSize = 0; StringSize < 2; StringSize++) { + + if (StringSize == 0) { + + // + // Do high part + // + + Value = NdisGetPhysicalAddressHigh(PhysicalAddress); + + } else { + + // + // Do Low part + // + + Value = NdisGetPhysicalAddressLow(PhysicalAddress); + + } + + // + // Convert value + // + + for (i = 1; i <= (sizeof(ULONG) * 2); i++) { + + switch ((Value >> (((sizeof(ULONG) * 2) - i) * 4)) & 0x0F) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + case 10: + Character = L'A'; + break; + case 11: + Character = L'B'; + break; + case 12: + Character = L'C'; + break; + case 13: + Character = L'D'; + break; + case 14: + Character = L'E'; + break; + case 15: + Character = L'F'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + } + + } + + Character = UNICODE_NULL; + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + + } + + *Status = NDIS_STATUS_RESOURCE_CONFLICT; + return; + + } + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + + if ( !HalTranslateBusAddress( + ((AdptrP->DeviceObject != NULL) ? + AdptrP->BusType: + Miniport->BusType), + ((AdptrP->DeviceObject != NULL) ? + AdptrP->BusNumber : + Miniport->BusNumber), + PhysicalAddress, + &addressSpace, + &PhysicalTemp + ) ) { + + // + // It would be nice to return a better status here, but we only get + // TRUE/FALSE back from HalTranslateBusAddress. + // + + *Status = NDIS_STATUS_FAILURE; + return; + } + + if (addressSpace == 0) { + + // + // memory space + // + + *VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE); + + } else { + + // + // I/O space + // + + *VirtualAddress = (PVOID)(PhysicalTemp.LowPart); + + } + + if (*VirtualAddress == NULL) { + *Status = NDIS_STATUS_RESOURCES; + } else { + *Status = NDIS_STATUS_SUCCESS; + } +} + +NDIS_STATUS +NdisAllocateMemory( + OUT PVOID *VirtualAddress, + IN UINT Length, + IN UINT MemoryFlags, + IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress + ) +/*++ + +Routine Description: + + Allocate memory for use by a protocol or a MAC driver + +Arguments: + + VirtualAddress - Returns a pointer to the allocated memory. + Length - Size of requested allocation in bytes. + MaximumPhysicalAddress - Highest addressable address of the allocated + memory.. 0 means highest system memory possible. + MemoryFlags - Bit mask that allows the caller to specify attributes + of the allocated memory. 0 means standard memory. + + other options: + + NDIS_MEMORY_CONTIGUOUS + NDIS_MEMORY_NONCACHED + +Return Value: + + NDIS_STATUS_SUCCESS if successful. + NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL. + + +--*/ +{ + // + // Depending on the value of MemoryFlags, we allocate three different + // types of memory. + // + + if (MemoryFlags == 0) { + + *VirtualAddress = ExAllocatePoolWithTag(NonPagedPool, Length, 'maDN'); + + } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) { + + *VirtualAddress = MmAllocateNonCachedMemory(Length); + + } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) { + + *VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress); + + } + + if (*VirtualAddress == NULL) { + + return NDIS_STATUS_FAILURE; + + } + + return NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisFreeMemory( + IN PVOID VirtualAddress, + IN UINT Length, + IN UINT MemoryFlags + ) +/*++ + +Routine Description: + + Releases memory allocated using NdisAllocateMemory. + +Arguments: + + VirtualAddress - Pointer to the memory to be freed. + Length - Size of allocation in bytes. + MemoryFlags - Bit mask that allows the caller to specify attributes + of the allocated memory. 0 means standard memory. + + other options: + + NDIS_MEMORY_CONTIGUOUS + NDIS_MEMORY_NONCACHED + +Return Value: + + None. + +--*/ +{ + // + // Depending on the value of MemoryFlags, we allocate three free 3 + // types of memory. + // + + if (MemoryFlags == 0) { + + ExFreePool(VirtualAddress); + + } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) { + + MmFreeNonCachedMemory(VirtualAddress, Length); + + } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) { + + MmFreeContiguousMemory(VirtualAddress); + + } + +} + +VOID +NdisInitializeTimer( + IN OUT PNDIS_TIMER NdisTimer, + IN PNDIS_TIMER_FUNCTION TimerFunction, + IN PVOID FunctionContext + ) +/*++ + +Routine Description: + + Sets up an NdisTimer object, initializing the DPC in the timer to + the function and context. + +Arguments: + + NdisTimer - the timer object. + TimerFunction - Routine to start. + FunctionContext - Context of TimerFunction. + +Return Value: + + None. + +--*/ +{ + + KeInitializeTimer(&(NdisTimer)->Timer); + + // + // Initialize our dpc. If Dpc was previously initialized, this will + // reinitialize it. + // + + KeInitializeDpc( + &NdisTimer->Dpc, + (PKDEFERRED_ROUTINE) TimerFunction, + FunctionContext + ); + + KeSetImportanceDpc( + &NdisTimer->Dpc, + LowImportance + ); +} + + +VOID +NdisSetTimer( + IN PNDIS_TIMER NdisTimer, + IN UINT MillisecondsToDelay + ) +/*++ + +Routine Description: + + Sets up TimerFunction to fire after MillisecondsToDelay. + +Arguments: + + NdisTimer - the timer object. + MillisecondsToDelay - Amount of time before TimerFunction is started. + +Return Value: + + None. + +--*/ +{ + LARGE_INTEGER FireUpTime; + + FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsToDelay, -10000); + + // + // Set the timer + // + KeSetTimer( + &NdisTimer->Timer, + FireUpTime, + &NdisTimer->Dpc + ); +} + + +BOOLEAN +NdisIsr( + IN PKINTERRUPT Interrupt, + IN PVOID Context + ) +/*++ + +Routine Description: + + Handles ALL Mac interrupts, calling the appropriate Mac ISR and DPC + depending on the context. + +Arguments: + + Interrupt - Interrupt object for the Mac. + + Context - Really a pointer to the interrupt. + +Return Value: + + None. + +--*/ +{ + // + // Get adapter from context. + // + + PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(Context); + + BOOLEAN (*InterruptIsr)(PVOID) = (BOOLEAN (*) (PVOID))(NdisInterrupt->MacIsr); + + UNREFERENCED_PARAMETER(Interrupt); + + // + // Call MacIsr + // + + if((*InterruptIsr)(NdisInterrupt->InterruptContext) != FALSE){ + + // + // Queue MacDpc if needed + // + + Increment((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock); + + if (!(KeInsertQueueDpc(&(NdisInterrupt->InterruptDpc),NULL,NULL))) { + + // + // If the DPC was already queued, then we have an extra + // reference (we do it this way to ensure that the reference + // is added *before* the DPC is queued). + // + + Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock); + + if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) { + + // + // We need to queue a DPC to set the event because we + // can't do it from the ISR. We know that the interrupt + // DPC won't fire because the refcount is 0, so we reuse it. + // + + KeInitializeDpc( + &NdisInterrupt->InterruptDpc, + NdisLastCountRemovedFunction, + (PVOID)(&NdisInterrupt->DpcsCompletedEvent) + ); + + // + // When NdisLastCountRemovedFunction runs it will set + // the event. + // + + KeInsertQueueDpc (&(NdisInterrupt->InterruptDpc), NULL, NULL); + + } + } + + return TRUE; + + } + + return FALSE; + +} + +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); + + KeSetEvent( + (PKEVENT)DeferredContext, + 0L, + FALSE + ); +} + + +VOID +NdisDpc( + IN PVOID SystemSpecific1, + IN PVOID InterruptContext, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) +/*++ + +Routine Description: + + Handles ALL Mac interrupt DPCs, calling the appropriate Mac DPC + depending on the context. + +Arguments: + + Interrupt - Interrupt object for the Mac. + + Context - Really a pointer to the Interrupt. + +Return Value: + + None. + +--*/ +{ + // + // Get adapter from context. + // + + PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(InterruptContext); + + VOID (*MacDpc)(PVOID) = (VOID (*) (PVOID))(NdisInterrupt->MacDpc); + + // + // Call MacDpc + // + + (*((PNDIS_DEFERRED_PROCESSING)MacDpc))(SystemSpecific1, + NdisInterrupt->InterruptContext, + SystemSpecific2, + SystemSpecific3 + ); + + Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock); + + if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) { + + KeSetEvent( + &NdisInterrupt->DpcsCompletedEvent, + 0L, + FALSE + ); + } + + +} + + +VOID +NdisInitializeInterrupt( + OUT PNDIS_STATUS Status, + IN OUT PNDIS_INTERRUPT NdisInterrupt, + IN NDIS_HANDLE NdisAdapterHandle, + IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine, + IN PVOID InterruptContext, + IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine, + IN UINT InterruptVector, + IN UINT InterruptLevel, + IN BOOLEAN SharedInterrupt, + IN NDIS_INTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + Initializes the interrupt and sets up the Dpc. + +Arguments: + + Status - Status of this request. + InterruptDpc - The Dpc object corresponding to DeferredProcessingRoutine. + Interrupt - Points to driver allocated memory that the wrapper fills in + with information about the interrupt handler. + InterruptServiceRoutine - The ISR that is called for this interrupt. + InterruptContext - Value passed to the ISR. + DeferredProcessingRoutine - The DPC queued by the ISR. + InterruptVector - Interrupt number used by the ISR. + InterruptMode - Type of interrupt the adapter generates. + +Return Value: + + None. + +--*/ +{ + NTSTATUS NtStatus; + PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle); + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle); + ULONG Vector; + ULONG NumberOfElements; + KIRQL Irql; + KAFFINITY InterruptAffinity; + PCM_RESOURCE_LIST Resources; + BOOLEAN Conflict; + BOOLEAN IsAMiniport; + PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)(NdisInterrupt); + + IsAMiniport = (AdptrP->DeviceObject == NULL); + + // + // First check if any bus access is allowed + // + + if (((IsAMiniport ? + Miniport->BusType: + AdptrP->BusType) == (NDIS_INTERFACE_TYPE)-1) || + ((IsAMiniport ? + Miniport->BusNumber: + AdptrP->BusNumber) == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + *Status = NDIS_STATUS_SUCCESS; + + // + // First check for resource conflict by expanding current resource list, + // adding in the interrupt, and then re-submitting the resource list. + // + + if ((IsAMiniport ? + Miniport->Resources: + AdptrP->Resources) != NULL) { + + NumberOfElements = (IsAMiniport ? + Miniport->Resources->List[0].PartialResourceList.Count + 1 : + AdptrP->Resources->List[0].PartialResourceList.Count + 1); + + } else { + + NumberOfElements = 1; + } + + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + NumberOfElements, + 'lrDN' + ); + + if (Resources == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + if ((IsAMiniport ? + Miniport->Resources : + AdptrP->Resources) != NULL) { + + RtlCopyMemory (Resources, + (IsAMiniport ? + Miniport->Resources : + AdptrP->Resources), + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (NumberOfElements - 1) + ); + + } else { + + // + // Setup initial resource info + // + ASSERT(IsAMiniport); + Resources->Count = 1; + Resources->List[0].InterfaceType = Miniport->AdapterType; + Resources->List[0].BusNumber = Miniport->BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup interrupt + // + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypeInterrupt; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + SharedInterrupt ? CmResourceShareShared : CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + (InterruptMode == NdisInterruptLatched) ? + CM_RESOURCE_INTERRUPT_LATCHED : + CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Level = + InterruptLevel; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Vector = + InterruptVector; + Resources->List[0].PartialResourceList.Count++; + + // + // Make the call + // + + NtStatus = IoReportResourceUsage( + NULL, + (IsAMiniport ? + Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver : + AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver), + NULL, + 0, + (IsAMiniport ? + Miniport->DeviceObject : + AdptrP->DeviceObject), + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Check for conflict. + // + + if ((IsAMiniport ? + Miniport->Resources: + AdptrP->Resources) != NULL) { + ExFreePool((IsAMiniport ? + Miniport->Resources: + AdptrP->Resources)); + } + + if (IsAMiniport) { + + Miniport->Resources = Resources; + + } else { + + AdptrP->Resources = Resources; + + + } + if (Conflict || (NtStatus != STATUS_SUCCESS)) { + + if (Conflict) { + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG i; + ULONG StringSize; + PUCHAR Place; + PWCH baseFileName; + WCHAR Character; + ULONG Value; + + baseFileName = ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Buffer : + Miniport->MiniportName.Buffer); + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; + i < ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Length : + Miniport->MiniportName.Length) / sizeof(WCHAR); + i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.Buffer[i] : + Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = ((AdptrP->DeviceObject != NULL) ? + &(AdptrP->AdapterName.Buffer[++i]): + &(Miniport->MiniportName.Buffer[++i])); + } + + } + + StringSize = ((AdptrP->DeviceObject != NULL) ? + AdptrP->AdapterName.MaximumLength : + Miniport->MiniportName.MaximumLength) - + (((ULONG)baseFileName) - + ((AdptrP->DeviceObject != NULL) ? + ((ULONG)AdptrP->AdapterName.Buffer) : + ((ULONG)Miniport->MiniportName.Buffer))); + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + (IsAMiniport ? + Miniport->DeviceObject : + AdptrP->DeviceObject), + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize + + 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET) + + StringSize; + + } else { + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET); + + errorLogEntry->NumberOfStrings = 0; + + } + + errorLogEntry->NumberOfStrings++; + + // + // Put in interrupt level + // + + Value = InterruptLevel; + + // + // Convert value + // + // I couldn't think of a better way to do this (with some + // loop). If you find one, plz put it in. + // + + if (Value > 9) { + + switch (Value / 10) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + Value -= 10; + + } + + switch (Value) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + Character = UNICODE_NULL; + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + } + + *Status = NDIS_STATUS_RESOURCE_CONFLICT; + return; + + } + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // We must do this stuff first because if we connect the + // interrupt first then an interrupt could occur before + // the MacISR is recorded in the Ndis interrupt structure. + // + + if (IsAMiniport) { + + KeInitializeSpinLock(&(MiniportInterrupt->DpcCountLock)); + Miniport->Interrupt = MiniportInterrupt; + MiniportInterrupt->DpcCount = 0; + MiniportInterrupt->MiniportIdField = NULL; + MiniportInterrupt->Miniport = Miniport; + MiniportInterrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler; + MiniportInterrupt->MiniportDpc = Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler; + MiniportInterrupt->SharedInterrupt = SharedInterrupt; + MiniportInterrupt->IsrRequested = (BOOLEAN)DeferredProcessingRoutine; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + } else { + + NdisInterrupt->MacIsr = InterruptServiceRoutine; + NdisInterrupt->MacDpc = DeferredProcessingRoutine; + NdisInterrupt->InterruptContext = InterruptContext; + KeInitializeSpinLock(&(NdisInterrupt->DpcCountLock)); + NdisInterrupt->DpcCount = 0; + NdisInterrupt->Removing = FALSE; + + } + + // + // This is used to tell when all Dpcs are completed after the + // interrupt has been removed. + // + + KeInitializeEvent( + (IsAMiniport ? + &MiniportInterrupt->DpcsCompletedEvent : + &NdisInterrupt->DpcsCompletedEvent), + NotificationEvent, + FALSE + ); + + // + // Initialize our dpc. + // + + if (NdisMacAdapterDpcTargetProcessor < 0) { + NdisMacAdapterDpcTargetProcessor = (**(PCCHAR *)&KeNumberProcessors) - 1; + } + + if (IsAMiniport) { + + KeInitializeDpc( + &MiniportInterrupt->InterruptDpc, + (PKDEFERRED_ROUTINE) NdisMDpc, + MiniportInterrupt + ); + + KeSetImportanceDpc( + &MiniportInterrupt->InterruptDpc, + LowImportance + ); + + KeSetTargetProcessorDpc ( + &MiniportInterrupt->InterruptDpc, + NdisMacAdapterDpcTargetProcessor + ); + } else { + + KeInitializeDpc( + &NdisInterrupt->InterruptDpc, + (PKDEFERRED_ROUTINE) NdisDpc, + NdisInterrupt + ); + + KeSetImportanceDpc( + &NdisInterrupt->InterruptDpc, + LowImportance + ); + + KeSetTargetProcessorDpc ( + &NdisInterrupt->InterruptDpc, + NdisMacAdapterDpcTargetProcessor + ); + } + + NdisMacAdapterDpcTargetProcessor -= 1; + + // + // Get the system interrupt vector and IRQL. + // + + Vector = HalGetInterruptVector( + (IsAMiniport ? + Miniport->BusType : + AdptrP->BusType), // InterfaceType + (IsAMiniport ? + Miniport->BusNumber : + AdptrP->BusNumber), // BusNumber + (ULONG)InterruptLevel, // BusInterruptLevel + (ULONG)InterruptVector, // BusInterruptVector + &Irql, // Irql + &InterruptAffinity + ); + + if (IsAMiniport) { + + NtStatus = IoConnectInterrupt( + &MiniportInterrupt->InterruptObject, + (PKSERVICE_ROUTINE)NdisMIsr, + MiniportInterrupt, + NULL, + Vector, + Irql, + Irql, + (KINTERRUPT_MODE)InterruptMode, + SharedInterrupt, + InterruptAffinity, + FALSE + ); + + } else { + + NtStatus = IoConnectInterrupt( + &NdisInterrupt->InterruptObject, + (PKSERVICE_ROUTINE)NdisIsr, + NdisInterrupt, + NULL, + Vector, + Irql, + Irql, + (KINTERRUPT_MODE)InterruptMode, + SharedInterrupt, + InterruptAffinity, + FALSE + ); + } + + + if (!NT_SUCCESS(NtStatus)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + +} + +VOID +NdisRemoveInterrupt( + IN PNDIS_INTERRUPT Interrupt + ) +/*++ + +Routine Description: + + Removes the interrupt, will not return until all interrupts and + interrupt dpcs are completed. + +Arguments: + + Interrupt - Points to driver allocated memory that the wrapper filled + with information about the interrupt handler. + +Return Value: + + None. + +--*/ +{ + PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt; + + if (MiniportInterrupt->MiniportIdField == NULL) { + + MiniportInterrupt->Miniport->BeingRemoved = TRUE; + + } else { + + Interrupt->Removing = TRUE; + + } + + // + // Now we disconnect the interrupt. NOTE: they are aligned in both structures + // + + IoDisconnectInterrupt( + Interrupt->InterruptObject + ); + + // + // Right now we know that any Dpcs that may fire are counted. + // We don't have to guard this with a spin lock because the + // Dpc will set the event if if completes first, or we may + // wait for a little while for it to complete. + // + + if (Interrupt->DpcCount > 0) { + + // + // Now we wait for all dpcs to complete. + // + + KeWaitForSingleObject( + &Interrupt->DpcsCompletedEvent, + Executive, + KernelMode, + TRUE, + (PTIME)NULL + ); + + KeResetEvent( + &Interrupt->DpcsCompletedEvent + ); + + + } + +} + + + +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; + + ACQUIRE_SPIN_LOCK(&NdisMacListLock); + + // + // Search for the MacP + // + + MacP = NdisMacList; + + while (MacP != (PNDIS_MAC_BLOCK)NULL) { + + if (MacP->NdisMacInfo->NdisWrapperDriver == DriverObject) { + + break; + + } + + MacP = MacP->NextMac; + + } + + RELEASE_SPIN_LOCK(&NdisMacListLock); + + 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. + // + + KeWaitForSingleObject( + &MacP->AdaptersRemovedEvent, + Executive, + KernelMode, + TRUE, + (PTIME)NULL + ); + + KeResetEvent( + &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( + PDEVICE_OBJECT DeviceObject, + 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); + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisShutdown\n"); + + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + } + + if (WrapperContext->ShutdownHandler != NULL) { + + // + // Call the shutdown routine + // + + WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext); + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisShutdown\n"); + + return STATUS_SUCCESS; +} + +VOID +NdisAllocateSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + OUT PVOID *VirtualAddress, + OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Allocates memory to be shared between the driver and the adapter. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - Length of the memory to allocate. + Cached - TRUE if memory is to be cached. + VirtualAddress - Returns the virtual address of the memory, + or NULL if the memory cannot be allocated. + PhysicalAddress - Returns the physical address of the memory. + +Return Value: + + None. + +--*/ + +{ + + ULONG Alignment; + PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + PADAPTER_OBJECT SystemAdapterObject; + PNDIS_WRAPPER_CONTEXT WrapperContext; + PULONG Page; + ULONG Type; + + // + // Get interesting information from the adapter/miniport. + // + + if ( AdaptP->DeviceObject != NULL ) { + SystemAdapterObject = AdaptP->SystemAdapterObject; + WrapperContext = AdaptP->WrapperContext; + } else { + SystemAdapterObject = Miniport->SystemAdapterObject; + WrapperContext = Miniport->WrapperContext; + } + + // + // Non-busmasters shouldn't call this routine. + // + + if (SystemAdapterObject == NULL) { + *VirtualAddress = NULL; + KdPrint(("NDIS: You are not a busmaster\n")); + return; + } + + // + // Compute allocation size by aligning to the proper boundary. + // + + ASSERT(Length != 0); + + Alignment = HalGetDmaAlignmentRequirement(); + if (sizeof(ULONG) > Alignment) { + Alignment = sizeof(ULONG); + } + + Length = (Length + Alignment - 1) & ~(Alignment - 1); + + // + // Check to determine is there is enough room left in the current page + // to satisfy the allocation. + // + + Type = Cached ? 1 : 0; + ExAcquireResourceExclusive(&SharedMemoryResource, TRUE); + if (WrapperContext->SharedMemoryLeft[Type] < Length) { + if ((Length + sizeof(ULONG)) >= PAGE_SIZE) { + + // + // The allocation is greater than a page. + // + + *VirtualAddress = HalAllocateCommonBuffer( + SystemAdapterObject, + Length, + PhysicalAddress, + Cached); + + ExReleaseResource(&SharedMemoryResource); + return; + } + + // + // Allocate a new page for shared alocation. + // + + WrapperContext->SharedMemoryPage[Type] = + HalAllocateCommonBuffer( + SystemAdapterObject, + PAGE_SIZE, + &WrapperContext->SharedMemoryAddress[Type], + Cached); + + if (WrapperContext->SharedMemoryPage[Type] == NULL) { + WrapperContext->SharedMemoryLeft[Type] = 0; + *VirtualAddress = NULL; + ExReleaseResource(&SharedMemoryResource); + return; + } + + // + // Initialize the reference count in the last ULONG of the page. + // + + Page = (PULONG)WrapperContext->SharedMemoryPage[Type]; + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] = 0; + WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(ULONG); + } + + // + // Increment the reference count, set the address of the allocation, + // compute the physical address, and reduce the space remaining. + // + + Page = (PULONG)WrapperContext->SharedMemoryPage[Type]; + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] += 1; + *VirtualAddress = (PVOID)((PUCHAR)Page + + (PAGE_SIZE - sizeof(ULONG) - WrapperContext->SharedMemoryLeft[Type])); + +#if !defined(BUILD_FOR_3_1) + PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart + + ((ULONG)*VirtualAddress & (PAGE_SIZE - 1)); +#else + *PhysicalAddress = RtlLargeIntegerAdd( + WrapperContext->SharedMemoryAddress[Type], + RtlConvertUlongToLargeInteger((ULONG)*VirtualAddress & (PAGE_SIZE - 1)) + ); +#endif + + WrapperContext->SharedMemoryLeft[Type] -= Length; + ExReleaseResource(&SharedMemoryResource); + return; +} + + +#undef NdisUpdateSharedMemory + +VOID +NdisUpdateSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Ensures that the data to be read from a shared memory region is + fully up-to-date. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - The length of the shared memory. + VirtualAddress - Virtual address returned by NdisAllocateSharedMemory. + PhysicalAddress - The physical address returned by NdisAllocateSharedMemory. + +Return Value: + + None. + +--*/ + +{ + + // + // There is no underlying HAL routine for this anymore, + // it is not needed. This is macro'd to nothing in the + // header file now. This is there for backward compatibility + + NdisAdapterHandle; Length; VirtualAddress; PhysicalAddress; + +} + + +VOID +NdisFreeSharedMemory( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG Length, + IN BOOLEAN Cached, + IN PVOID VirtualAddress, + IN NDIS_PHYSICAL_ADDRESS PhysicalAddress + ) + +/*++ + +Routine Description: + + Allocates memory to be shared between the driver and the adapter. + +Arguments: + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + Length - Length of the memory to allocate. + Cached - TRUE if memory was allocated cached. + VirtualAddress - Virtual address returned by NdisAllocateSharedMemory. + PhysicalAddress - The physical address returned by NdisAllocateSharedMemory. + +Return Value: + + None. + +--*/ + +{ + + ULONG Alignment; + PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + PADAPTER_OBJECT SystemAdapterObject; + PNDIS_WRAPPER_CONTEXT WrapperContext; + PULONG Page; + ULONG Type; + + // + // Get interesting information from the adapter/miniport. + // + + if ( AdaptP->DeviceObject != NULL ) { + SystemAdapterObject = AdaptP->SystemAdapterObject; + WrapperContext = AdaptP->WrapperContext; + } else { + SystemAdapterObject = Miniport->SystemAdapterObject; + WrapperContext = Miniport->WrapperContext; + } + + // + // Non-busmasters shouldn't call this routine. + // + + ASSERT(SystemAdapterObject != NULL); + + // + // Compute allocation size by aligning to the proper boundary. + // + + ASSERT(Length != 0); + + Alignment = HalGetDmaAlignmentRequirement(); + if (sizeof(ULONG) > Alignment) { + Alignment = sizeof(ULONG); + } + + Length = (Length + Alignment - 1) & ~(Alignment - 1); + + // + // Free the specified memory. + // + + ExAcquireResourceExclusive(&SharedMemoryResource, TRUE); + if ((Length + sizeof(ULONG)) >= PAGE_SIZE) { + + // + // The allocation is greater than a page free the page directly. + // + + HalFreeCommonBuffer( + SystemAdapterObject, + Length, + PhysicalAddress, + VirtualAddress, + Cached); + + } else { + + // + // Decrement the reference count and if the result is zero, then free + // the page. + // + + Page = (PULONG)((ULONG)VirtualAddress & ~(PAGE_SIZE - 1)); + Page[(PAGE_SIZE / sizeof(ULONG)) - 1] -= 1; + if (Page[(PAGE_SIZE / sizeof(ULONG)) - 1] == 0) { + + // + // Compute the physical address of the page and free it. + // + + PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1); + HalFreeCommonBuffer( + SystemAdapterObject, + PAGE_SIZE, + PhysicalAddress, + Page, + Cached); + + Type = Cached ? 1 : 0; + if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type]) { + WrapperContext->SharedMemoryLeft[Type] = 0; + WrapperContext->SharedMemoryPage[Type] = NULL; + } + } + } + + ExReleaseResource(&SharedMemoryResource); + return; +} + + +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 NdisAllocate + DmaChannel 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. + // + + KeSetEvent( + &DmaBlock->AllocationEvent, + 0L, + FALSE + ); + + return KeepObject; +} + + + +VOID +NdisAllocateDmaChannel( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisDmaHandle, + IN NDIS_HANDLE NdisAdapterHandle, + IN PNDIS_DMA_DESCRIPTION DmaDescription, + IN ULONG MaximumLength + ) + +/*++ + +Routine Description: + + Sets up a DMA channel for future DMA operations. + +Arguments: + + Status - Returns the status of the request. + + NdisDmaHandle - Returns a handle used to specify this channel to + future operations. + + NdisAdapterHandle - handle returned by NdisRegisterAdapter. + + DmaDescription - Details of the DMA channel. + + MaximumLength - The maximum length DMA transfer that will be done + using this channel. + +Return Value: + + None. + +--*/ +{ + // + // For registering this set of resources + // + PCM_RESOURCE_LIST Resources; + BOOLEAN Conflict; + + // + // Needed to call HalGetAdapter. + // + DEVICE_DESCRIPTION DeviceDescription; + + // + // Returned by HalGetAdapter. + // + PADAPTER_OBJECT AdapterObject; + + // + // Map registers needed per channel. + // + ULONG MapRegistersNeeded; + + // + // Map registers allowed per channel. + // + ULONG MapRegistersAllowed; + + // + // Saves the structure we allocate for this channel. + // + PNDIS_DMA_BLOCK DmaBlock; + + // + // Convert the handle to our internal structure. + PNDIS_ADAPTER_BLOCK AdapterBlock = + (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle; + + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) NdisAdapterHandle; + BOOLEAN IsAMiniport; + + // + // Save our IRQL when we raise it to call IoAllocateAdapterChannel. + // + KIRQL OldIrql; + ULONG NumberOfElements; + + NTSTATUS NtStatus; + + LARGE_INTEGER TimeoutValue; + + IsAMiniport = (AdapterBlock->DeviceObject == NULL); + + // + // First check if any bus access is allowed + // + + if (((IsAMiniport ? + Miniport->BusType : + AdapterBlock->BusType) == (NDIS_INTERFACE_TYPE)-1) || + ((IsAMiniport ? + Miniport->BusNumber : + AdapterBlock->BusNumber) == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) { + + NumberOfElements = + (IsAMiniport ? + Miniport->Resources->List[0].PartialResourceList.Count : + AdapterBlock->Resources->List[0].PartialResourceList.Count) + 1; + + } else { + + NumberOfElements = 1; + } + + // + // First check for resource conflict by expanding current resource list, + // adding in the mapped space, and then re-submitting the resource list. + // + + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + NumberOfElements, + 'lrDN' + ); + + if (Resources == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) { + + RtlCopyMemory (Resources, + (IsAMiniport ? Miniport->Resources : AdapterBlock->Resources), + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (NumberOfElements - 1) + ); + } else { + + // + // Setup initial resource info + // + ASSERT(IsAMiniport); + Resources->Count = 1; + Resources->List[0].InterfaceType = Miniport->AdapterType; + Resources->List[0].BusNumber = Miniport->BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup DMA Channel + // + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypeDma; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + 0; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel = + (IsAMiniport ? Miniport->ChannelNumber : + (DmaDescription->DmaChannelSpecified ? + DmaDescription->DmaChannel : AdapterBlock->ChannelNumber)); + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port = + DmaDescription->DmaPort; + Resources->List[0].PartialResourceList.Count++; + + + // + // Make the call + // + + *Status = IoReportResourceUsage( + NULL, + (IsAMiniport ? + Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver : + AdapterBlock->MacHandle->NdisMacInfo->NdisWrapperDriver), + NULL, + 0, + (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject), + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) { + + ExFreePool((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources)); + + } + + if (IsAMiniport) { + + Miniport->Resources = Resources; + + } else { + + AdapterBlock->Resources = Resources; + + } + + // + // Check for conflict. + // + + if (Conflict || (*Status != STATUS_SUCCESS)) { + + + if (Conflict) { + + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG i; + ULONG StringSize; + PUCHAR Place; + PWCH baseFileName; + WCHAR Character; + ULONG Value; + + baseFileName = (IsAMiniport ? + Miniport->MiniportName.Buffer : + AdapterBlock->AdapterName.Buffer); + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; + i < (IsAMiniport ? Miniport->MiniportName.Length : + AdapterBlock->AdapterName.Length) + / sizeof(WCHAR); + i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ((IsAMiniport ? + Miniport->MiniportName.Buffer[i] : + AdapterBlock->AdapterName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) { + + baseFileName = (IsAMiniport ? + &(Miniport->MiniportName.Buffer[++i]) : + &(AdapterBlock->AdapterName.Buffer[++i])); + + } + + } + + StringSize = (IsAMiniport ? + Miniport->MiniportName.MaximumLength : + AdapterBlock->AdapterName.MaximumLength) - + (((ULONG)baseFileName) - + (IsAMiniport ? + ((ULONG)Miniport->MiniportName.Buffer) : + ((ULONG)AdapterBlock->AdapterName.Buffer))); + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + (IsAMiniport ? + Miniport->DeviceObject : + AdapterBlock->DeviceObject), + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize + + 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET) + + StringSize; + + } else { + + Place = ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET); + + errorLogEntry->NumberOfStrings = 0; + + } + + errorLogEntry->NumberOfStrings++; + + // + // Put in dma channel + // + + Value = (IsAMiniport ? Miniport->ChannelNumber : + AdapterBlock->ChannelNumber); + + // + // Convert value + // + // I couldn't think of a better way to do this (with some + // loop). If you find one, plz put it in. + // + + if (Value > 9) { + + switch (Value / 10) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + Value -= 10; + + } + + switch (Value) { + + case 0: + Character = L'0'; + break; + case 1: + Character = L'1'; + break; + case 2: + Character = L'2'; + break; + case 3: + Character = L'3'; + break; + case 4: + Character = L'4'; + break; + case 5: + Character = L'5'; + break; + case 6: + Character = L'6'; + break; + case 7: + Character = L'7'; + break; + case 8: + Character = L'8'; + break; + case 9: + Character = L'9'; + break; + } + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + Place += sizeof(WCHAR); + + Character = UNICODE_NULL; + + memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR)); + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + + } + + *Status = NDIS_STATUS_RESOURCE_CONFLICT; + return; + + } + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Set up the device description; zero it out in case its + // size changes. + // + + RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); + + DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; + DeviceDescription.Master = (IsAMiniport ? Miniport->Master : FALSE); + DeviceDescription.ScatterGather = (IsAMiniport ? Miniport->Master : FALSE); + DeviceDescription.DemandMode = DmaDescription->DemandMode; + DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize; + DeviceDescription.Dma32BitAddresses = (IsAMiniport ? Miniport->Dma32BitAddresses : FALSE); + DeviceDescription.BusNumber = (IsAMiniport ? Miniport->BusNumber : AdapterBlock->BusNumber); + DeviceDescription.DmaChannel = (IsAMiniport ? Miniport->ChannelNumber : + (DmaDescription->DmaChannelSpecified ? + DmaDescription->DmaChannel : AdapterBlock->ChannelNumber)); + DeviceDescription.InterfaceType = (IsAMiniport ? Miniport->BusType : AdapterBlock->BusType); + DeviceDescription.DmaWidth = DmaDescription->DmaWidth; + DeviceDescription.DmaSpeed = DmaDescription->DmaSpeed; + DeviceDescription.MaximumLength = MaximumLength; + DeviceDescription.DmaPort = DmaDescription->DmaPort; + + + MapRegistersNeeded = ((MaximumLength - 2) / PAGE_SIZE) + 2; + + // + // Get the adapter object. + // + + AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed); + + if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersNeeded)) { + + *Status = NDIS_STATUS_RESOURCES; + return; + } + + + // + // Allocate storage for our DMA block. + // + + DmaBlock = (PNDIS_DMA_BLOCK)ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_DMA_BLOCK), 'bdDN'); + + if (DmaBlock == (PNDIS_DMA_BLOCK)NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + + // + // Use this event to tell us when NdisAllocationExecutionRoutine + // has been called. + // + + KeInitializeEvent( + &DmaBlock->AllocationEvent, + NotificationEvent, + FALSE + ); + + // + // We save this to call IoFreeAdapterChannel later. + // + + DmaBlock->SystemAdapterObject = AdapterObject; + + + // + // Now allocate the adapter channel. + // + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NtStatus = IoAllocateAdapterChannel( + AdapterObject, + (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject), + MapRegistersNeeded, + NdisDmaExecutionRoutine, + (PVOID)DmaBlock + ); + + KeLowerIrql(OldIrql); + + if (!NT_SUCCESS(NtStatus)) { + NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus); + ExFreePool (DmaBlock); + *Status = NDIS_STATUS_RESOURCES; + return; + } + + TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000); + + // + // NdisDmaExecutionRoutine will set this event + // when it has been called. + // + + NtStatus = KeWaitForSingleObject( + &DmaBlock->AllocationEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus); + ExFreePool (DmaBlock); + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + KeResetEvent( + &DmaBlock->AllocationEvent + ); + + + // + // We now have the DMA channel allocated, we are done. + // + + DmaBlock->InProgress = FALSE; + + *NdisDmaHandle = (NDIS_HANDLE)DmaBlock; + *Status = NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisFreeDmaChannel( + IN PNDIS_HANDLE NdisDmaHandle + ) + +/*++ + +Routine Description: + + Frees a DMA channel allocated with NdisAllocateDmaChannel. + +Arguments: + + NdisDmaHandle - Handle returned by NdisAllocateDmaChannel, indicating the + DMA channel that is to be freed. + +Return Value: + + None. + +--*/ +{ + + KIRQL OldIrql; + PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + IoFreeAdapterChannel (DmaBlock->SystemAdapterObject); + KeLowerIrql(OldIrql); + + ExFreePool (DmaBlock); + +} + + +VOID +NdisSetupDmaTransfer( + OUT PNDIS_STATUS Status, + IN PNDIS_HANDLE NdisDmaHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + Sets up the host DMA controller for a DMA transfer. The + DMA controller is set up to transfer the specified MDL. + Since we register all DMA channels as non-scatter/gather, + IoMapTransfer will ensure that the entire MDL is + in a single logical piece for transfer. + +Arguments: + + Status - Returns the status of the request. + + NdisDmaHandle - Handle returned by NdisAllocateDmaChannel. + + Buffer - An NDIS_BUFFER which describes the host memory involved in the + transfer. + + Offset - An offset within buffer where the transfer should + start. + + Length - The length of the transfer. VirtualAddress plus Length must not + extend beyond the end of the buffer. + + WriteToDevice - TRUE for a download operation (host to adapter); FALSE + for an upload operation (adapter to host). + +Return Value: + + None. + +--*/ +{ + + PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle; + PHYSICAL_ADDRESS LogicalAddress; + ULONG LengthMapped; + + + // + // Make sure another request is not in progress. + // + + if (DmaBlock->InProgress) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + + DmaBlock->InProgress = TRUE; + + // + // Use IoMapTransfer to set up the transfer. + // + + LengthMapped = Length; + + LogicalAddress = IoMapTransfer( + DmaBlock->SystemAdapterObject, + (PMDL)Buffer, + DmaBlock->MapRegisterBase, + (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset, + &LengthMapped, + WriteToDevice + ); + + if (LengthMapped != Length) { + + // + // Somehow the request could not be mapped competely, + // this should not happen for a non-scatter/gather adapter. + // + + (VOID)IoFlushAdapterBuffers( + DmaBlock->SystemAdapterObject, + (PMDL)Buffer, + DmaBlock->MapRegisterBase, + (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset, + LengthMapped, + WriteToDevice + ); + + DmaBlock->InProgress = FALSE; + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + *Status = NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisCompleteDmaTransfer( + OUT PNDIS_STATUS Status, + IN PNDIS_HANDLE NdisDmaHandle, + IN PNDIS_BUFFER Buffer, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + Completes a previously started DMA transfer. + +Arguments: + + Status - Returns the status of the transfer. + + NdisDmaHandle - Handle returned by NdisAllocateDmaChannel. + + Buffer - An NDIS_BUFFER which was passed to NdisSetupDmaTransfer. + + Offset - the offset passed to NdisSetupDmaTransfer. + + Length - The length passed to NdisSetupDmaTransfer. + + WriteToDevice - TRUE for a download operation (host to adapter); FALSE + for an upload operation (adapter to host). + + +Return Value: + + None. + +--*/ + +{ + + PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle; + BOOLEAN Successful; + + Successful = IoFlushAdapterBuffers( + DmaBlock->SystemAdapterObject, + (PMDL)Buffer, + DmaBlock->MapRegisterBase, + (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset, + Length, + WriteToDevice); + + *Status = (Successful ? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES); + DmaBlock->InProgress = FALSE; + +} + +// +// Requests used by protocol modules +// +// + +VOID +NdisRegisterProtocol( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisProtocolHandle, + IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics, + IN UINT CharacteristicsLength + ) + +/*++ + +Routine Description: + + Register an NDIS protocol. + +Arguments: + + Status - Returns the final status. + NdisProtocolHandle - Returns a handle referring to this protocol. + ProtocolCharacteritics - The NDIS_PROTOCOL_CHARACTERISTICS table. + CharacteristicsLength - The length of ProtocolCharacteristics. + +Return Value: + + None. + +--*/ + +{ + PNDIS_PROTOCOL_BLOCK NewProtP; + UINT MemNeeded; + + // + // Do any initial initialization that may be necessary. Note: this + // routine will notice if this is the second or later call to it. + // + *Status = NdisInitialInit( NULL ); + if (!NT_SUCCESS(*Status)) { + return; + } + + // + // Check that this is an NDIS 3.1 protocol. + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterProtocol\n"); + IF_ERROR_CHK { + if (DbgIsNull(ProtocolCharacteristics->OpenAdapterCompleteHandler)) { + NdisPrint1("RegisterProtocol: OpenAdapterCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->CloseAdapterCompleteHandler)) { + NdisPrint1("RegisterProtocol: CloseAdapterCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->SendCompleteHandler)) { + NdisPrint1("RegisterProtocol: SendCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->TransferDataCompleteHandler)) { + NdisPrint1("RegisterProtocol: TransferDataCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->ResetCompleteHandler)) { + NdisPrint1("RegisterProtocol: ResetCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->RequestCompleteHandler)) { + NdisPrint1("RegisterProtocol: RequestCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->ReceiveHandler)) { + NdisPrint1("RegisterProtocol: ReceiveHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->ReceiveCompleteHandler)) { + NdisPrint1("RegisterProtocol: ReceiveCompleteHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->StatusHandler)) { + NdisPrint1("RegisterProtocol: StatusHandler Null\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolCharacteristics->StatusCompleteHandler)) { + NdisPrint1("RegisterProtocol: StatusCompleteHandler Null\n"); + DbgBreakPoint(); + } + } + + + if (ProtocolCharacteristics->MajorNdisVersion != 3 || + ProtocolCharacteristics->MinorNdisVersion != 0) { + *Status = NDIS_STATUS_BAD_VERSION; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n"); + return; + } + + + // + // Check that CharacteristicsLength is enough. + // + + if (CharacteristicsLength < sizeof(NDIS_PROTOCOL_CHARACTERISTICS)) { + *Status = NDIS_STATUS_BAD_CHARACTERISTICS; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n"); + return; + } + + + // + // Allocate memory for the NDIS protocol block. + // + + MemNeeded = sizeof(NDIS_PROTOCOL_BLOCK); + NewProtP = (PNDIS_PROTOCOL_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bpDN'); + if (NewProtP == (PNDIS_PROTOCOL_BLOCK)NULL) { + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n"); + return; + } + RtlZeroMemory(NewProtP, sizeof(NDIS_PROTOCOL_BLOCK)); + + NewProtP->Length = MemNeeded; + + // + // Copy over the characteristics table. + // + + RtlCopyMemory((PVOID)&NewProtP->ProtocolCharacteristics, + (PVOID)ProtocolCharacteristics, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); + +#if NDISDBG + IF_TRACE(TRACE_IMPT) NdisPrint2(" Protocol: %s\n",ProtocolCharacteristics->Name); +#endif + + // + // No opens for this protocol yet. + // + + NewProtP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL; + + NdisInitializeRef(&NewProtP->Ref); + *NdisProtocolHandle = (NDIS_HANDLE)NewProtP; + *Status = NDIS_STATUS_SUCCESS; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n"); +} + +VOID +NdisDeregisterProtocol( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisProtocolHandle + ) + +/*++ + +Routine Description: + + Deregisters an NDIS protocol. + +Arguments: + + Status - Returns the final status. + NdisProtocolHandle - The handle returned by NdisRegisterProtocol. + +Return Value: + + None. + +Note: + + This will kill all the opens for this protocol. + +--*/ + +{ + + PNDIS_PROTOCOL_BLOCK OldProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle; + + // + // If the protocol is already closing, return. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeregisterProtocol\n"); + NdisPrint2(" Protocol: %wZ\n",&OldProtP->ProtocolCharacteristics.Name); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisProtocolHandle)) { + NdisPrint1("DeregisterProtocol: Null Handle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisProtocolHandle)) { + NdisPrint1("DeregisterProtocol: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + if (!NdisCloseRef(&OldProtP->Ref)) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n"); + return; + } + + + // + // Kill all the opens for this protocol. + // + + while (OldProtP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) { + + // + // This removes it from the protocol's OpenQueue etc. + // + + NdisKillOpenAndNotifyProtocol(OldProtP->OpenQueue); + } + + NdisDereferenceProtocol(OldProtP); + + *Status = NDIS_STATUS_SUCCESS; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n"); +} + + +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; + + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + + // + // Find protocol binding context and get associated open for it. + // + Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext); + ASSERT(Open != NULL); + + Status = + (Open->PostNt31ReceiveHandler) ( + ProtocolBindingContext, + MacReceiveContext, + HeaderBuffer, + HeaderBufferSize, + LookaheadBuffer, + LookaheadBufferSize, + PacketSize); + + KeLowerIrql( oldIrql ); + return Status; +} + + +VOID +NdisMacReceiveCompleteHandler( + IN NDIS_HANDLE ProtocolBindingContext + ) +{ + PNDIS_OPEN_BLOCK Open; + KIRQL oldIrql; + KeRaiseIrql( DISPATCH_LEVEL, &oldIrql ); + + // + // Find protocol binding context and get associated open for it. + // + Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext); + ASSERT(Open != NULL); + + (Open->PostNt31ReceiveCompleteHandler) ( + ProtocolBindingContext + ); + KeLowerIrql( oldIrql ); + return; +} + +PNDIS_OPEN_BLOCK +GetOpenBlockFromProtocolBindingContext( + IN NDIS_HANDLE ProtocolBindingContext + ) +{ + PNDIS_OPEN_BLOCK TmpOpen; + PNDIS_OPEN_BLOCK PrvOpen = NULL; + + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + TmpOpen = GlobalOpenList; + + while (TmpOpen != NULL) { + + if (TmpOpen->ProtocolBindingContext == ProtocolBindingContext) { + + if (TmpOpen != GlobalOpenList) { + + // + // Put this one at the front of the list + // + + PrvOpen->NextGlobalOpen = TmpOpen->NextGlobalOpen; + TmpOpen->NextGlobalOpen = GlobalOpenList; + GlobalOpenList = TmpOpen; + + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + return(TmpOpen); + + } + + PrvOpen = TmpOpen; + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + return((PNDIS_OPEN_BLOCK)NULL); + +} + +VOID +MiniportOpenAdapter( + OUT PNDIS_STATUS Status, + OUT PNDIS_STATUS OpenErrorStatus, + OUT PNDIS_HANDLE NdisBindingHandle, + IN NDIS_HANDLE NdisProtocolHandle, + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_STRING AdapterName, + IN UINT OpenOptions, + IN PSTRING AddressingInformation, + IN PNDIS_MINIPORT_BLOCK Miniport, + IN PNDIS_OPEN_BLOCK NewOpenP, + IN PFILE_OBJECT FileObject, + IN BOOLEAN UsingEncapsulation + ) +/*++ + +Routine Description: + + This routine handles opening a miniport either directly from NdisOpenAdapter() + of from our deferred processing routine if the open had to pend. + + NOTE: Must be called with spin lock held. + NOTE: Must be called with lock acquired flag set. + +Arguments: + +Return Value: + + None. + +--*/ +{ + PNDIS_M_OPEN_BLOCK MiniportOpen; + PNDIS_MAC_BLOCK FakeMac; + BOOLEAN FilterOpen; + PNDIS_PROTOCOL_BLOCK TmpProtP; + + ASSERT( MINIPORT_LOCK_ACQUIRED(Miniport) ); + + if (!NdisReferenceMiniport(Miniport)) { + + // + // The adapter is closing. + // + + ObDereferenceObject((PVOID)FileObject); + ExFreePool((PVOID)NewOpenP); + + *Status = NDIS_STATUS_CLOSING; + + return; + } + + // + // Increment the protocol's reference count. + // + + TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle; + + if (!NdisReferenceProtocol(TmpProtP)) { + + // + // The protocol is closing. + // + + NdisDereferenceMiniport(Miniport); + ObDereferenceObject((PVOID)FileObject); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_CLOSING; + return; + } + + + // + // Now allocate a complete set of MAC structures for the protocol + // and set them up to transfer to the Miniport handler routines. + // + + if (Miniport->DriverHandle->FakeMac == NULL) { + + FakeMac = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool, + sizeof(NDIS_MAC_BLOCK), + ' DN' + ); + + if (FakeMac == NULL) { + ObDereferenceObject((PVOID)FileObject); + NdisDereferenceMiniport(Miniport); + NdisDereferenceProtocol(TmpProtP); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_RESOURCES; + return; + } + + RtlZeroMemory(FakeMac, sizeof(NDIS_MAC_BLOCK)); + Miniport->DriverHandle->FakeMac = FakeMac; + FakeMac->MacCharacteristics.OpenAdapterHandler = NULL; + FakeMac->MacCharacteristics.CloseAdapterHandler = NULL; + FakeMac->MacCharacteristics.SendHandler = NdisMSend; + FakeMac->MacCharacteristics.ResetHandler = NdisMReset; + FakeMac->MacCharacteristics.RequestHandler = NdisMRequest; + FakeMac->MacCharacteristics.QueryGlobalStatisticsHandler = NULL; + FakeMac->MacCharacteristics.UnloadMacHandler = NULL; + FakeMac->MacCharacteristics.AddAdapterHandler = NULL; + FakeMac->MacCharacteristics.RemoveAdapterHandler = NULL; + + // + // If transfer data calls don't pend then we'll use the faster + // NdisMTransferDataSync(). + // + + if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) { + FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferDataSync; + } else { + FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferData; + } + + // + // Keep the SendHandler the same for WAN miniports + // + + if (Miniport->MediaType == NdisMediumWan) { + + FakeMac->MacCharacteristics.SendHandler = + (PVOID)Miniport->DriverHandle->MiniportCharacteristics.SendHandler; + } + + } else { + + FakeMac = Miniport->DriverHandle->FakeMac; + + } + + // + // Allocate an open within the Miniport context + // + MiniportOpen = (PNDIS_M_OPEN_BLOCK)ExAllocatePoolWithTag(NonPagedPool, + sizeof(NDIS_M_OPEN_BLOCK), + ' DN' + ); + + if (MiniportOpen == (PNDIS_M_OPEN_BLOCK)NULL) { + ObDereferenceObject((PVOID)FileObject); + NdisDereferenceMiniport(Miniport); + NdisDereferenceProtocol(TmpProtP); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_RESOURCES; + return; + } + + NdisZeroMemory(MiniportOpen, sizeof(NDIS_M_OPEN_BLOCK)); + + MiniportOpen->DriverHandle = Miniport->DriverHandle; + MiniportOpen->MiniportHandle = Miniport; + MiniportOpen->ProtocolHandle = TmpProtP; + MiniportOpen->FakeOpen = NewOpenP; + MiniportOpen->ProtocolBindingContext = ProtocolBindingContext; + MiniportOpen->MiniportAdapterContext = Miniport->MiniportAdapterContext; + MiniportOpen->FileObject = FileObject; + MiniportOpen->Closing = FALSE; + MiniportOpen->CloseRequestHandle = 0; + MiniportOpen->CurrentLookahead = Miniport->CurrentLookahead; + + NdisAllocateSpinLock(&(MiniportOpen->SpinLock)); + + MiniportOpen->References = 1; + MiniportOpen->UsingEthEncapsulation = UsingEncapsulation; + MiniportOpen->SendHandler = + Miniport->DriverHandle->MiniportCharacteristics.SendHandler; + MiniportOpen->TransferDataHandler = + Miniport->DriverHandle->MiniportCharacteristics.TransferDataHandler; + MiniportOpen->SendCompleteHandler = + TmpProtP->ProtocolCharacteristics.SendCompleteHandler; + MiniportOpen->TransferDataCompleteHandler = + TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler; + MiniportOpen->ReceiveHandler = + TmpProtP->ProtocolCharacteristics.ReceiveHandler; + MiniportOpen->ReceiveCompleteHandler = + TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler; + + // + // Set up the elements of the open structure. + // + + NdisAllocateSpinLock(&NewOpenP->SpinLock); + NewOpenP->Closing = FALSE; + + NewOpenP->AdapterHandle = (NDIS_HANDLE) Miniport; + NewOpenP->ProtocolHandle = TmpProtP; + NewOpenP->ProtocolBindingContext = ProtocolBindingContext; + NewOpenP->MacBindingHandle = (NDIS_HANDLE)MiniportOpen; + + // + // for speed, instead of having to use AdapterHandle->MacHandle + // + NewOpenP->MacHandle = (NDIS_HANDLE)FakeMac; + + // + // for even more speed.... + // + + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + NewOpenP->TransferDataHandler = NdisMArcTransferData; + + } else { + + if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) { + NewOpenP->TransferDataHandler = NdisMTransferDataSync; + } else { + NewOpenP->TransferDataHandler = NdisMTransferData; + } + } + + NewOpenP->SendHandler = NdisMSend; + + // + // For WAN miniports, the send handler is different + // + + if ( Miniport->MediaType == NdisMediumWan ) { + + NewOpenP->SendHandler = (PVOID)NdisMWanSend; + } + + NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler; + NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler; + NewOpenP->ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler; + NewOpenP->ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler; + NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler; + NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler; + + // + // Save a pointer to the file object in the open... + // + + NewOpenP->FileObject = FileObject; + + // + // ...and a pointer to the open in the file object. + // + + FileObject->FsContext = (PVOID)NewOpenP; + + *NdisBindingHandle = (NDIS_HANDLE)NewOpenP; + + // + // Insert the open into the filter package + // + + switch (Miniport->MediaType) { + + case NdisMediumArcnet878_2: + + if ( !UsingEncapsulation ) { + + FilterOpen = ArcNoteFilterOpenAdapter( + Miniport->ArcDB, + MiniportOpen, + (NDIS_HANDLE)NewOpenP, + &MiniportOpen->FilterHandle + ); + + break; + } + + // + // If we're using ethernet encapsulation then + // we simply fall through to the ethernet stuff. + // + + case NdisMedium802_3: + + FilterOpen = EthNoteFilterOpenAdapter( + Miniport->EthDB, + MiniportOpen, + (NDIS_HANDLE)NewOpenP, + &MiniportOpen->FilterHandle + ); + break; + + case NdisMedium802_5: + + FilterOpen = TrNoteFilterOpenAdapter( + Miniport->TrDB, + MiniportOpen, + (NDIS_HANDLE)NewOpenP, + &MiniportOpen->FilterHandle + ); + break; + + case NdisMediumFddi: + + FilterOpen = FddiNoteFilterOpenAdapter( + Miniport->FddiDB, + MiniportOpen, + (NDIS_HANDLE)NewOpenP, + &MiniportOpen->FilterHandle + ); + break; + + + case NdisMediumWan: + // + // Bogus non-NULL value + // + + FilterOpen = 1; + break; + } + + // + // Check for an open filter failure. + // + + if ( !FilterOpen ) { + + // + // Something went wrong, clean up and exit. + // + + ObDereferenceObject((PVOID)FileObject); + NdisDereferenceMiniport(Miniport); + NdisDereferenceProtocol(TmpProtP); + ExFreePool((PVOID)MiniportOpen); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_OPEN_FAILED; + return; + + } + + NdisQueueOpenOnProtocol(NewOpenP, TmpProtP); + + // + // Everything has been filled in. Synchronize access to the + // adapter block and link the new open adapter in. + // + + MiniportOpen->MiniportNextOpen = Miniport->OpenQueue; + Miniport->OpenQueue = MiniportOpen; + + // + // NOTE: This must be called at DPC_LEVEL, which it is. + // + MiniportAdjustMaximumLookahead(Miniport); + + *Status = NDIS_STATUS_SUCCESS; +} + + +VOID +MiniportFinishPendingOpens( + PNDIS_MINIPORT_BLOCK Miniport + ) +/*++ + +Routine Description: + + Handles any pending NdisOpenAdapter() calls for miniports. + + NOTE: Must be called with spin lock held. + + NOTE: Must be called with lock acquired flag set. + +Arguments: + + Miniport. + +Return Value: + + None. + +--*/ + +{ + PMINIPORT_PENDING_OPEN MiniportPendingOpen; + NDIS_STATUS Status; + NDIS_STATUS OpenErrorStatus; + + while( Miniport->FirstPendingOpen != NULL ) { + + MiniportPendingOpen = Miniport->FirstPendingOpen; + + // + // Do the open again. + // + + MiniportOpenAdapter( + &Status, + &OpenErrorStatus, + MiniportPendingOpen->NdisBindingHandle, + MiniportPendingOpen->NdisProtocolHandle, + MiniportPendingOpen->ProtocolBindingContext, + MiniportPendingOpen->AdapterName, + MiniportPendingOpen->OpenOptions, + MiniportPendingOpen->AddressingInformation, + MiniportPendingOpen->Miniport, + MiniportPendingOpen->NewOpenP, + MiniportPendingOpen->FileObject, + MiniportPendingOpen->UsingEncapsulation + ); + + // + // If the open didn't pend then call the NdisCompleteOpenAdapter(), + // + + if ( Status != NDIS_STATUS_PENDING ) { + + PNDIS_OPEN_BLOCK OpenP = MiniportPendingOpen->NewOpenP; + + (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) ( + OpenP->ProtocolBindingContext, + Status, + OpenErrorStatus + ); + } + + // + // Get the next pending open. + // + + Miniport->FirstPendingOpen = MiniportPendingOpen->NextPendingOpen; + + // + // We're done with this pending open context. + // + + NdisFreeMemory( + MiniportPendingOpen, + sizeof(MINIPORT_PENDING_OPEN), + 0 + ); + + } +} + + + +UCHAR NdisInternalEaName[4] = "NDIS"; +UCHAR NdisInternalEaValue[8] = "INTERNAL"; + +VOID +NdisOpenAdapter( + OUT PNDIS_STATUS Status, + OUT PNDIS_STATUS OpenErrorStatus, + OUT PNDIS_HANDLE NdisBindingHandle, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE NdisProtocolHandle, + IN NDIS_HANDLE ProtocolBindingContext, + IN PNDIS_STRING AdapterName, + IN UINT OpenOptions, + IN PSTRING AddressingInformation OPTIONAL + ) + +/*++ + +Routine Description: + + Opens a connection between a protocol and an adapter (MAC). + +Arguments: + + Status - Returns the final status. + NdisBindingHandle - Returns a handle referring to this open. + SelectedMediumIndex - Index in MediumArray of the medium type that + the MAC wishes to be viewed as. + MediumArray - Array of medium types which a protocol supports. + MediumArraySize - Number of elements in MediumArray. + NdisProtocolHandle - The handle returned by NdisRegisterProtocol. + ProtocolBindingContext - A context for indications. + AdapterName - The name of the adapter to open. + OpenOptions - bit mask. + AddressingInformation - Information passed to MacOpenAdapter. + +Return Value: + + None. + +Note: + + This function opens the adapter which will cause an IRP_MJ_CREATE + to be sent to the adapter, which is ignored. However, after that we + can access the file object for the open, and fill it in as + appropriate. The work is done here rather than in the IRP_MJ_CREATE + handler because this avoids having to pass the parameters to + NdisOpenAdapter through to the adapter. + +--*/ + +{ + HANDLE FileHandle; + OBJECT_ATTRIBUTES ObjectAttr; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + PNDIS_OPEN_BLOCK NewOpenP; + PNDIS_PROTOCOL_BLOCK TmpProtP; + PNDIS_ADAPTER_BLOCK TmpAdaptP; + NDIS_STATUS OpenStatus; + NTSTATUS NtOpenStatus; + IO_STATUS_BLOCK IoStatus; + PFILE_FULL_EA_INFORMATION OpenEa; + ULONG OpenEaLength; + BOOLEAN UsingEncapsulation; + KIRQL OldIrql; + BOOLEAN LocalLock; + + // + // Allocate memory for the NDIS open block. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisOpenAdapter\n"); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisProtocolHandle)) { + NdisPrint1("OpenAdapter: Null ProtocolHandle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisProtocolHandle)) { + NdisPrint1("OpenAdapter: ProtocolHandle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(ProtocolBindingContext)) { + NdisPrint1("OpenAdapter: Null Context\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(ProtocolBindingContext)) { + NdisPrint1("OpenAdapter: Context not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + NewOpenP = (PNDIS_OPEN_BLOCK) ExAllocatePoolWithTag(NonPagedPool, + sizeof(NDIS_OPEN_BLOCK), + 'boDN' + ); + + if (NewOpenP == (PNDIS_OPEN_BLOCK)NULL) { + + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + + return; + } + + RtlZeroMemory(NewOpenP, sizeof(NDIS_OPEN_BLOCK)); + + OpenEaLength = sizeof(FILE_FULL_EA_INFORMATION) + + sizeof(NdisInternalEaName) + + sizeof(NdisInternalEaValue); + + OpenEa = ExAllocatePoolWithTag (NonPagedPool, OpenEaLength, ' DN'); + + if (OpenEa == NULL) { + ExFreePool (NewOpenP); + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; + } + + OpenEa->NextEntryOffset = 0; + OpenEa->Flags = 0; + OpenEa->EaNameLength = sizeof(NdisInternalEaName); + OpenEa->EaValueLength = sizeof(NdisInternalEaValue); + + RtlCopyMemory( + OpenEa->EaName, + NdisInternalEaName, + sizeof(NdisInternalEaName) + ); + + RtlCopyMemory( + &OpenEa->EaName[OpenEa->EaNameLength+1], + NdisInternalEaValue, + sizeof(NdisInternalEaValue) + ); + + + // + // Obtain a handle to the driver's file object. + // + + InitializeObjectAttributes( + &ObjectAttr, + AdapterName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + + NtOpenStatus = ZwCreateFile(&FileHandle, + FILE_READ_DATA | FILE_WRITE_DATA, + &ObjectAttr, + &IoStatus, + (PLARGE_INTEGER) NULL, // allocation size + 0L, // file attributes + FILE_SHARE_READ | FILE_SHARE_WRITE, // share access + FILE_OPEN, // create disposition + 0, // create options + OpenEa, + OpenEaLength); + + + ExFreePool(OpenEa); + + if (NtOpenStatus != STATUS_SUCCESS) { + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_ADAPTER_NOT_FOUND; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; + } + + + // + // Convert the file handle into a pointer to the adapter's + // file object. + // + + ObReferenceObjectByHandle(FileHandle, + 0, + NULL, + KernelMode, + (PVOID *) &FileObject, + NULL + ); + + // + // Close the file handle, now that we have the object reference. + // + + ZwClose(FileHandle); + + // + // From the file object, obtain the device object. + // + + DeviceObject = IoGetRelatedDeviceObject(FileObject); + + + // + // Increment the adapter's reference count. + // + + TmpAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); + + // + // Check if this is a Miniport or mac + // + + if (TmpAdaptP->DeviceObject != DeviceObject) { + + // + // It is a Miniport + // + + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)TmpAdaptP; + ULONG i; + + UsingEncapsulation = FALSE; + + // + // Select the medium to use + // + + for (i = 0; i < MediumArraySize; i++){ + + if (MediumArray[i] == Miniport->MediaType) { + + break; + + } + + } + + if (i == MediumArraySize){ + + // + // Check for ethernet encapsulation on Arcnet as + // a possible combination. + // + if (Miniport->MediaType == NdisMediumArcnet878_2) { + + for (i = 0; i < MediumArraySize; i++){ + + if (MediumArray[i] == NdisMedium802_3) { + break; + } + } + + if (i == MediumArraySize) { + + *Status = NDIS_STATUS_UNSUPPORTED_MEDIA; + return; + + } + + // + // encapsulated ethernet, so we add in the wrapper's + // ability to support (emulate) the multicast stuff + // + + Miniport->SupportedPacketFilters |= (NDIS_PACKET_TYPE_MULTICAST | + NDIS_PACKET_TYPE_ALL_MULTICAST); + + UsingEncapsulation = TRUE; + + } else { + + *Status = NDIS_STATUS_UNSUPPORTED_MEDIA; + return; + + } + + } + + *SelectedMediumIndex = i; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock); + + // + // Lock the miniport. If the lock fails, then + // we must pend this open and try it later. + // + + LOCK_MINIPORT(Miniport, LocalLock); + + if ( LocalLock ) { + + MiniportOpenAdapter( + Status, + OpenErrorStatus, + NdisBindingHandle, + NdisProtocolHandle, + ProtocolBindingContext, + AdapterName, + OpenOptions, + AddressingInformation, + Miniport, + NewOpenP, + FileObject, + UsingEncapsulation + ); + + } else { + + PMINIPORT_PENDING_OPEN MiniportPendingOpen; + + // + // Allocate some space for this pending structure. + // We free in after we call NdisOpenComplete. + // + + *Status = NdisAllocateMemory( + (PVOID *) &MiniportPendingOpen, + sizeof(MINIPORT_PENDING_OPEN), + 0, + HighestAcceptableMax + ); + + if ( *Status == NDIS_STATUS_SUCCESS ) { + + // + // Save off the parameters for this open so we can + // do the actual NdisOpenAdapter() later on. + // + + MiniportPendingOpen->NextPendingOpen = NULL; + MiniportPendingOpen->NdisBindingHandle = NdisBindingHandle; + MiniportPendingOpen->NdisProtocolHandle = NdisProtocolHandle; + MiniportPendingOpen->ProtocolBindingContext = ProtocolBindingContext; + MiniportPendingOpen->AdapterName = AdapterName; + MiniportPendingOpen->OpenOptions = OpenOptions; + MiniportPendingOpen->AddressingInformation = AddressingInformation; + MiniportPendingOpen->Miniport = Miniport; + MiniportPendingOpen->NewOpenP = NewOpenP; + MiniportPendingOpen->FileObject = FileObject; + MiniportPendingOpen->UsingEncapsulation = UsingEncapsulation; + + if ( Miniport->FirstPendingOpen == NULL ) { + + Miniport->FirstPendingOpen = MiniportPendingOpen; + + } else { + + Miniport->LastPendingOpen->NextPendingOpen = MiniportPendingOpen; + } + + Miniport->LastPendingOpen = MiniportPendingOpen; + + // + // Make sure MiniportProcessDeferred() completes the open. + // + + *Status = NDIS_STATUS_PENDING; + + Miniport->ProcessOddDeferredStuff = TRUE; + + } else { + + ObDereferenceObject((PVOID) FileObject); + ExFreePool((PVOID) NewOpenP); + } + } + + // + // Unlock the miniport. + // + + UNLOCK_MINIPORT(Miniport, LocalLock); + + RELEASE_SPIN_LOCK_DPC(&Miniport->Lock); + KeLowerIrql(OldIrql); + + return; + } + + // + // It is a mac + // + + IF_TRACE(TRACE_IMPT) NdisPrint2("openadapter: adaptername=%s\n",TmpAdaptP->AdapterName.Buffer); + if (!NdisReferenceAdapter(TmpAdaptP)) { + + // + // The adapter is closing. + // + + ObDereferenceObject((PVOID)FileObject); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_CLOSING; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; + } + + // + // Increment the protocol's reference count. + // + + TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle; + if (!NdisReferenceProtocol(TmpProtP)) { + + // + // The protocol is closing. + // + + NdisDereferenceAdapter(TmpAdaptP); + ObDereferenceObject((PVOID)FileObject); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_CLOSING; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; + } + + + // + // Set up the elements of the open structure. + // + + NdisAllocateSpinLock(&NewOpenP->SpinLock); + NewOpenP->Closing = FALSE; + + NewOpenP->AdapterHandle = TmpAdaptP; + NewOpenP->ProtocolHandle = TmpProtP; + + // + // for speed, instead of having to use AdapterHandle->MacHandle + // + NewOpenP->MacHandle = TmpAdaptP->MacHandle; + + // + // for even more speed.... + // + + NewOpenP->SendHandler = TmpAdaptP->MacHandle->MacCharacteristics.SendHandler; + NewOpenP->TransferDataHandler = TmpAdaptP->MacHandle->MacCharacteristics.TransferDataHandler; + + NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler; + NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler; + + // + // Now we have to fake some stuff to get all indications to happen + // at DPC_LEVEL. What we do is start the pointer at an NDIS function + // which will guarantee that it occurs. + // + // Then, by extending the OPEN structure and adding the real handlers + // at the end we can use these for drivers compiled with this header. + // + NewOpenP->ProtocolBindingContext = ProtocolBindingContext; + NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler; + NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler; + NewOpenP->ReceiveHandler = NdisMacReceiveHandler; + NewOpenP->ReceiveCompleteHandler = NdisMacReceiveCompleteHandler; + + // + // Patch the open into the global list of macs + // + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + NewOpenP->NextGlobalOpen = GlobalOpenList; + GlobalOpenList = NewOpenP; + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + + // + // Save a pointer to the file object in the open... + // + + NewOpenP->FileObject = FileObject; + + // + // ...and a pointer to the open in the file object. + // + + FileObject->FsContext = (PVOID)NewOpenP; + + + *NdisBindingHandle = (NDIS_HANDLE)NewOpenP; + + + // + // Call MacOpenAdapter, see what we shall see... + // + + OpenStatus = (TmpAdaptP->MacHandle->MacCharacteristics.OpenAdapterHandler) ( + OpenErrorStatus, + &NewOpenP->MacBindingHandle, + SelectedMediumIndex, + MediumArray, + MediumArraySize, + (NDIS_HANDLE)NewOpenP, + TmpAdaptP->MacAdapterContext, + OpenOptions, + AddressingInformation + ); + + if ((OpenStatus == NDIS_STATUS_SUCCESS) && NdisFinishOpen(NewOpenP)) { + + *Status = NDIS_STATUS_SUCCESS; + + } else if (OpenStatus == NDIS_STATUS_PENDING) { + + *Status = NDIS_STATUS_PENDING; + + } else { + + PNDIS_OPEN_BLOCK TmpOpen; + + // + // Something went wrong, clean up and exit. + // + + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + if (GlobalOpenList == NewOpenP) { + + GlobalOpenList = NewOpenP->NextGlobalOpen; + + } else { + + TmpOpen = GlobalOpenList; + + while (TmpOpen->NextGlobalOpen != NewOpenP) { + + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + TmpOpen->NextGlobalOpen = NewOpenP->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + ObDereferenceObject((PVOID)FileObject); + NdisDereferenceAdapter(TmpAdaptP); + NdisDereferenceProtocol(TmpProtP); + ExFreePool((PVOID)NewOpenP); + *Status = NDIS_STATUS_OPEN_FAILED; + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n"); + return; +} + + +VOID +NdisCloseAdapter( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisBindingHandle + ) + +/*++ + +Routine Description: + + Closes a connection between a protocol and an adapter (MAC). + +Arguments: + + Status - Returns the final status. + NdisBindingHandle - The handle returned by NdisOpenAdapter. + +Return Value: + + None. + +--*/ + +{ + PNDIS_OPEN_BLOCK OpenP = ((PNDIS_OPEN_BLOCK)NdisBindingHandle); + + if (OpenP->AdapterHandle->DeviceObject == NULL) { + + // + // This is a Miniport + // This returns TRUE if it finished synchronously. + // + + if (NdisMKillOpen(OpenP)) { + + *Status = NDIS_STATUS_SUCCESS; + + } else { + + *Status = NDIS_STATUS_PENDING; // will complete later + + } + return; + } + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisCloseAdapter\n"); + NdisPrint3(" Protocol %wZ is closing Adapter %wZ\n", + &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name, + &(OpenP->AdapterHandle)->AdapterName); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisBindingHandle)) { + NdisPrint1("OpenAdapter: Null BindingHandle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisBindingHandle)) { + NdisPrint1("OpenAdapter: BindingHandle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + // + // This returns TRUE if it finished synchronously. + // + + if (NdisKillOpen(OpenP)) { + + *Status = NDIS_STATUS_SUCCESS; + + } else { + + *Status = NDIS_STATUS_PENDING; // will complete later + + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisCloseAdapter\n"); +#undef OpenP +} + + +// +// Requests Used by MAC Drivers +// +// + + + +VOID +NdisInitializeWrapper( + OUT PNDIS_HANDLE NdisWrapperHandle, + IN PVOID SystemSpecific1, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) + +/*++ + +Routine Description: + + Called at the beginning of every MAC's initialization routine. + +Arguments: + + NdisWrapperHandle - A MAC specific handle for the wrapper. + + SystemSpecific1, a pointer to the driver object for the MAC. + SystemSpecific2, a PUNICODE_STRING containing the location of + the registry subtree for this driver. + SystemSpecific3, unused on NT. + +Return Value: + + None. + +--*/ + +{ + NDIS_STATUS Status; + + PNDIS_WRAPPER_HANDLE NdisMacInfo; + + UNREFERENCED_PARAMETER (SystemSpecific3); + + + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisInitializeWrapper\n"); + + Status = NdisAllocateMemory( + (PVOID*) (NdisWrapperHandle), + sizeof(NDIS_WRAPPER_HANDLE), + 0, + HighestAcceptableMax + ); + + if ( Status == NDIS_STATUS_SUCCESS ) { + + NdisMacInfo = (PNDIS_WRAPPER_HANDLE) (*NdisWrapperHandle); + NdisMacInfo->NdisWrapperDriver = (PDRIVER_OBJECT) SystemSpecific1; + NdisMacInfo->NdisWrapperConfigurationHandle = (HANDLE) SystemSpecific2; + + } else { + + *NdisWrapperHandle = NULL; + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisInitializeWrapper\n"); +} + +VOID +NdisTerminateWrapper( + IN NDIS_HANDLE NdisWrapperHandle, + IN PVOID SystemSpecific + ) + +/*++ + +Routine Description: + + Called at the end of every MAC's termination routine. + +Arguments: + + NdisWrapperHandle - The handle returned from NdisInitializeWrapper. + + SystemSpecific - No defined value. + +Return Value: + + None. + +--*/ + +{ + PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle; + + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisTerminateWrapper\n"); + + UNREFERENCED_PARAMETER(SystemSpecific); + + + if (NdisMacInfo != NULL) { + + NdisFreeMemory(NdisMacInfo, sizeof(NDIS_WRAPPER_HANDLE), 0); + + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisTerminateWrapper\n"); + + return; +} + +VOID +NdisRegisterMac( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE NdisWrapperHandle, + IN NDIS_HANDLE MacMacContext, + IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics, + IN UINT CharacteristicsLength + ) + +/*++ + +Routine Description: + + Register an NDIS MAC. + +Arguments: + + Status - Returns the final status. + NdisMacHandle - Returns a handle referring to this MAC. + NdisWrapperHandle - Handle returned by NdisInitializeWrapper. + MacMacContext - Context for calling MACUnloadMac and MACAddAdapter. + MacCharacteritics - The NDIS_MAC_CHARACTERISTICS table. + CharacteristicsLength - The length of MacCharacteristics. + +Return Value: + + None. + +--*/ + +{ + PNDIS_MAC_BLOCK NewMacP; + PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle); + UINT MemNeeded; + + // + // check that this is an NDIS 3.0 MAC. + // + IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterMac\n"); + + // + // Do any initial initialization that may be necessary. Note: this + // routine will notice if this is the second or later call to it. + // + *Status = NdisInitialInit( NdisMacInfo->NdisWrapperDriver ); + if (!NT_SUCCESS(*Status)) { + return; + } + + *NdisMacHandle = (NDIS_HANDLE)NULL; + + if (NdisMacInfo == NULL) { + + *Status = NDIS_STATUS_FAILURE; + + return; + + } + + IF_ERROR_CHK { + if (DbgIsNull(MacCharacteristics->OpenAdapterHandler)) { + NdisPrint1("RegisterMac: Null OpenAdapterHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->CloseAdapterHandler)) { + NdisPrint1("RegisterMac: Null CloseAdapterHandler \n"); + DbgBreakPoint(); + } + + if (DbgIsNull(MacCharacteristics->SendHandler)) { + NdisPrint1("RegisterMac: Null SendHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->TransferDataHandler)) { + NdisPrint1("RegisterMac: Null TransferDataHandler \n"); + DbgBreakPoint(); + } + + if (DbgIsNull(MacCharacteristics->ResetHandler)) { + NdisPrint1("RegisterMac: Null ResetHandler \n"); + DbgBreakPoint(); + } + + if (DbgIsNull(MacCharacteristics->RequestHandler)) { + NdisPrint1("RegisterMac: Null RequestHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->QueryGlobalStatisticsHandler)) { + NdisPrint1("RegisterMac: Null QueryGlobalStatisticsHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->UnloadMacHandler)) { + NdisPrint1("RegisterMac: Null UnloadMacHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->AddAdapterHandler)) { + NdisPrint1("RegisterMac: Null AddAdapterHandler \n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacCharacteristics->RemoveAdapterHandler)) { + NdisPrint1("RegisterMac: Null RemoveAdapterHandler \n"); + DbgBreakPoint(); + } + } + + if (MacCharacteristics->MajorNdisVersion != 3 || + MacCharacteristics->MinorNdisVersion != 0) { + *Status = NDIS_STATUS_BAD_VERSION; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n"); + return; + } + + // + // Check that CharacteristicsLength is enough. + // + + if (CharacteristicsLength < sizeof(NDIS_MAC_CHARACTERISTICS)) { + NdisPrint3("char len = %d < %d\n",CharacteristicsLength, + sizeof(NDIS_MAC_CHARACTERISTICS)); + + *Status = NDIS_STATUS_BAD_CHARACTERISTICS; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n"); + return; + } + + // + // Allocate memory for the NDIS MAC block. + // + MemNeeded = sizeof(NDIS_MAC_BLOCK) + MacCharacteristics->Name.Length; + NewMacP = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bmDN'); + if (NewMacP == (PNDIS_MAC_BLOCK)NULL) { + *Status = NDIS_STATUS_RESOURCES; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n"); + return; + } + RtlZeroMemory(NewMacP, sizeof(NDIS_MAC_BLOCK)); + + NewMacP->Length = MemNeeded; + + // + // Copy over the characteristics table. + // + + RtlCopyMemory((PVOID)&NewMacP->MacCharacteristics, + (PVOID)MacCharacteristics, sizeof(NDIS_MAC_CHARACTERISTICS)); + + // + // Move buffer pointer to correct location (extra space at the end of + // the characteristics table) + // + + (NewMacP->MacCharacteristics).Name.Buffer = + (PWSTR)((PUCHAR)NewMacP + sizeof(NDIS_MAC_BLOCK)); + + + // + // Copy String over. + // + + RtlCopyMemory( + (NewMacP->MacCharacteristics).Name.Buffer, + (MacCharacteristics->Name).Buffer, + (MacCharacteristics->Name).Length + ); + + // + // No adapters yet registered for this MAC. + // + + NewMacP->AdapterQueue = (PNDIS_ADAPTER_BLOCK)NULL; + + NewMacP->MacMacContext = MacMacContext; + + // + // Set up unload handler + // + + NdisMacInfo->NdisWrapperDriver->DriverUnload = NdisUnload; + + // + // Set up shutdown handler + // + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = NdisShutdown; + + // + // Set up the handlers for this driver (they all do nothing). + // + + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = NdisCreateIrpHandler; + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisDeviceControlIrpHandler; + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = NdisSuccessIrpHandler; + NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = NdisCloseIrpHandler; + + NewMacP->NdisMacInfo = NdisMacInfo; + + // + // Put MAC on global list. + // + + ACQUIRE_SPIN_LOCK(&NdisMacListLock); + + NewMacP->NextMac = NdisMacList; + NdisMacList = NewMacP; + + RELEASE_SPIN_LOCK(&NdisMacListLock); + + // + // Use this event to tell us when all adapters are removed from the mac + // during an unload + // + + KeInitializeEvent( + &NewMacP->AdaptersRemovedEvent, + NotificationEvent, + FALSE + ); + + NewMacP->Unloading = FALSE; + + NdisInitializeRef(&NewMacP->Ref); + + *NdisMacHandle = (NDIS_HANDLE)NewMacP; + + NdisInitReferencePackage(); + + if (NdisMacInfo->NdisWrapperConfigurationHandle) { + + if (NdisCallDriverAddAdapter(NewMacP) == NDIS_STATUS_SUCCESS) { + *Status = NDIS_STATUS_SUCCESS; + } else { + *Status = NDIS_STATUS_FAILURE; + NdisDereferenceMac(NewMacP); + } + } else { + *Status = NDIS_STATUS_FAILURE; + } + + NdisInitDereferencePackage(); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n"); +} + + +VOID +NdisDeregisterMac( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE NdisMacHandle + ) + +/*++ + +Routine Description: + + Deregisters an NDIS MAC. + +Arguments: + + Status - Returns the status of the request. + NdisMacHandle - The handle returned by NdisRegisterMac. + +Return Value: + + None. + +--*/ + +{ + + PNDIS_MAC_BLOCK OldMacP = (PNDIS_MAC_BLOCK)NdisMacHandle; + + // + // If the MAC is already closing, return. + // + + *Status = NDIS_STATUS_SUCCESS; + + if (OldMacP == NULL) { + + return; + } + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeregisterMac\n"); + NdisPrint2(" Mac %wZ being deregistered\n",&OldMacP->MacCharacteristics.Name); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisMacHandle)) { + NdisPrint1("DeregisterMac: Null Handle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisMacHandle)) { + NdisPrint1("DeregisterMac: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + if (!NdisCloseRef(&OldMacP->Ref)) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n"); + return; + } + + + ASSERT(OldMacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n"); +} + +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. + // + + KeSetEvent( + ((AdaptP->DeviceObject == NULL) ? + &Miniport->AllocationEvent : + &AdaptP->AllocationEvent), + 0L, + FALSE + ); + + return DeallocateObjectKeepRegisters; +} + + + +NDIS_STATUS +NdisRegisterAdapter( + OUT PNDIS_HANDLE NdisAdapterHandle, + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE MacAdapterContext, + IN NDIS_HANDLE WrapperConfigurationContext, + IN PNDIS_STRING AdapterName, + IN PVOID AdapterInformation + ) + +/*++ + +Routine Description: + + Register an NDIS adapter. + +Arguments: + + NdisAdapterHandle - Returns a handle referring to this adapter. + NdisMacHandle - A handle for a previously registered MAC. + MacAdapterContext - A context for calls into this MAC. + WrapperConfigurationContext - Context passed to MacAddAdapter. + AdapterName - The name the adapter should be registered under. + AdapterInformation - Contains adapter information. For future + use. NULL for the meantime. Storage for it + must be allocated by the caller. + +Return Value: + + The final status. + +--*/ + +{ + PNDIS_ADAPTER_BLOCK NewAdaptP; + PDEVICE_OBJECT TmpDeviceP; + PNDIS_MAC_BLOCK TmpMacP; + NTSTATUS NtStatus; + NDIS_STRING NdisAdapterName; + PHYSICAL_ADDRESS PortAddress; + PHYSICAL_ADDRESS InitialPortAddress; + ULONG addressSpace; + PNDIS_ADAPTER_INFORMATION AdapterInfo = (PNDIS_ADAPTER_INFORMATION)AdapterInformation; + BOOLEAN Conflict; + PCM_RESOURCE_LIST Resources; + LARGE_INTEGER TimeoutValue; + BOOLEAN AllocateIndividualPorts = TRUE; + ULONG i; + ULONG BusNumber; + NDIS_INTERFACE_TYPE BusType; + NDIS_STATUS Status; + KIRQL OldIrql; + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisRegisterAdapter\n"); + } + + + IF_ERROR_CHK { + if (DbgIsNull(NdisMacHandle)) { + NdisPrint1("RegisterAdapter: Null Handle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisMacHandle)) { + NdisPrint1("RegisterAdapter: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacAdapterContext)) { + NdisPrint1("RegisterAdapter: Null Context\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(MacAdapterContext)) { + NdisPrint1("RegisterAdapter: Context not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + // + // Increment the MAC's refernce count. + // + + if (!NdisReferenceMac((PNDIS_MAC_BLOCK)NdisMacHandle)) { + + // + // The MAC is closing. + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_CLOSING; + } + + // + // Allocate the string structure and space for the string. This + // must be allocated from nonpaged pool, because it is touched by + // NdisWriteErrorLogEntry, which may be called from DPC level. + // + + NdisAdapterName.Buffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + AdapterName->MaximumLength, + 'naDN' + ); + if (NdisAdapterName.Buffer == NULL) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + } + + NdisAdapterName.MaximumLength = AdapterName->MaximumLength; + NdisAdapterName.Length = AdapterName->Length; + + RtlCopyMemory(NdisAdapterName.Buffer, + AdapterName->Buffer, + AdapterName->MaximumLength + ); + + // + // Create a device object for this adapter. + // + + NtStatus = IoCreateDevice( + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + sizeof(NDIS_ADAPTER_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size + AdapterName, + FILE_DEVICE_PHYSICAL_NETCARD, + 0, + FALSE, // exclusive flag + &TmpDeviceP + ); + + if (NtStatus != STATUS_SUCCESS) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + ExFreePool( NdisAdapterName.Buffer ); + return NDIS_STATUS_DEVICE_FAILED; + } + + + // + // Initialize the NDIS adapter block in the device object extension + // + // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than + // NDIS_ADAPTER_BLOCK, so we put it first in the extension. + // + + ASSERT( (sizeof(NDIS_WRAPPER_CONTEXT) & 3) <= (sizeof(NDIS_ADAPTER_BLOCK) & 3) ); + + NewAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1); + RtlZeroMemory(NewAdaptP, sizeof(NDIS_ADAPTER_BLOCK)); + + NewAdaptP->DeviceObject = TmpDeviceP; + NewAdaptP->MacHandle = TmpMacP = (PNDIS_MAC_BLOCK)NdisMacHandle; + NewAdaptP->MacAdapterContext = MacAdapterContext; + NewAdaptP->AdapterName = NdisAdapterName; + // NewAdaptP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL; + + NewAdaptP->WrapperContext = TmpDeviceP->DeviceExtension; + + // + // Get the BusNumber and BusType from the context + // + + if (((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultType == + (NDIS_INTERFACE_TYPE)-1) { + + BusType = (NDIS_INTERFACE_TYPE)-1; + + } else { + + BusType = AdapterInfo->AdapterType; + + } + + BusNumber = ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength; + + // + // Check that if there is no bus number or no bus type that the driver is not + // going to try to acquire any hardware resources + // + + if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1)) { + + if ((AdapterInfo != NULL) && + ((AdapterInfo->NumberOfPortDescriptors != 0) || + (AdapterInfo->Master))) { + + // + // Error out + // + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + return NDIS_STATUS_BAD_CHARACTERISTICS; + + } + + } + + // + // Copy over any PCI assigned resources + // + if ((BusType == NdisInterfacePci) && + (BusNumber != -1) && + (AdapterInfo != NULL) && + (TmpMacP->PciAssignedResources != NULL)) { + + // + // Reassign old resources to this device + // + NtStatus = IoReportResourceUsage( + NULL, + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + NULL, + 0, + NewAdaptP->DeviceObject, + TmpMacP->PciAssignedResources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Allocate a new buffer + // + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (AdapterInfo->NumberOfPortDescriptors + + TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count + + (((AdapterInfo->Master == TRUE) && + (AdapterInfo->AdapterType == NdisInterfaceIsa)) + ?1 + :0)), + 'lrDN' + ); + + if (Resources == NULL) { + + // + // Error out + // + + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + ExFreePool( TmpMacP->PciAssignedResources ); + NdisDereferenceMac(TmpMacP); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + // + // Copy over old resource list + // + NdisMoveMemory(Resources, + TmpMacP->PciAssignedResources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count + ); + + TmpMacP->PciAssignedResources->Count = 0; + + NtStatus = IoReportResourceUsage( + NULL, + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + TmpMacP->PciAssignedResources, + sizeof(CM_RESOURCE_LIST), + NULL, + NULL, + 0, + TRUE, + &Conflict + ); + + ExFreePool( TmpMacP->PciAssignedResources); + + TmpMacP->PciAssignedResources = NULL; + + } else { + + // + // Allocate a new buffer for non-pci devices + // + Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + (AdapterInfo->NumberOfPortDescriptors + + (((AdapterInfo->Master == TRUE) && + (AdapterInfo->AdapterType == NdisInterfaceIsa)) + ?1 + :0)), + 'lrDN' + ); + + if (Resources == NULL) { + + // + // Error out + // + + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + // + // Fix up counts for non-pci devices + // + Resources->List[0].PartialResourceList.Count = 0; + + } + + // + // Setup resources for the ports + // + + if ((BusType != (NDIS_INTERFACE_TYPE)-1) && + (BusNumber != (ULONG)-1)) { + + if (AdapterInfo != NULL) { + + ULONG HighestPort; + ULONG LowestPort; + + Resources->Count = 1; + Resources->List[0].InterfaceType = AdapterInfo->AdapterType; + Resources->List[0].BusNumber = BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + + NewAdaptP->Resources = Resources; + NewAdaptP->BusNumber = BusNumber; + NewAdaptP->BusType = BusType; + NewAdaptP->AdapterType = AdapterInfo->AdapterType; + NewAdaptP->Master = AdapterInfo->Master; + + // + // NewAdaptP->InitialPort and NumberOfPorts refer to the + // union of all port mappings specified; the area must + // cover all possible ports. We scan the list, keeping track + // of the highest and lowest ports used. + // + + if (AdapterInfo->NumberOfPortDescriptors > 0) { + + + // + // Setup port + // + LowestPort = AdapterInfo->PortDescriptors[0].InitialPort; + HighestPort = LowestPort + AdapterInfo->PortDescriptors[0].NumberOfPorts; + + if (AdapterInfo->PortDescriptors[0].PortOffset == NULL) { + + AllocateIndividualPorts = FALSE; + + } + + for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) { + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Type = + CmResourceTypePort; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Flags = + (AdapterInfo->AdapterType == NdisInterfaceInternal)? + CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO; +#if !defined(BUILD_FOR_3_1) + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start.QuadPart = + (ULONG)AdapterInfo->PortDescriptors[i].InitialPort; +#else + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start = + RtlConvertUlongToLargeInteger((ULONG)(AdapterInfo->PortDescriptors[i].InitialPort)); +#endif + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Length = + AdapterInfo->PortDescriptors[i].NumberOfPorts; + + if (AdapterInfo->PortDescriptors[i].PortOffset == NULL) { + + AllocateIndividualPorts = FALSE; + + } + + if (AdapterInfo->PortDescriptors[i].InitialPort < LowestPort) { + LowestPort = AdapterInfo->PortDescriptors[i].InitialPort; + } + if ((AdapterInfo->PortDescriptors[i].InitialPort + + AdapterInfo->PortDescriptors[i].NumberOfPorts) > HighestPort) { + HighestPort = AdapterInfo->PortDescriptors[i].InitialPort + + AdapterInfo->PortDescriptors[i].NumberOfPorts; + } + } + + NewAdaptP->InitialPort = LowestPort; + NewAdaptP->NumberOfPorts = HighestPort - LowestPort; + + } else { + + NewAdaptP->NumberOfPorts = 0; + + } + + Resources->List[0].PartialResourceList.Count += AdapterInfo->NumberOfPortDescriptors; + + } else { + + // + // Error out + // + + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_FAILURE; + + } + + } + + NewAdaptP->BeingRemoved = FALSE; + + if ((BusType != (NDIS_INTERFACE_TYPE)-1) && + (BusNumber != (ULONG)-1)) { + + // + // Submit Resources + // + + NtStatus = IoReportResourceUsage( + NULL, + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + NULL, + 0, + NewAdaptP->DeviceObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Check for conflict. + // + + if (Conflict || (NtStatus != STATUS_SUCCESS)) { + + if (Conflict) { + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG StringSize; + PWCH baseFileName; + + baseFileName = NewAdaptP->AdapterName.Buffer; + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]); + } + + } + + StringSize = NewAdaptP->AdapterName.MaximumLength - + (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ; + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + TmpDeviceP, + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize) + ); + + if (errorLogEntry != NULL) { + + errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT; + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + } else { + + errorLogEntry->NumberOfStrings = 0; + + } + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + } + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + return(NDIS_STATUS_RESOURCE_CONFLICT); + + } + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + + return(NDIS_STATUS_FAILURE); + } + + // + // If port mapping is needed, we do that. If the result + // is in memory, we have to map it. We map only the + // ports specified in AdapterInformation; the default + // is to map the first 4K. + // + // Note that NumberOfPorts can only be 0 if AdapterInfo + // is provided and explicitly sets it to 0, so in that + // case it is OK to leave the adapter in a state where + // a call to NdisXXXPort will probably crash (because + // PortOffset will be undefined). + // + + if (NewAdaptP->NumberOfPorts > 0) { + + if (AllocateIndividualPorts) { + + // + // We get here if we are supposed to allocate ports on an + // individual bases -- which implies that the driver will + // be using the Raw functions. + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) { + + addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1; + + InitialPortAddress.LowPart = AdapterInfo->PortDescriptors[i].InitialPort; + InitialPortAddress.HighPart = 0; + + if ( !HalTranslateBusAddress( + NewAdaptP->BusType, // InterfaceType + NewAdaptP->BusNumber, // BusNumber + InitialPortAddress, // Bus Address + &addressSpace, // AddressSpace + &PortAddress // Translated address + ) ) { + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + + return(NDIS_STATUS_FAILURE); + } + + if (addressSpace == 0) { + + // + // memory space + // + + *(AdapterInfo->PortDescriptors[i].PortOffset) = MmMapIoSpace( + PortAddress, + AdapterInfo->PortDescriptors[i].NumberOfPorts, + FALSE + ); + + if (*(AdapterInfo->PortDescriptors[i].PortOffset) == NULL) { + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + } else { + + // + // I/O space + // + + *(AdapterInfo->PortDescriptors[i].PortOffset) = (PUCHAR)PortAddress.LowPart; + + } + + } + + } else { + + // + // The driver will not use the Raw functions, only the + // old NdisRead and NdisWrite port functions. + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1; + InitialPortAddress.LowPart = NewAdaptP->InitialPort; + InitialPortAddress.HighPart = 0; + if ( !HalTranslateBusAddress( + NewAdaptP->BusType, // InterfaceType + NewAdaptP->BusNumber, // BusNumber + InitialPortAddress, // Bus Address + &addressSpace, // AddressSpace + &PortAddress // Translated address + ) ) { + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + + return(NDIS_STATUS_FAILURE); + } + + if (addressSpace == 0) { + + // + // memory space + // + + NewAdaptP->InitialPortMapping = MmMapIoSpace( + PortAddress, + NewAdaptP->NumberOfPorts, + FALSE + ); + + if (NewAdaptP->InitialPortMapping == NULL) { + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + } + + NewAdaptP->InitialPortMapped = TRUE; + + } else { + + // + // I/O space + // + + NewAdaptP->InitialPortMapping = (PUCHAR)PortAddress.LowPart; + NewAdaptP->InitialPortMapped = FALSE; + + } + + // + // PortOffset holds the mapped address of port 0. + // + + NewAdaptP->PortOffset = NewAdaptP->InitialPortMapping - NewAdaptP->InitialPort; + + } + + } else { + + // + // Technically should not allow this, but do it until + // all drivers register their info correctly. + // + + NewAdaptP->PortOffset = 0; + + } + + } + + // + // If the driver want to be called back now, use + // supplied callback routine. + // + + if ((AdapterInfo != NULL) && (AdapterInfo->ActivateCallback != NULL)) { + + Status = (*(AdapterInfo->ActivateCallback))((NDIS_HANDLE)NewAdaptP, + MacAdapterContext, + AdapterInfo->DmaChannel + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + // + // Exit + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return Status; + + } + + } + + // + // Set information from AdapterInformation. The call back + // routine can set these values. + // + + NewAdaptP->ChannelNumber = AdapterInfo->DmaChannel; + NewAdaptP->PhysicalMapRegistersNeeded = + AdapterInfo->PhysicalMapRegistersNeeded; + NewAdaptP->MaximumPhysicalMapping = + AdapterInfo->MaximumPhysicalMapping; + + + // + // Check for resource conflic on DmaChannel. + // + + if ((NewAdaptP->Master) && + (BusType != (NDIS_INTERFACE_TYPE)-1) && + (BusNumber != (ULONG)-1)) { + + if (NewAdaptP->AdapterType == NdisInterfaceIsa) { + + // + // Put the DMA channel in the resource list. + // + + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type = + CmResourceTypeDma; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition = + CmResourceShareDeviceExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags = + 0; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel = + NewAdaptP->ChannelNumber; + Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port = + 0; + Resources->List[0].PartialResourceList.Count++; + + } + + // + // Submit Resources + // + + NtStatus = IoReportResourceUsage( + NULL, + ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver, + NULL, + 0, + NewAdaptP->DeviceObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * + Resources->List[0].PartialResourceList.Count, + TRUE, + &Conflict + ); + + // + // Check for conflict. + // + + if (Conflict || (NtStatus != STATUS_SUCCESS)) { + + if (Conflict) { + + // + // Log an error + // + + PIO_ERROR_LOG_PACKET errorLogEntry; + ULONG StringSize; + PWCH baseFileName; + + baseFileName = NewAdaptP->AdapterName.Buffer; + + // + // Parse out the path name, leaving only the device name. + // + + for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set baseFileName to + // the character after the separator. + // + + if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]); + } + + } + + StringSize = NewAdaptP->AdapterName.MaximumLength - + (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ; + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + TmpDeviceP, + (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + + StringSize) + ); + + if (errorLogEntry != NULL) { + + if ((NewAdaptP->Master) && + (NewAdaptP->AdapterType == Isa)){ + + errorLogEntry->ErrorCode = EVENT_NDIS_PORT_OR_DMA_CONFLICT; + + } else { + + errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT; + + } + + // + // store the time + // + + errorLogEntry->MajorFunctionCode = 0; + errorLogEntry->RetryCount = 0; + errorLogEntry->UniqueErrorValue = 0; + errorLogEntry->FinalStatus = 0; + errorLogEntry->SequenceNumber = 0; + errorLogEntry->IoControlCode = 0; + + // + // Set string information + // + + if (StringSize != 0) { + + errorLogEntry->NumberOfStrings = 1; + errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET); + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + sizeof(IO_ERROR_LOG_PACKET), + (PVOID)baseFileName, + StringSize + ); + + } else { + + errorLogEntry->NumberOfStrings = 0; + + } + + // + // write it out + // + + IoWriteErrorLogEntry(errorLogEntry); + } + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + return(NDIS_STATUS_RESOURCE_CONFLICT); + + } + + // + // Free memory + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + + + return(NDIS_STATUS_FAILURE); + } + + } + + // + // If the device is a busmaster, we get an adapter + // object for it. + // If map registers are needed, we loop, allocating an + // adapter channel for each map register needed. + // + + if ((NewAdaptP->Master) && + (BusType != (NDIS_INTERFACE_TYPE)-1) && + (BusNumber != (ULONG)-1)) { + + // + // This is needed by HalGetAdapter. + // + DEVICE_DESCRIPTION DeviceDescription; + + // + // Returned by HalGetAdapter. + // + ULONG MapRegistersAllowed; + + // + // Returned by HalGetAdapter. + // + PADAPTER_OBJECT AdapterObject; + + // + // Map registers needed per channel. + // + ULONG MapRegistersPerChannel; + + NTSTATUS Status; + + // + // Allocate storage for holding the appropriate + // information for each map register. + // + + NewAdaptP->MapRegisters = (PMAP_REGISTER_ENTRY) + ExAllocatePoolWithTag( + NonPagedPool, + sizeof(MAP_REGISTER_ENTRY) * + NewAdaptP->PhysicalMapRegistersNeeded, + 'rmDN'); + + if (NewAdaptP->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) { + + // + // Error out + // + + ExFreePool(Resources); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + // + // Use this event to tell us when NdisAllocationExecutionRoutine + // has been called. + // + + KeInitializeEvent( + &NewAdaptP->AllocationEvent, + NotificationEvent, + FALSE + ); + + + // + // Set up the device description; zero it out in case its + // size changes. + // + + RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); + + DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; + DeviceDescription.Master = TRUE; + DeviceDescription.ScatterGather = TRUE; + + DeviceDescription.BusNumber = NewAdaptP->BusNumber; + DeviceDescription.DmaChannel = NewAdaptP->ChannelNumber; + DeviceDescription.InterfaceType = NewAdaptP->AdapterType; + + if (DeviceDescription.InterfaceType == NdisInterfaceIsa) { + + // + // For ISA devices, the width is based on the DMA channel: + // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility + // mode. + // + + if (NewAdaptP->ChannelNumber > 4) { + DeviceDescription.DmaWidth = Width16Bits; + } else { + DeviceDescription.DmaWidth = Width8Bits; + } + DeviceDescription.DmaSpeed = Compatible; + + } else if ((DeviceDescription.InterfaceType == NdisInterfaceMca) || + (DeviceDescription.InterfaceType == NdisInterfaceEisa) || + (DeviceDescription.InterfaceType == NdisInterfacePci)) + { + DeviceDescription.Dma32BitAddresses = AdapterInfo->Dma32BitAddresses; + DeviceDescription.DmaPort = 0; + + } + + DeviceDescription.MaximumLength = NewAdaptP->MaximumPhysicalMapping; + + + // + // Determine how many map registers we need per channel. + // + + MapRegistersPerChannel = + ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; + + // + // Get the adapter object. + // + + AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed); + + if (AdapterObject == NULL) { + + ExFreePool(Resources); + ExFreePool(NewAdaptP->MapRegisters); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_RESOURCES; + + } + + ASSERT (MapRegistersAllowed >= MapRegistersPerChannel); + + // + // We save this to call IoFreeMapRegisters later. + // + + NewAdaptP->SystemAdapterObject = AdapterObject; + + + // + // Now loop, allocating an adapter channel each time, then + // freeing everything but the map registers. + // + + for (i=0; iPhysicalMapRegistersNeeded; i++) { + + NewAdaptP->CurrentMapRegister = i; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + Status = IoAllocateAdapterChannel( + AdapterObject, + NewAdaptP->DeviceObject, + MapRegistersPerChannel, + NdisAllocationExecutionRoutine, + (PVOID)NewAdaptP + ); + + KeLowerIrql(OldIrql); + + if (!NT_SUCCESS(Status)) { + +#if DBG + DbgPrint("NDIS: Failed to load driver because of\n"); + DbgPrint("NDIS: insufficient map registers.\n"); + DbgPrint("NDIS: AllocateAdapterChannel: %lx\n", Status); +#endif + + ExFreePool(Resources); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + for (; i != 0; i--) { + IoFreeMapRegisters( + NewAdaptP->SystemAdapterObject, + NewAdaptP->MapRegisters[i-1].MapRegister, + MapRegistersPerChannel + ); + } + + KeLowerIrql(OldIrql); + + ExFreePool(NewAdaptP->MapRegisters); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + return(NDIS_STATUS_RESOURCES); + } + + TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000); + + // + // NdisAllocationExecutionRoutine will set this event + // when it has gotten FirstTranslationEntry. + // + + NtStatus = KeWaitForSingleObject( + &NewAdaptP->AllocationEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus); + ExFreePool(Resources); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + for (; i != 0; i--) { + IoFreeMapRegisters( + NewAdaptP->SystemAdapterObject, + NewAdaptP->MapRegisters[i-1].MapRegister, + MapRegistersPerChannel + ); + } + + KeLowerIrql(OldIrql); + + ExFreePool(NewAdaptP->MapRegisters); + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + return(NDIS_STATUS_RESOURCES); + + } + + KeResetEvent( + &NewAdaptP->AllocationEvent + ); + + } + + } + + + + NdisInitializeRef(&NewAdaptP->Ref); + + + if (!NdisQueueAdapterOnMac(NewAdaptP, TmpMacP)) { + + // + // The MAC is closing, undo what we have done. + // + + ExFreePool(Resources); + if (NewAdaptP->Master) { + ULONG MapRegistersPerChannel = + ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; + + for (i=0; iPhysicalMapRegistersNeeded; i++) { + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + IoFreeMapRegisters( + NewAdaptP->SystemAdapterObject, + NewAdaptP->MapRegisters[i].MapRegister, + MapRegistersPerChannel + ); + + KeLowerIrql(OldIrql); + } + + ExFreePool(NewAdaptP->MapRegisters); + } + IoDeleteDevice(TmpDeviceP); + ExFreePool( NdisAdapterName.Buffer ); + NdisDereferenceMac(TmpMacP); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_CLOSING; + } + + NdisMacReferencePackage(); + + // + // Add an extra reference because the wrapper is using the MAC + // + NdisReferenceAdapter(NewAdaptP); + + *NdisAdapterHandle = (NDIS_HANDLE)NewAdaptP; + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n"); + return NDIS_STATUS_SUCCESS; +} + + +NDIS_STATUS +NdisDeregisterAdapter( + IN NDIS_HANDLE NdisAdapterHandle + ) + +/*++ + +Routine Description: + + Deregisters an NDIS adapter. + +Arguments: + + NdisAdapterHandle - The handle returned by NdisRegisterAdapter. + +Return Value: + + NDIS_STATUS_SUCCESS. + +--*/ + +{ + + // + // KillAdapter does all the work. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeregisterAdapter\n"); + NdisPrint2(" Deregistering Adapter %s\n", + ((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle)->AdapterName.Buffer); + } + IF_ERROR_CHK { + if (DbgIsNull(NdisAdapterHandle)) { + NdisPrint1("DeregisterAdapter: Null Handle\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisAdapterHandle)) { + NdisPrint1("DeregisterAdapter: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + NdisKillAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle); + + // + // Remove reference from wrapper + // + NdisDereferenceAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle); + + NdisMacDereferencePackage(); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterAdapter\n"); + return NDIS_STATUS_SUCCESS; +} + + +VOID +NdisRegisterAdapterShutdownHandler( + IN NDIS_HANDLE NdisAdapterHandle, + IN PVOID ShutdownContext, + IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler + ) + +/*++ + +Routine Description: + + Deregisters an NDIS adapter. + +Arguments: + + NdisAdapterHandle - The handle returned by NdisRegisterAdapter. + + ShutdownContext - Context to pass the the handler, when called. + + ShutdownHandler - The Handler for the Adapter, to be called on shutdown. + +Return Value: + + NDIS_STATUS_SUCCESS. + +--*/ + +{ + PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle; + PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext; + + if (WrapperContext->ShutdownHandler == NULL) { + + // + // Store information + // + + WrapperContext->ShutdownHandler = ShutdownHandler; + WrapperContext->ShutdownContext = ShutdownContext; + + // + // Register our shutdown handler for either a system shutdown + // notification or a bugcheck. + // + + IoRegisterShutdownNotification(Adapter->DeviceObject); + +#if !defined(BUILD_FOR_3_1) + KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord); + + KeRegisterBugCheckCallback( + &WrapperContext->BugcheckCallbackRecord, // callback record. + (PVOID) NdisBugcheckHandler, // callback routine. + (PVOID) WrapperContext, // free form buffer. + sizeof(NDIS_WRAPPER_CONTEXT), // buffer size. + "Ndis mac" // component id. + ); +#endif + + } +} + + +VOID +NdisDeregisterAdapterShutdownHandler( + IN NDIS_HANDLE NdisAdapterHandle + ) + +/*++ + +Routine Description: + + Deregisters an NDIS adapter. + +Arguments: + + NdisAdapterHandle - The handle returned by NdisRegisterAdapter. + +Return Value: + + NDIS_STATUS_SUCCESS. + +--*/ + +{ + PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle; + PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext; + + if (WrapperContext->ShutdownHandler != NULL) { + + // + // Clear information + // + + WrapperContext->ShutdownHandler = NULL; + + IoUnregisterShutdownNotification(Adapter->DeviceObject); + +#if !defined(BUILD_FOR_3_1) + KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord); +#endif + + } +} + + +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 + ); + + + return; + +} + + +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; + ULONG i; + ULONG StringSize; + PWCH baseFileName; + + if (AdapterBlock == NULL) { + + return; + + } + + if (AdapterBlock->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 < ((AdapterBlock->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 ( ((AdapterBlock->DeviceObject != NULL) ? + AdapterBlock->AdapterName.Buffer[i] : + Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) { + baseFileName = ((AdapterBlock->DeviceObject != NULL) ? + &(AdapterBlock->AdapterName.Buffer[++i]) : + &(Miniport->MiniportName.Buffer[++i])); + } + + } + + StringSize = ((AdapterBlock->DeviceObject != NULL) ? + AdapterBlock->AdapterName.MaximumLength : + Miniport->MiniportName.MaximumLength) - + (((ULONG)baseFileName) - + ((AdapterBlock->DeviceObject != NULL) ? + ((ULONG)AdapterBlock->AdapterName.Buffer) : + ((ULONG)Miniport->MiniportName.Buffer))) ; + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + ((AdapterBlock->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); + + + RtlCopyMemory ( + ((PUCHAR)errorLogEntry) + + (sizeof(IO_ERROR_LOG_PACKET) + + NumberOfErrorValues * sizeof(ULONG)), + (PVOID)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; + PNDIS_OPEN_BLOCK TmpOpen; + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisCompleteOpenAdapter\n"); + } + IF_ERROR_CHK { + if (!DbgIsNonPaged(NdisBindingContext)) { + NdisPrint1("NdisCompleteOpenAdapter: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisBindingContext)) { + NdisPrint1("NdisCompleteOpenAdapter: Binding Context not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + if (Status == NDIS_STATUS_SUCCESS) { + if (!NdisFinishOpen(OpenP)) { + Status = NDIS_STATUS_CLOSING; + } + } + + (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) ( + OpenP->ProtocolBindingContext, + Status, + OpenErrorStatus + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + // + // Something went wrong, clean up and exit. + // + + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + if (GlobalOpenList == OpenP) { + + GlobalOpenList = OpenP->NextGlobalOpen; + + } else { + + TmpOpen = GlobalOpenList; + + while (TmpOpen->NextGlobalOpen != OpenP) { + + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + TmpOpen->NextGlobalOpen = OpenP->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + ObDereferenceObject((PVOID)OpenP->FileObject); + NdisDereferenceAdapter(OpenP->AdapterHandle); + NdisDereferenceProtocol(OpenP->ProtocolHandle); + ExFreePool((PVOID)OpenP); + + } + +} + + +VOID +NdisCompleteCloseAdapter( + IN NDIS_HANDLE NdisBindingContext, + IN NDIS_STATUS Status + ) + +{ + PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK) NdisBindingContext; + PNDIS_OPEN_BLOCK TmpOpen; + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisCompleteCloseAdapter\n"); + } + IF_ERROR_CHK { + if (!DbgIsNonPaged(NdisBindingContext)) { + NdisPrint1("NdisCompleteCloseAdapter: Handle not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(NdisBindingContext)) { + NdisPrint1("NdisCompleteCloseAdapter: Binding Context not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + + (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) ( + Open->ProtocolBindingContext, + Status + ); + + NdisDeQueueOpenOnAdapter(Open, Open->AdapterHandle); + NdisDeQueueOpenOnProtocol(Open, Open->ProtocolHandle); + + NdisDereferenceProtocol(Open->ProtocolHandle); + NdisDereferenceAdapter(Open->AdapterHandle); + NdisFreeSpinLock(&Open->SpinLock); + + // + // This sends an IRP_MJ_CLOSE IRP. + // + + ObDereferenceObject((PVOID)(Open->FileObject)); + + // + // Remove from global list + // + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + if (GlobalOpenList == Open) { + + GlobalOpenList = Open->NextGlobalOpen; + + } else { + + TmpOpen = GlobalOpenList; + + while (TmpOpen->NextGlobalOpen != Open) { + + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + TmpOpen->NextGlobalOpen = Open->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + ExFreePool((PVOID)(NdisBindingContext)); +} + + + + +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. + +--*/ + +{ + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisReferenceRef\n"); + + IF_ERROR_CHK { + if (DbgIsNull(RefP)) { + NdisPrint1("NdisReferenceRef: NULL Reference address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(RefP)) { + NdisPrint1("NdisReferenceRef: Reference not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&RefP->SpinLock); + + if (RefP->Closing) { + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n"); + return FALSE; + } + + ++(RefP->ReferenceCount); + + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n"); + return TRUE; +} + +BOOLEAN +NdisDereferenceRef( + 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. + +--*/ + +{ + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDereferenceRef\n"); + + IF_ERROR_CHK { + if (DbgIsNull(RefP)) { + NdisPrint1("NdisDereferenceRef: NULL Reference address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(RefP)) { + NdisPrint1("NdisDereferenceRef: Reference not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + ACQUIRE_SPIN_LOCK(&RefP->SpinLock); + --(RefP->ReferenceCount); + if (RefP->ReferenceCount == 0) { + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n"); + return TRUE; + } + + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n"); + return FALSE; +} + + +VOID +NdisInitializeRef( + PREFERENCE RefP + ) + +/*++ + +Routine Description: + + Initialize a reference count structure. + +Arguments: + + RefP - The structure to be initialized. + +Return Value: + + None. + +--*/ + +{ + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisInitializeRef\n"); + + IF_ERROR_CHK { + if (DbgIsNull(RefP)) { + NdisPrint1("NdisInitializeRef: NULL Reference address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(RefP)) { + NdisPrint1("NdisInitializeRef: Reference not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + RefP->Closing = FALSE; + RefP->ReferenceCount = 1; + NdisAllocateSpinLock(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisInitializeRef\n"); +} + +BOOLEAN +NdisCloseRef( + 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. + +--*/ + +{ + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseRef\n"); + + IF_ERROR_CHK { + if (DbgIsNull(RefP)) { + NdisPrint1("NdisCloseRef: NULL Reference address\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(RefP)) { + NdisPrint1("NdisCloseRef: Reference not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&RefP->SpinLock); + + if (RefP->Closing) { + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n"); + return FALSE; + } + + RefP->Closing = TRUE; + + RELEASE_SPIN_LOCK(&RefP->SpinLock); + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n"); + return TRUE; +} + + + +BOOLEAN +NdisQueueOpenOnProtocol( + IN PNDIS_OPEN_BLOCK OpenP, + IN PNDIS_PROTOCOL_BLOCK ProtP + ) + +/*++ + +Routine Description: + + Attaches an open block to the list of opens for a protocol. + +Arguments: + + OpenP - The open block to be queued. + ProtP - The protocol block to queue it to. + +Return Value: + + TRUE if the operation is successful. + FALSE if the protocol is closing. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisQueueOpenOnProtocol\n"); + NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name); + } + + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisQueueOpenOnProtocol: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + if (DbgIsNull(ProtP)) { + NdisPrint1("NdisQueueOpenOnProtocol: Null Protocol Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(ProtP)) { + NdisPrint1("NdisQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + } + ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock); + + // + // Make sure the protocol is not closing. + // + + if (ProtP->Ref.Closing) { + RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n"); + return FALSE; + } + + + // + // Attach this open at the head of the queue. + // + + OpenP->ProtocolNextOpen = ProtP->OpenQueue; + ProtP->OpenQueue = OpenP; + + + RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n"); + return TRUE; +} + +VOID +NdisDeQueueOpenOnProtocol( + IN PNDIS_OPEN_BLOCK OpenP, + IN PNDIS_PROTOCOL_BLOCK ProtP + ) + +/*++ + +Routine Description: + + Detaches an open block from the list of opens for a protocol. + +Arguments: + + OpenP - The open block to be dequeued. + ProtP - The protocol block to dequeue it from. + +Return Value: + + None. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeQueueOpenOnProtocol\n"); + NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name); + } + + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisDeQueueOpenOnProtocol: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisDeQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + if (DbgIsNull(ProtP)) { + NdisPrint1("NdisDeQueueOpenOnProtocol: Null Protocol Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(ProtP)) { + NdisPrint1("NdisDeQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + + } + + ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock); + + // + // Find the open on the queue, and remove it. + // + + if (ProtP->OpenQueue == OpenP) { + ProtP->OpenQueue = OpenP->ProtocolNextOpen; + } else { + PNDIS_OPEN_BLOCK PP = ProtP->OpenQueue; + + while (PP->ProtocolNextOpen != OpenP) { + PP = PP->ProtocolNextOpen; + } + + PP->ProtocolNextOpen = PP->ProtocolNextOpen->ProtocolNextOpen; + } + + RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueOpenOnProtocol\n"); +} + +VOID +NdisDeQueueOpenOnMiniport( + IN PNDIS_M_OPEN_BLOCK OpenP, + IN PNDIS_MINIPORT_BLOCK Miniport + ) + +/*++ + +Routine Description: + + Detaches an open block from the list of opens for a Miniport. + +Arguments: + + OpenP - The open block to be dequeued. + Miniport - The Miniport block to dequeue it from. + +Return Value: + + None. + +--*/ + +{ + ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock); + + OpenP->References--; + + // + // Find the open on the queue, and remove it. + // + + if (Miniport->OpenQueue == OpenP) { + Miniport->OpenQueue = OpenP->MiniportNextOpen; + } else { + PNDIS_M_OPEN_BLOCK PP = Miniport->OpenQueue; + + while (PP->MiniportNextOpen != OpenP) { + PP = PP->MiniportNextOpen; + } + + PP->MiniportNextOpen = PP->MiniportNextOpen->MiniportNextOpen; + } + + RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock); +} + + + +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. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisFinishOpen\n"); + NdisPrint3(" Protocol %wZ is being bound to Adapter %wZ\n", + &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name, + &OpenP->AdapterHandle->AdapterName); + } + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisFinishOpen: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisFinishOpen: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + if (!NdisQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle)) { + + // + // The adapter is closing. + // + // Call MacCloseAdapter(), don't worry about it completing. + // + + (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) ( + OpenP->MacBindingHandle); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==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); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n"); + return FALSE; + } + + + // + // Both queueings succeeded. + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n"); + return TRUE; +} + +NTSTATUS +NdisCreateIrpHandler( + PDEVICE_OBJECT DeviceObject, + 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; + BOOLEAN IsAMiniport; + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCreateIrpHandler\n"); + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + AdapterBlock = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1); + 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) + ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_USER_OPEN_CONTEXT), ' DN'); + + if (OpenContext == NULL) { + + Status = STATUS_INSUFFICIENT_RESOURCES; + + } else { + + OpenContext->DeviceObject = DeviceObject; + + OpenContext->AdapterBlock = AdapterBlock; + OpenContext->OidCount = 0; + OpenContext->OidArray = NULL; + + IrpSp->FileObject->FsContext = (PVOID)OpenContext; + IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_QUERY_STATISTICS; + + if (IsAMiniport) { + Status = NdisMQueryOidList((PNDIS_M_USER_OPEN_CONTEXT)OpenContext, Irp); + } else { + Status = NdisQueryOidList(OpenContext, Irp); + } + + if (Status != STATUS_SUCCESS) { + ExFreePool (OpenContext); + } + + } + + } else { + + // + // This is an internal open, verify the EA. + // + + if ((IrpEaInfo->EaNameLength != sizeof(NdisInternalEaName)) || + (RtlCompareMemory(IrpEaInfo->EaName, NdisInternalEaName, sizeof(NdisInternalEaName)) != + sizeof(NdisInternalEaName)) || + (IrpEaInfo->EaValueLength != sizeof(NdisInternalEaValue)) || + (RtlCompareMemory(&IrpEaInfo->EaName[IrpEaInfo->EaNameLength+1], + NdisInternalEaValue, sizeof(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); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n"); + return Status; +} + + + +NTSTATUS +NdisQueryOidList( + PNDIS_USER_OPEN_CONTEXT OpenContext, + 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. + +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. + +--*/ + +{ + + NDIS_QUERY_OPEN_REQUEST OpenRequest; + NDIS_STATUS NdisStatus; + PNDIS_OID TmpBuffer; + ULONG TmpBufferLength; + UINT i, j; + + // + // First query the OID list with no buffer, to find out + // how big it should be. + // + + KeInitializeEvent( + &OpenRequest.Event, + NotificationEvent, + FALSE + ); + + 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; + + NdisStatus = + (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) ( + OpenContext->AdapterBlock->MacAdapterContext, + &OpenRequest.Request); + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &OpenRequest.Event, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)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 = ExAllocatePoolWithTag(NonPagedPool, TmpBufferLength, ' DN'); + + if (TmpBuffer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // ...and query the real list. + // + + KeResetEvent( + &OpenRequest.Event + ); + + + OpenRequest.Request.RequestType = NdisRequestQueryStatistics; + OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST; + 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; + + NdisStatus = + (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) ( + OpenContext->AdapterBlock->MacAdapterContext, + &OpenRequest.Request); + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &OpenRequest.Event, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + NdisStatus = OpenRequest.NdisStatus; + + } + + ASSERT (NdisStatus == NDIS_STATUS_SUCCESS); + + + // + // Now go through the buffer, counting the statistics OIDs. + // + + for (i=0; iOidCount; + } + } + + // + // Now allocate storage for the real OID array. + // + + OpenContext->OidArray = ExAllocatePoolWithTag (NonPagedPool, OpenContext->OidCount * sizeof(NDIS_OID), ' DN'); + + if (OpenContext->OidArray == NULL) { + ExFreePool (TmpBuffer); + return STATUS_INSUFFICIENT_RESOURCES; + } + + + // + // Now go through the buffer, copying the statistics OIDs. + // + + j = 0; + for (i=0; iOidArray[j] = TmpBuffer[i]; + ++j; + } + } + + ASSERT (j == OpenContext->OidCount); + + ExFreePool (TmpBuffer); + return STATUS_SUCCESS; +} + +#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0]) + + + +NTSTATUS +NdisDeviceControlIrpHandler( + PDEVICE_OBJECT DeviceObject, + 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; + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDeviceControlIrpHandler\n"); + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + 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; + } + + switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { + + case IOCTL_NDIS_QUERY_GLOBAL_STATS: + + // + // Allocate a request. + // + + OpenContext = IrpSp->FileObject->FsContext; + GlobalRequest = (PNDIS_QUERY_GLOBAL_REQUEST) + ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_GLOBAL_REQUEST), ' DN'); + + if (GlobalRequest == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + GlobalRequest->Irp = Irp; + + if (OpenContext->AdapterBlock->DeviceObject == NULL) { + + Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + 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 = + MmGetSystemAddressForMdl (Irp->MdlAddress); + GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = + MmGetMdlByteCount (Irp->MdlAddress); + GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0; + GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0; + + + if (Miniport != NULL) { + PNDIS_REQUEST_RESERVED Reserved; + + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(GlobalRequest->Request)); + Reserved->Next = NULL; + Miniport->LastPendingRequest = &(GlobalRequest->Request); + + if (Miniport->FirstPendingRequest == NULL) { + + Miniport->FirstPendingRequest = &(GlobalRequest->Request); + + } else { + + PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = + &(GlobalRequest->Request); + + } + + if (Miniport->MiniportRequest == NULL) { + + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + + } + + // + // If we were able to grab the local lock then we can do some + // deferred processing now. + // + + if ( LocalLock ) { + if (!Miniport->ProcessingDeferred) { + MiniportProcessDeferred(Miniport); + } + } + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + + } 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( + (NDIS_HANDLE)OpenContext->AdapterBlock, + &GlobalRequest->Request, + NdisStatus); + } + + } + + Status = STATUS_PENDING; + + break; + + case IOCTL_NDIS_QUERY_ALL_STATS: + + + // + // Allocate a request. + // + + OpenContext = IrpSp->FileObject->FsContext; + AllRequest = (PNDIS_QUERY_ALL_REQUEST) + ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_ALL_REQUEST), ' DN'); + + if (AllRequest == NULL) { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + if (OpenContext->AdapterBlock->DeviceObject == NULL) { + + Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + LOCK_MINIPORT(Miniport, LocalLock); + + } else { + + Miniport = NULL; + + } + + AllRequest->Irp = Irp; + + Buffer = (PUCHAR)MmGetSystemAddressForMdl (Irp->MdlAddress); + BufferLength = MmGetMdlByteCount (Irp->MdlAddress); + BytesWritten = 0; + + KeInitializeEvent( + &AllRequest->Event, + NotificationEvent, + FALSE + ); + + NdisStatus = NDIS_STATUS_SUCCESS; + + for (CurrentOid = 0; CurrentOidOidCount; 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) { + + PNDIS_REQUEST_RESERVED Reserved; + + Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(AllRequest->Request)); + Reserved->Next = NULL; + Miniport->LastPendingRequest = &(AllRequest->Request); + + if (Miniport->FirstPendingRequest == NULL) { + + Miniport->FirstPendingRequest = &(AllRequest->Request); + + } else { + + PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next = + &(AllRequest->Request); + + } + + if (Miniport->MiniportRequest == NULL) { + + Miniport->RunDoRequests = TRUE; + Miniport->ProcessOddDeferredStuff = TRUE; + + } + + // + // If we were able to grab the local lock then we can do some + // deferred processing now. + // + + if ( LocalLock ) { + if (!Miniport->ProcessingDeferred) { + MiniportProcessDeferred(Miniport); + } + } + + NdisStatus = NDIS_STATUS_PENDING; + + } else { + + NdisStatus = + (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) ( + OpenContext->AdapterBlock->MacAdapterContext, + &AllRequest->Request); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + if (Miniport != NULL) { + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(OldIrql); + } + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &AllRequest->Event, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + NdisStatus = AllRequest->NdisStatus; + + if (Miniport != NULL) { + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock)); + 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; + + } + + KeResetEvent( + &AllRequest->Event + ); + + } + + if (Miniport != NULL) { + + UNLOCK_MINIPORT(Miniport, LocalLock); + RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock)); + KeLowerIrql(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; + + } + + if (Status != STATUS_PENDING) { + IrpSp->Control &= ~SL_PENDING_RETURNED; + Irp->IoStatus.Status = Status; + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); + } + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n"); + return Status; +} + + + +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_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + 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; + KeSetEvent( + &OpenRequest->Event, + 0L, + FALSE); + + 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; // what else ? + } + + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); + + ExFreePool (GlobalRequest); + break; + + case IOCTL_NDIS_QUERY_ALL_STATS: + + // + // An "all" query. + // + + AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest; + + AllRequest->NdisStatus = Status; + KeSetEvent( + &AllRequest->Event, + 0L, + FALSE); + + break; + + } + + break; + + } + +} + + + +NTSTATUS +NdisCloseIrpHandler( + PDEVICE_OBJECT DeviceObject, + 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; + + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseIrpHandler\n"); + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + IrpSp = IoGetCurrentIrpStackLocation (Irp); + + if (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_INTERNAL) { + + // + // An internal open, nothing needs to be done. + // + + } else { + + // + // Free the query context. + // + + ASSERT (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS); + + OpenContext = IrpSp->FileObject->FsContext; + ExFreePool (OpenContext->OidArray); + ExFreePool (OpenContext); + + } + + Irp->IoStatus.Status = Status; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseIrplHandler\n"); + return Status; +} + +NTSTATUS +NdisSuccessIrpHandler( + PDEVICE_OBJECT DeviceObject, + 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 + + IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisSuccessIrplHandler\n"); + IF_ERROR_CHK { + if (DbgIsNull(Irp)) { + NdisPrint1(": Null Irp\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(Irp)) { + NdisPrint1(": Irp not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + Irp->IoStatus.Status = STATUS_SUCCESS; + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisSuccessIrplHandler\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. + // + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisKillOpenAndNotifyProtocol\n"); + NdisPrint3(" Closing Adapter %wZ and notifying Protocol %wZ\n", + &OldOpenP->AdapterHandle->AdapterName, + &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name); + } + + IF_ERROR_CHK { + if (DbgIsNull(OldOpenP)) { + NdisPrint1("NdisKillOpenAndNotifyProtocol: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OldOpenP)) { + NdisPrint1("NdisKillOpenAndNotifyProtocol: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + (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); + } + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpenAndNotifyProtocol\n"); +} + + +BOOLEAN +NdisKillOpen( + 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. + +--*/ + +{ + PNDIS_OPEN_BLOCK TmpOpen; + PFILE_OBJECT FileObject = OldOpenP->FileObject; + + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisKillOpen\n"); + NdisPrint3(" Closing Adapter %wZ as requested by %wZ\n", + &OldOpenP->AdapterHandle->AdapterName, + &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name); + } + IF_ERROR_CHK { + if (DbgIsNull(OldOpenP)) { + NdisPrint1("NdisKillOpen: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OldOpenP)) { + NdisPrint1("NdisKillOpen: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&OldOpenP->SpinLock); + + // + // See if this open is already closing. + // + + if (OldOpenP->Closing) { + RELEASE_SPIN_LOCK(&OldOpenP->SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n"); + return TRUE; + } + + + // + // Indicate to others that this open is closing. + // + + OldOpenP->Closing = TRUE; + RELEASE_SPIN_LOCK(&OldOpenP->SpinLock); + + // + // Inform the MAC. + // + + if ((OldOpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) ( + OldOpenP->MacBindingHandle) == NDIS_STATUS_PENDING) { + + // + // MacCloseAdapter pended, will complete later. + // + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n"); + return FALSE; + } + + // + // Remove the reference for this open. + // + ObDereferenceObject((PVOID)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 adpater list + // + ACQUIRE_SPIN_LOCK(&GlobalOpenListLock); + + if (GlobalOpenList == OldOpenP) { + + GlobalOpenList = OldOpenP->NextGlobalOpen; + + } else { + + TmpOpen = GlobalOpenList; + + while (TmpOpen->NextGlobalOpen != OldOpenP) { + + TmpOpen = TmpOpen->NextGlobalOpen; + + } + + TmpOpen->NextGlobalOpen = OldOpenP->NextGlobalOpen; + + } + + RELEASE_SPIN_LOCK(&GlobalOpenListLock); + + ExFreePool((PVOID)OldOpenP); + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==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. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisQueueAdapterOnMac\n"); + NdisPrint2(" Adapter %wZ being added to MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name); + } + + IF_ERROR_CHK { + if (DbgIsNull(AdaptP)) { + NdisPrint1("NdisQueueAdapterOnMac: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(AdaptP)) { + NdisPrint1("NdisQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacP)) { + NdisPrint1("NdisQueueAdapterOnMac: Null Mac Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(MacP)) { + NdisPrint1("NdisQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock); + + // + // Make sure the MAC is not closing. + // + + if (MacP->Ref.Closing) { + RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n"); + return FALSE; + } + + + // + // Add this adapter at the head of the queue + // + + AdaptP->NextAdapter = MacP->AdapterQueue; + MacP->AdapterQueue = AdaptP; + + RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n"); + return TRUE; +} + + +VOID +NdisDeQueueAdapterOnMac( + PNDIS_ADAPTER_BLOCK AdaptP, + 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. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeQueueAdapterOnMac\n"); + NdisPrint2(" Adapter %wZ being removed from MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name); + } + IF_ERROR_CHK { + if (DbgIsNull(AdaptP)) { + NdisPrint1("NdisDeQueueAdapterOnMac: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(AdaptP)) { + NdisPrint1("NdisDeQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(MacP)) { + NdisPrint1("NdisDeQueueAdapterOnMac: Null Mac Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(MacP)) { + NdisPrint1("NdisDeQueueAdapterOnMac: Mac Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock); + + // + // 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; + } + + RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock); + + if (MacP->Unloading && (MacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL)) { + + KeSetEvent( + &MacP->AdaptersRemovedEvent, + 0L, + FALSE + ); + + } + + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnMac\n"); +} + + + +VOID +NdisKillAdapter( + 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. + // + + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisKillAdapter\n"); + NdisPrint2(" Removing Adapter %s\n",OldAdaptP->AdapterName.Buffer); + } + IF_ERROR_CHK { + if (DbgIsNull(OldAdaptP)) { + NdisPrint1("NdisKillAdapter: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OldAdaptP)) { + NdisPrint1("NdisKillAdapter: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + if (!NdisCloseRef(&OldAdaptP->Ref)) { + IF_TRACE(TRACE_IMPT) NdisPrint1("<==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); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n"); +} + + + +VOID +NdisDereferenceAdapter( + 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) { + + ExFreePool(AdaptP->Resources); + + } + + ExFreePool(AdaptP->AdapterName.Buffer); + + if (AdaptP->Master) { + UINT i; + ULONG MapRegistersPerChannel = + ((AdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2; + KIRQL OldIrql; + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + for (i=0; iPhysicalMapRegistersNeeded; i++) { + IoFreeMapRegisters( + AdaptP->SystemAdapterObject, + AdaptP->MapRegisters[i].MapRegister, + MapRegistersPerChannel); + } + + KeLowerIrql(OldIrql); + } + + if ((AdaptP->NumberOfPorts > 0) && AdaptP->InitialPortMapped) { + MmUnmapIoSpace (AdaptP->InitialPortMapping, AdaptP->NumberOfPorts); + } + + 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. + +--*/ + +{ + // attach ourselves to the adapter object linked list of opens + ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + + // + // Make sure the adapter is not closing. + // + + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisQueueAdapterOnAdapter\n"); + NdisPrint2(" Open being added to list for Adapter %s\n",AdaptP->AdapterName.Buffer); + } + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisQueueOpenOnAdapter: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(AdaptP)) { + NdisPrint1("NdisQueueOpenOnAdapter: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(AdaptP)) { + NdisPrint1("NdisQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + if (AdaptP->Ref.Closing) { + RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n"); + return FALSE; + } + + + // + // Attach this open at the head of the queue. + // + + OpenP->AdapterNextOpen = AdaptP->OpenQueue; + AdaptP->OpenQueue = OpenP; + + + RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n"); + return TRUE; +} + +VOID +NdisDeQueueOpenOnAdapter( + PNDIS_OPEN_BLOCK OpenP, + 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. + +--*/ + +{ + IF_TRACE(TRACE_IMPT) { + NdisPrint1("==>NdisDeQueueAdapterOnAdapter\n"); + NdisPrint2(" Open being removed from list for Adapter %s\n",AdaptP->AdapterName.Buffer); + } + IF_ERROR_CHK { + if (DbgIsNull(OpenP)) { + NdisPrint1("NdisDeQueueOpenOnAdapter: Null Open Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(OpenP)) { + NdisPrint1("NdisDeQueueOpenOnAdapter: Open Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + if (DbgIsNull(AdaptP)) { + NdisPrint1("NdisDeQueueOpenOnAdapter: Null Adapter Block\n"); + DbgBreakPoint(); + } + if (!DbgIsNonPaged(AdaptP)) { + NdisPrint1("NdisDeQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n"); + DbgBreakPoint(); + } + } + + ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + // + // 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; + } + + RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock); + IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnAdapter\n"); +} + + +VOID +NdisDereferenceMac( + 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. + +--*/ +{ + if (NdisDereferenceRef(&(MacP)->Ref)) { + + // + // Remove it from the global list. + // + + ACQUIRE_SPIN_LOCK(&NdisMacListLock); + + if (NdisMacList == MacP) { + + NdisMacList = MacP->NextMac; + + } else { + + PNDIS_MAC_BLOCK TmpMacP = NdisMacList; + + while(TmpMacP->NextMac != MacP) { + + TmpMacP = TmpMacP->NextMac; + + } + + TmpMacP->NextMac = TmpMacP->NextMac->NextMac; + + } + + RELEASE_SPIN_LOCK(&NdisMacListLock); + + if ( MacP->PciAssignedResources != NULL ) { + ExFreePool( MacP->PciAssignedResources ); + } + + ExFreePool((PVOID)(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); +} + + + +NTSTATUS +WrapperSaveLinkage( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) + +/*++ + +Routine Description: + + This routine is a callback routine for RtlQueryRegistryValues + It is called with the values for the "Bind" and "Export" multi-strings + for a given driver. It allocates memory to hold the data and copies + it over. + +Arguments: + + ValueName - The name of the value ("Bind" or "Export" -- ignored). + + ValueType - The type of the value (REG_MULTI_SZ -- ignored). + + ValueData - The null-terminated data for the value. + + ValueLength - The length of ValueData. + + Context - Unused. + + EntryContext - A pointer to the pointer that holds the copied data. + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + PWSTR * Data = ((PWSTR *)EntryContext); + + UNREFERENCED_PARAMETER(ValueName); + UNREFERENCED_PARAMETER(ValueType); + UNREFERENCED_PARAMETER(Context); + + + *Data = ExAllocatePoolWithTag (NonPagedPool, ValueLength, ' DN'); + + if (*Data == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory (*Data, ValueData, ValueLength); + + return STATUS_SUCCESS; + +} + + +NTSTATUS +WrapperCheckRoute( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) + +/*++ + +Routine Description: + + This routine is a callback routine for RtlQueryRegistryValues + It is called with the value for the "Route" multi-string. It + counts the number of "'s in the first string and if it is + more than two than it knows that this is a layered driver. + +Arguments: + + ValueName - The name of the value ("Route" -- ignored). + + ValueType - The type of the value (REG_MULTI_SZ -- ignored). + + ValueData - The null-terminated data for the value. + + ValueLength - The length of ValueData. + + Context - Unused. + + EntryContext - A pointer to a BOOLEAN that is set to TRUE + if the driver is layered. + +Return Value: + + STATUS_SUCCESS + +--*/ + +{ + + PWSTR CurRouteLoc = (PWSTR)ValueData; + UINT QuoteCount = 0; + + UNREFERENCED_PARAMETER(ValueName); + UNREFERENCED_PARAMETER(ValueType); + UNREFERENCED_PARAMETER(ValueLength); + UNREFERENCED_PARAMETER(Context); + + while (*CurRouteLoc != 0) { + + if (*CurRouteLoc == (WCHAR)L'"') { + ++QuoteCount; + } + ++CurRouteLoc; + } + + if (QuoteCount > 2) { + *(PBOOLEAN)EntryContext = TRUE; + } + + return STATUS_SUCCESS; + +} + +NDIS_STATUS +NdisCallDriverAddAdapter( + IN PNDIS_MAC_BLOCK NewMacP + ) + +/*++ + +Routine Description: + + Reads the driver registry bindings and calls add adapter for each + one. + +Arguments: + + NewMacP - Pointer to the Mac block allocated for this Mac. + +Return Value: + + None. + +--*/ +{ + // + // Pointer to a Miniport + // + PNDIS_M_DRIVER_BLOCK WDriver = (PNDIS_M_DRIVER_BLOCK)NewMacP; + + // + // Number of adapters added successfully + // + UINT AdaptersAdded = 0; + + // + // Status of calls to MacAddAdapter + // + NDIS_STATUS AddAdapterStatus; + + // + // Status of calls to MiniportInitialize + // + NDIS_STATUS MiniportInitializeStatus; + NDIS_STATUS OpenErrorStatus; + + UINT SelectedMediumIndex; + + NDIS_MEDIUM MediumArray[] = {NdisMedium802_3, + NdisMedium802_5, + NdisMediumFddi, + NdisMediumArcnet878_2, + NdisMediumWan }; + + UINT MediumArraySize = 5; + + // + // Status of registry requests. + // + NTSTATUS RegistryStatus; + NTSTATUS NtStatus; + + // + // subkey containing the card parameters + // + PWSTR Linkage = L"Linkage"; + + // + // subkeys below "Linkage" + // + + PWSTR Bind = L"Bind"; + PWSTR Export = L"Export"; + PWSTR Route = L"Route"; + + // + // These hold the REG_MULTI_SZ read from "Bind" and "Export". + // + + PWSTR BindData; + PWSTR ExportData; + + // + // These hold our place in the REG_MULTI_SZ read for + // "Bind" and "Export". + // + + PWSTR CurBindValue; + PWSTR CurExportValue; + + // + // Will be set to TRUE if the driver is layered (that is, + // it binds to another NDIS driver, not to an adapter). + // + + BOOLEAN LayeredDriver; + + // + // subkey below the driver's service key. + // + + PWSTR Parameters = L"Parameters"; + + // + // The path to our configuration data. + // + PUNICODE_STRING ConfigurationString; + + // + // Holds a null-terminated copy of ConfigurationString + // + PWSTR ConfigurationPath; + + ULONG i; + ULONG BusNumber; + NDIS_INTERFACE_TYPE BusType; + + // + // Holds the key below services where Parameters are stored. + // + PWCH BaseFileName; + + // + // Used to instruct RtlQueryRegistryValues to read the + // Linkage\Bind and Linkage\Export keys + // + RTL_QUERY_REGISTRY_TABLE LinkageQueryTable[5]; + + // + // Used to instruct RtlQueryRegistryValues to read the + // [Driver]\Parameters keys. This is passed as the + // ConfigContext to the MacAddAdapter routine. + // + + NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle; + + NDIS_WRAPPER_CONFIGURATION_HANDLE WrapperConfigurationHandle; + + // + // Used for calls to other Ndis routines + // + NDIS_STATUS NdisStatus; + + BOOLEAN IsAMiniport; + +#define BLOCK_LOCK_MINIPORT(_M, _L) \ + { \ + ACQUIRE_SPIN_LOCK(&_M->Lock); \ + LOCK_MINIPORT(_M, _L); \ + while (!_L) { \ + UNLOCK_MINIPORT(_M, _L); \ + RELEASE_SPIN_LOCK(&_M->Lock); \ + ACQUIRE_SPIN_LOCK(&_M->Lock); \ + LOCK_MINIPORT(_M, _L); \ + } \ + RELEASE_SPIN_LOCK(&_M->Lock); \ + } + + IsAMiniport = (WDriver->MiniportIdField == (NDIS_HANDLE)0x01); + + // + // Set up LinkageQueryTable to do the following: + // + + // + // 1) Switch to the Linkage key below this driver's key + // + + LinkageQueryTable[0].QueryRoutine = NULL; + LinkageQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; + LinkageQueryTable[0].Name = Linkage; + + // + // 2) Call WrapperSaveLinkage for "Bind" (as a single multi-string), + // which will allocate storage and save the data in BindData. + // + + LinkageQueryTable[1].QueryRoutine = WrapperSaveLinkage; + LinkageQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; + LinkageQueryTable[1].Name = Bind; + LinkageQueryTable[1].EntryContext = (PVOID)&BindData; + LinkageQueryTable[1].DefaultType = REG_NONE; + + // + // 3) Call WrapperSaveLinkage for "Export" (as a single multi-string) + // which will allocate storage and save the data in ExportData. + // + + LinkageQueryTable[2].QueryRoutine = WrapperSaveLinkage; + LinkageQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; + LinkageQueryTable[2].Name = Export; + LinkageQueryTable[2].EntryContext = (PVOID)&ExportData; + LinkageQueryTable[2].DefaultType = REG_NONE; + + // + // 4) Call WrapperCheckRoute for "Route" (as a single multi-string) + // which will set LayeredDriver to TRUE for a layered driver (this + // is optional, the default is FALSE). + // + + LinkageQueryTable[3].QueryRoutine = WrapperCheckRoute; + LinkageQueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND; + LinkageQueryTable[3].Name = Route; + LinkageQueryTable[3].EntryContext = (PVOID)&LayeredDriver; + LinkageQueryTable[3].DefaultType = REG_NONE; + + LayeredDriver = FALSE; + + // + // 5) Stop + // + + LinkageQueryTable[4].QueryRoutine = NULL; + LinkageQueryTable[4].Flags = 0; + LinkageQueryTable[4].Name = NULL; + + + // + // Allocate room for a null-terminated version of the config path + // + + if (IsAMiniport) { + + ConfigurationString = (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle); + + } else { + + ConfigurationString = (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle); + + } + + ConfigurationPath = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + ConfigurationString->Length + sizeof(WCHAR), + ' DN'); + if (ConfigurationPath == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory (ConfigurationPath, ConfigurationString->Buffer, ConfigurationString->Length); + *(PWCHAR)(((PUCHAR)ConfigurationPath)+ConfigurationString->Length) = (WCHAR)L'\0'; + + BindData = NULL; + ExportData = NULL; + + RegistryStatus = RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE, + ConfigurationPath, + LinkageQueryTable, + (PVOID)NULL, // no context needed + NULL); + + if (!NT_SUCCESS(RegistryStatus)) { + + // + // Free memory if needed, exit. + // + + ExFreePool (ConfigurationPath); + + if (BindData != NULL) { + ExFreePool (BindData); + } + if (ExportData != NULL) { + ExFreePool (ExportData); + } + +#if DBG + if (IsAMiniport) { + + DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n", + (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle), + RegistryStatus); + + } else { + + DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n", + (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle), + RegistryStatus); + + } +#endif + return NDIS_STATUS_FAILURE; + + } + + // + // NdisReadConfiguration assumes that ParametersQueryTable[3].Name is + // a key below the services key where the Parameters should be read, + // for layered drivers we store the last piece of Configuration + // Path there, leading to the desired effect. + // + // I.e, ConfigurationPath == "...\Services\Driver". + // + // For a layered driver, ParameterQueryTable[3].Name is "Driver" + // for all calls to AddAdapter, and parameters are read from + // "...\Services\Driver\Parameters" for all calls. + // + // For a non-layered driver, ParametersQueryTable[3].Name might be + // "Driver01" for the first call to AddAdapter, "Driver02" for the + // second, etc., and parameters are read from + // "..\Services\Driver01\Parameters" for the first call to + // AddAdapter, "...\Services\Driver02\Parameters" for the second + // call, etc. + // + + if (LayeredDriver) { + + BaseFileName = ConfigurationPath; + + for ( i = 0; i < ConfigurationString->Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set BaseFileName to + // the character after the separator. + // + + if ( ConfigurationPath[i] == OBJ_NAME_PATH_SEPARATOR ) { + BaseFileName = &(ConfigurationPath[++i]); + } + + } + +#if DBG + DbgPrint ("NDIS: Loading layered driver %ws\n", BaseFileName); +#endif + + } + + + // + // Set up ParametersQueryTable. We set most of it up here, + // then call the MAC's AddAdapter routine with its address + // as a ConfigContext. Inside ReadConfiguration, we get + // the ConfigContext back and can then finish initializing + // the table and use RtlQueryRegistryValues (with a + // callback to WrapperSaveParameter) to read the value + // specified. + // + + + // + // 1) Switch to the Parameters key below the [DriverName] key + // (DriverName is passed as a parameter to RtlQueryRegistryValues). + // + + ConfigurationHandle.ParametersQueryTable[0].QueryRoutine = NULL; + ConfigurationHandle.ParametersQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; + ConfigurationHandle.ParametersQueryTable[0].Name = Parameters; + + // + // 2) Call WrapperSaveParameter for a parameter, which + // will allocate storage for it. + // + // ParametersQueryTable[1].Name and ParametersQueryTable[1].EntryContext + // are filled in inside ReadConfiguration, in preparation + // for the callback. + // + + ConfigurationHandle.ParametersQueryTable[1].QueryRoutine = WrapperSaveParameters; + ConfigurationHandle.ParametersQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND; + ConfigurationHandle.ParametersQueryTable[1].DefaultType = REG_NONE; + + // + // 3) Stop + // + + ConfigurationHandle.ParametersQueryTable[2].QueryRoutine = NULL; + ConfigurationHandle.ParametersQueryTable[2].Flags = 0; + ConfigurationHandle.ParametersQueryTable[2].Name = NULL; + + // + // NOTE: Some fields in ParametersQueryTable[3] are used to + // store information for later retrieval. + // + + + + // + // OK, Now lock down all the filter packages. If a MAC or + // Miniport driver uses any of these, then the filter package + // will reference itself, to keep the image in memory. + // + ArcReferencePackage(); + EthReferencePackage(); + FddiReferencePackage(); + TrReferencePackage(); + MiniportReferencePackage(); + NdisMacReferencePackage(); + + // + // For each binding, get the handle to the card object. + // Call the driver's addadapter routine. + // + + CurBindValue = BindData; + CurExportValue = ExportData; + + while ((*CurBindValue != 0) && (*CurExportValue != 0)) { + + UNICODE_STRING CurBindString; + UNICODE_STRING CurExportString; + NDIS_CONFIGURATION_HANDLE TmpConfigHandle; + NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType"); + NDIS_STRING BusNumberStr = NDIS_STRING_CONST("BusNumber"); + PNDIS_CONFIGURATION_PARAMETER ReturnedValue; + PDEVICE_OBJECT TmpDeviceP; + PNDIS_MINIPORT_BLOCK Miniport; + LARGE_INTEGER TimeoutValue; + + TimeoutValue.QuadPart = Int32x32To64(100 * 1000, -10000); + + // + // Setup the query table to point to the section in + // the registry corresponding to what was specified + // in "Bind". The "Parameters" key below this is where + // config parameters are read from. + // + + RtlInitUnicodeString (&CurBindString, CurBindValue); + + // + // For layered drivers, BaseFileName is already + // initialized. + // + + if (!LayeredDriver) { + + // + // Parse out the path name, leaving only the driver name. + // + + BaseFileName = CurBindString.Buffer; + + for ( i = 0; i < CurBindString.Length / sizeof(WCHAR); i++ ) { + + // + // If s points to a directory separator, set fileBaseName to + // the character after the separator. + // + + if ( CurBindString.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) { + BaseFileName = &(CurBindString.Buffer[++i]); + } + + } + + // + // Set this to NULL, in case NdisReadBindingInformation + // is called. + // + + ConfigurationHandle.ParametersQueryTable[3].EntryContext = NULL; + + } else { + + // + // This will be returned by NdisReadBindingInformation. + // + + ConfigurationHandle.ParametersQueryTable[3].EntryContext = CurBindValue; + + } + + + // + // Save the driver name here; later we will use this as + // a parameter to RtlQueryRegistryValues. + // + + ConfigurationHandle.ParametersQueryTable[3].Name = BaseFileName; + + // + // Also, save the BusType and BusNumber so that we can pull them + // out in NdisRegisterAdapter(), NdisReadEisaSlotInformation() and + // NdisReadPosInformation(). + // + + TmpConfigHandle.KeyQueryTable = ConfigurationHandle.ParametersQueryTable; + TmpConfigHandle.ParameterList = NULL; + + // + // Read Bus Number + // + + NdisReadConfiguration( + &NdisStatus, + &ReturnedValue, + &TmpConfigHandle, + &BusNumberStr, + NdisParameterInteger + ); + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + BusNumber = ReturnedValue->ParameterData.IntegerData; + + } else { + + BusNumber = (ULONG)(-1); + } + + // + // Read Bus Type + // + + NdisReadConfiguration( + &NdisStatus, + &ReturnedValue, + &TmpConfigHandle, + &BusTypeStr, + NdisParameterInteger + ); + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + + BusType = (NDIS_INTERFACE_TYPE)(ReturnedValue->ParameterData.IntegerData); + + } else { + + BusType = (NDIS_INTERFACE_TYPE)(-1); + + } + + ConfigurationHandle.ParametersQueryTable[3].DefaultType = (ULONG)(BusType); + ConfigurationHandle.ParametersQueryTable[3].DefaultLength = (ULONG)(BusNumber); + ConfigurationHandle.ParametersQueryTable[3].DefaultData = NULL; + + // + // Call adapter callback. The current value for "Export" + // is what we tell him to name this device. + // + + RtlInitUnicodeString (&CurExportString, CurExportValue); + + if (IsAMiniport) + { + ConfigurationHandle.DriverObject = WDriver->NdisDriverInfo->NdisWrapperDriver; + } + else + { + ConfigurationHandle.DriverObject = NewMacP->NdisMacInfo->NdisWrapperDriver; + } + + if (IsAMiniport) + { + KIRQL OldIrql; + ULONG MaximumLongAddresses; + UCHAR CurrentLongAddress[6]; + ULONG MaximumShortAddresses; + UCHAR CurrentShortAddress[2]; + UINT BytesWritten; + UINT BytesNeeded; + UINT PacketFilter = 0x1; + UCHAR i; + BOOLEAN LocalLock; + PARC_BUFFER_LIST Buffer; + PVOID DataBuffer; + + // + // Initialize device. + // + + if (!NdisReferenceDriver((PNDIS_M_DRIVER_BLOCK)WDriver)) { + + // + // The driver is closing. + // + + goto LoopBottom; + + } + + NtStatus = IoCreateDevice( + WDriver->NdisDriverInfo->NdisWrapperDriver, + sizeof(NDIS_MINIPORT_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size + &CurExportString, + FILE_DEVICE_PHYSICAL_NETCARD, + 0, + FALSE, // exclusive flag + &TmpDeviceP + ); + + if (NtStatus != STATUS_SUCCESS) { + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + + // + // Initialize the Miniport adapter block in the device object extension + // + // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than + // NDIS_MINIPORT_BLOCK, so we put it first in the extension. + // + + Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1); + + Miniport->WrapperContext = TmpDeviceP->DeviceExtension; + + Miniport->BusType = BusType; + Miniport->BusNumber = BusNumber; + Miniport->DeviceObject = TmpDeviceP; + Miniport->DriverHandle = WDriver; + Miniport->MiniportName.Buffer = (PWSTR)ExAllocatePoolWithTag( + NonPagedPool, + CurExportString.MaximumLength, + 'naDN' + ); + + if (Miniport->MiniportName.Buffer == NULL) { + NdisDereferenceDriver(WDriver); + IoDeleteDevice(TmpDeviceP); + goto LoopBottom; + } + + Miniport->MiniportName.MaximumLength = CurExportString.MaximumLength; + Miniport->MiniportName.Length = CurExportString.Length; + + RtlCopyMemory(Miniport->MiniportName.Buffer, + CurExportString.Buffer, + CurExportString.MaximumLength + ); + + Miniport->OpenQueue = (PNDIS_M_OPEN_BLOCK)NULL; + Miniport->EthDB = NULL; + Miniport->TrDB = NULL; + Miniport->FddiDB = NULL; + Miniport->ArcDB = NULL; + Miniport->BeingRemoved = FALSE; + Miniport->SendResourcesAvailable = 0xffffff; + Miniport->Flags = 0; // a value that cannot be a pointer. + Miniport->InAddDriver = TRUE; + NdisAllocateSpinLock(&Miniport->Lock); + //KeSetSpecialSpinLock(&Miniport->Lock, "miniport lock" ); + + NdisInitializeRef(&Miniport->Ref); + + NdisInitializeTimer( + &Miniport->DpcTimer, + (PVOID) NdisMDpcTimer, + (PVOID) Miniport + ); + + NdisInitializeTimer( + &Miniport->WakeUpDpcTimer, + (PVOID) NdisMWakeUpDpc, + (PVOID) Miniport + ); + + if (!NdisQueueMiniportOnDriver(Miniport, WDriver)) { + + // + // The Driver is closing, undo what we have done. + // + + ExFreePool(Miniport->MiniportName.Buffer); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + + // + // Now we do something really bogus. We create many + // temporary filter databases, just in case any indications + // happen. + // + + if (!EthCreateFilter( + 1, + NdisMChangeEthAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &(Miniport->EthDB) + )) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + if (!TrCreateFilter( + NdisMChangeFunctionalAddress, + NdisMChangeGroupAddress, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &(Miniport->TrDB) + )) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + if (!FddiCreateFilter( + 1, + 1, + NdisMChangeFddiAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + CurrentShortAddress, + &Miniport->Lock, + &(Miniport->FddiDB) + )) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + if (!ArcCreateFilter( + Miniport, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress[0], + &Miniport->Lock, + &(Miniport->ArcDB) + )) { + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Call adapter callback. The current value for "Export" + // is what we tell him to name this device. + // + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + MiniportInitializeStatus = + (WDriver->MiniportCharacteristics.InitializeHandler)( + &OpenErrorStatus, + &SelectedMediumIndex, + MediumArray, + MediumArraySize, + (NDIS_HANDLE)(Miniport), + (NDIS_HANDLE)&ConfigurationHandle + ); + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + // + // Free the slot information buffer + // + + if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) { + + ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData); + + } + + if (MiniportInitializeStatus == NDIS_STATUS_SUCCESS) { + + ASSERT(SelectedMediumIndex < MediumArraySize); + + Miniport->MediaType = MediumArray[SelectedMediumIndex]; + + KeInitializeEvent( + &Miniport->RequestEvent, + NotificationEvent, + FALSE + ); + + KeResetEvent( + &Miniport->RequestEvent + ); + + // + // Query maximum lookahead + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_GEN_MAXIMUM_LOOKAHEAD, + &MaximumLongAddresses, + sizeof(MaximumLongAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x1 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x2 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + // + // Now adjust based on media type + // + + switch(Miniport->MediaType) { + + case NdisMedium802_3: + + Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 14 < MaximumLongAddresses) ? + NDIS_M_MAX_LOOKAHEAD - 14 : + MaximumLongAddresses; + break; + + case NdisMedium802_5: + + Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 32 < MaximumLongAddresses) ? + NDIS_M_MAX_LOOKAHEAD - 32 : + MaximumLongAddresses; + break; + + case NdisMediumFddi: + Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 16 < MaximumLongAddresses) ? + NDIS_M_MAX_LOOKAHEAD - 16 : + MaximumLongAddresses; + break; + + case NdisMediumArcnet878_2: + Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 50 < MaximumLongAddresses) ? + NDIS_M_MAX_LOOKAHEAD - 50 : + MaximumLongAddresses; + break; + + case NdisMediumWan: + Miniport->MaximumLookahead = 1514; + + } + + Miniport->CurrentLookahead = Miniport->MaximumLookahead; + + // + // Query mac options + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_GEN_MAC_OPTIONS, + &MaximumLongAddresses, + sizeof(MaximumLongAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x3 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + Miniport->MacOptions = (UINT)MaximumLongAddresses; + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x4 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Create filter package + // + switch(Miniport->MediaType) { + + case NdisMedium802_3: + + // + // Query maximum MulticastAddress + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_802_3_MAXIMUM_LIST_SIZE, + &MaximumLongAddresses, + sizeof(MaximumLongAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x5 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) { + + MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST; + + } + + Miniport->MaximumLongAddresses = MaximumLongAddresses; + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x6 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_802_3_CURRENT_ADDRESS, + &(CurrentLongAddress), + sizeof(CurrentLongAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x7 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x8 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + if (!EthCreateFilter( + MaximumLongAddresses, + NdisMChangeEthAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &Miniport->EthDB + )) { + + // + // Halt the miniport driver + // + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x9 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + case NdisMedium802_5: + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_802_5_CURRENT_ADDRESS, + &(CurrentLongAddress), + sizeof(CurrentLongAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xA + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xB + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + if (!TrCreateFilter( + NdisMChangeFunctionalAddress, + NdisMChangeGroupAddress, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &Miniport->TrDB + )) { + + // + // Halt the miniport driver + // + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0xC + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + case NdisMediumFddi: + + // + // Query maximum MulticastAddress + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_FDDI_LONG_MAX_LIST_SIZE, + &MaximumLongAddresses, + sizeof(MaximumLongAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xD + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) { + + MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST; + + } + + Miniport->MaximumLongAddresses = MaximumLongAddresses; + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xE + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Query maximum MulticastAddress + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_FDDI_SHORT_MAX_LIST_SIZE, + &MaximumShortAddresses, + sizeof(MaximumShortAddresses), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0xF + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (MaximumShortAddresses > NDIS_M_MAX_MULTI_LIST) { + + MaximumShortAddresses = NDIS_M_MAX_MULTI_LIST; + + } + + Miniport->MaximumShortAddresses = MaximumShortAddresses; + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x10 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_FDDI_LONG_CURRENT_ADDR, + &(CurrentLongAddress), + sizeof(CurrentLongAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x11 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x12 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_FDDI_SHORT_CURRENT_ADDR, + &(CurrentShortAddress), + sizeof(CurrentShortAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x13 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x14 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + if (!FddiCreateFilter( + MaximumLongAddresses, + MaximumShortAddresses, + NdisMChangeFddiAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + CurrentShortAddress, + &Miniport->Lock, + &Miniport->FddiDB + )) { + + // + // Halt the miniport driver + // + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x15 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + case NdisMediumArcnet878_2: + + // + // In case of an encapsulated ethernet binding, we need + // to return the maximum number of multicast addresses + // possible. + // + + Miniport->MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST; + + // + // Allocate Buffer pools + // + NdisAllocateBufferPool(&NdisStatus, + &Miniport->ArcnetBufferPool, + WRAPPER_ARC_BUFFERS + ); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x16 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + NdisAllocateMemory((PVOID)&Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0, + HighestAcceptableMax + ); + + if (Buffer == NULL) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x18 + ); + NdisFreeBufferPool(Miniport->ArcnetBufferPool); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + NdisAllocateMemory((PVOID)&DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0, + HighestAcceptableMax + ); + + + if (DataBuffer == NULL) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x19 + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeBufferPool(Miniport->ArcnetBufferPool); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + for (i = WRAPPER_ARC_BUFFERS; i != 0 ; i--) { + + Buffer->BytesLeft = Buffer->Size = WRAPPER_ARC_HEADER_SIZE; + Buffer->Buffer = DataBuffer; + Buffer->Next = Miniport->ArcnetFreeBufferList; + Miniport->ArcnetFreeBufferList = Buffer; + + Buffer++; + DataBuffer = (PVOID)(((PUCHAR)DataBuffer) + + WRAPPER_ARC_HEADER_SIZE); + + } + + + // + // Get current address + // + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_ARCNET_CURRENT_ADDRESS, + &CurrentLongAddress[5], // address = 00-00-00-00-00-XX + 1, + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x1A + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeMemory(DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeBufferPool(Miniport->ArcnetBufferPool); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x1B + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeMemory(DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->ArcnetAddress = CurrentLongAddress[5]; + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + if (!ArcCreateFilter( + Miniport, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress[5], + &Miniport->Lock, + &(Miniport->ArcDB) + )) { + + // + // Halt the miniport driver + // + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x1C + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeMemory(DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // Zero all but the last one. + + CurrentLongAddress[0] = 0; + CurrentLongAddress[1] = 0; + CurrentLongAddress[2] = 0; + CurrentLongAddress[3] = 0; + CurrentLongAddress[4] = 0; + + if (!EthCreateFilter( + 32, + NdisMChangeEthAddresses, + NdisMChangeClass, + NdisMCloseAction, + CurrentLongAddress, + &Miniport->Lock, + &Miniport->EthDB + )) { + + // + // Halt the miniport driver + // + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + 0xFF00FF00, + 0x1D + ); + NdisFreeMemory(Buffer, + sizeof(ARC_BUFFER_LIST) * + WRAPPER_ARC_BUFFERS, + 0 + ); + NdisFreeMemory(DataBuffer, + WRAPPER_ARC_HEADER_SIZE * + WRAPPER_ARC_BUFFERS, + 0 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + case NdisMediumWan: + + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryInformation; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_WAN_CURRENT_ADDRESS, + &(CurrentLongAddress), + sizeof(CurrentLongAddress), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x7 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + if (NdisStatus != NDIS_STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x8 + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + // + // Now undo the bogus filter package. We lock + // the miniport so that no dpcs will get queued. + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + Miniport->InInitialize = TRUE; + Miniport->NormalInterrupts = FALSE; + + EthDeleteFilter(Miniport->EthDB); + Miniport->EthDB = NULL; + TrDeleteFilter(Miniport->TrDB); + Miniport->TrDB = NULL; + FddiDeleteFilter(Miniport->FddiDB); + Miniport->FddiDB = NULL; + ArcDeleteFilter(Miniport->ArcDB); + Miniport->ArcDB = NULL; + + Miniport->InInitialize = FALSE; + CHECK_FOR_NORMAL_INTERRUPTS(Miniport); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + break; + + } + + // + // Get supported packet filters + // + Miniport->SupportedPacketFilters = 0; + + // + // Set the filter packages bit mask to fake it out. + // + if (Miniport->EthDB) { + Miniport->EthDB->CombinedPacketFilter = 0xFFFFFFFF; + } + if (Miniport->TrDB) { + Miniport->TrDB->CombinedPacketFilter = 0xFFFFFFFF; + } + if (Miniport->FddiDB) { + Miniport->FddiDB->CombinedPacketFilter = 0xFFFFFFFF; + } + + // + // For WAN there is no packet filter + // + + if (Miniport->MediaType==NdisMediumWan) { + goto SkipFilter; + } + + for (i=0; i<31; i++) { + + // + // Set packet filter + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_GEN_CURRENT_PACKET_FILTER, + &PacketFilter, + sizeof(PacketFilter), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + NtStatus = KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + &TimeoutValue + ); + + if (NtStatus != STATUS_SUCCESS) { + + // + // Halt the miniport driver + // + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + + (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) ( + Miniport->MiniportAdapterContext + ); + + UNLOCK_MINIPORT(Miniport, LocalLock); + + NdisWriteErrorLogEntry( + (NDIS_HANDLE)Miniport, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + 0xFF00FF00, + 0x1E + ); + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + + } + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + Miniport->SupportedPacketFilters |= PacketFilter; + } + + PacketFilter = PacketFilter << 1; + + } + + // + // Set packet filter + // + Miniport->MiniportRequest = &Miniport->InternalRequest; + PacketFilter = 0; + + Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics; + + BLOCK_LOCK_MINIPORT(Miniport, LocalLock); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + NdisStatus = + (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) ( + Miniport->MiniportAdapterContext, + OID_GEN_CURRENT_PACKET_FILTER, + &PacketFilter, + sizeof(PacketFilter), + &BytesWritten, + &BytesNeeded + ); + + KeLowerIrql(OldIrql); + UNLOCK_MINIPORT(Miniport, LocalLock); + + // + // Fire a DPC to do anything + // + if ((NdisStatus == NDIS_STATUS_PENDING) || + (NdisStatus == NDIS_STATUS_SUCCESS)) { + + Miniport->RunDpc = FALSE; + NdisSetTimer(&(Miniport->DpcTimer), 1); + + } + + if (NdisStatus == NDIS_STATUS_PENDING) { + + // + // The completion routine will set NdisRequestStatus. + // + + KeWaitForSingleObject( + &Miniport->RequestEvent, + Executive, + KernelMode, + TRUE, + (PLARGE_INTEGER)NULL + ); + + KeResetEvent( + &Miniport->RequestEvent + ); + + NdisStatus = Miniport->RequestStatus; + + } + + // + // Set the filter packages bit mask to fake it out. + // + if (Miniport->EthDB) { + Miniport->EthDB->CombinedPacketFilter = 0; + } + if (Miniport->TrDB) { + Miniport->TrDB->CombinedPacketFilter = 0; + } + if (Miniport->FddiDB) { + Miniport->FddiDB->CombinedPacketFilter = 0; + } + +SkipFilter: + + // + // Start wake up timer + // + NdisSetTimer(&(Miniport->WakeUpDpcTimer), 2000); + + // + // Done with adding this MINIPORT!!! + // + Miniport->MiniportRequest = NULL; + Miniport->InAddDriver = FALSE; + + IoRegisterShutdownNotification(Miniport->DeviceObject); + + ++AdaptersAdded; + + } else{ + + // + // Undo all the stuff from this mini-port + // + ExFreePool(Miniport->MiniportName.Buffer); + NdisDequeueMiniportOnDriver(Miniport, WDriver); + IoDeleteDevice(TmpDeviceP); + NdisDereferenceDriver(WDriver); + goto LoopBottom; + } + + } else { + + // + // NDIS 3.0 MAC + // + AddAdapterStatus = + (NewMacP->MacCharacteristics.AddAdapterHandler)( + NewMacP->MacMacContext, + &ConfigurationHandle, + &CurExportString + ); + + + // + // Free the slot information buffer + // + + if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) { + + ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData); + + } + + if (AddAdapterStatus == NDIS_STATUS_SUCCESS) { + ++AdaptersAdded; + } + + } + +LoopBottom: + + + // + // Now advance the "Bind" and "Export" values. + // + + CurBindValue = (PWCHAR)((PUCHAR)CurBindValue + CurBindString.MaximumLength); + CurExportValue = (PWCHAR)((PUCHAR)CurExportValue + CurExportString.MaximumLength); + + } + + + // + // OK, Now dereference all the filter packages. If a MAC or + // Miniport driver uses any of these, then the filter package + // will reference itself, to keep the image in memory. + // + ArcDereferencePackage(); + EthDereferencePackage(); + FddiDereferencePackage(); + TrDereferencePackage(); + MiniportDereferencePackage(); + NdisMacDereferencePackage(); + + // + // Now close the handles we opened at the beginning. + // + + + ExFreePool (ConfigurationPath); + ExFreePool (BindData); + ExFreePool (ExportData); + + // + // Succeed if any adapters were added. + // + + if (AdaptersAdded > 0) { + return NDIS_STATUS_SUCCESS; + } else { + return NDIS_STATUS_FAILURE; + } + +#undef BLOCK_LOCK_MINIPORT + +} + + +VOID +NdisReadEisaSlotInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData + ) + +/*++ + +Routine Description: + + This routine reads the EISA data from the slot given. + +Arguments: + + Status - Status of request to be returned to the user. + WrapperConfigurationContext - Context passed to MacAddAdapter. + SlotNumber - the EISA Slot where the card is at. + EisaData - pointer to a buffer where the EISA configuration is to be + returned. + +Return Value: + + None. + +--*/ +{ + PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer; + PNDIS_EISA_SLOT_INFORMATION SlotInformation; + NTSTATUS NtStatus; + ULONG BusNumber; + ULONG DataLength; + ULONG SearchSlotNumber; + ULONG FoundSlotNumber; + BOOLEAN Found; + NDIS_INTERFACE_TYPE BusType; + ULONG CompressedId = 0; + PWSTR CompressedIDString = L"EisaCompressedId"; + PWSTR SlotNumberString = L"SlotNumber"; + PWSTR Parameters = L"\\Parameters"; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + NDIS_CONFIGURATION_HANDLE NdisConfiguration; + ULONG Length; + PWSTR PathName; + + // + // Get the BusNumber and the BusType from the Context here!! + // + + NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + + BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType); + + BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength; + + // + // First check if any bus access is allowed + // + + if ((BusType == (NDIS_INTERFACE_TYPE)-1) || + (BusNumber == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData; + + *SlotNumber = 0; + + if (BusType != Eisa) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + + // + // Find the CompressedId for this board. + // + + NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if (NtStatus != NDIS_STATUS_SUCCESS) { + CompressedId = 0xffffffff; + } else if (ParameterValue->ParameterType != NdisParameterInteger) { + CompressedId = 0xffffffff; + } else { + CompressedId = ParameterValue->ParameterData.IntegerData; + } + + // + // Was there already a buffer allocated? + // + + if (SlotInformation == NULL) { + + // + // No, allocate a buffer + // + + SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + sizeof(NDIS_EISA_FUNCTION_INFORMATION), + 'isDN' + ); + + if (SlotInformation == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + // + // Free any old buffer + // + + if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) { + + ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData); + + } + + NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation; + + } + + // + // Now read the slot number + // + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if ((NtStatus == NDIS_STATUS_SUCCESS) && + (ParameterValue->ParameterType == NdisParameterInteger)) { + + *SlotNumber = ParameterValue->ParameterData.IntegerData; + + } else { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + *SlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + sizeof(NDIS_EISA_FUNCTION_INFORMATION) + ); + + if ((CompressedId != 0xFFFFFFFF) && + ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) { + + // + // The card seems to have been moved on us. Now we search for it. + // + + SearchSlotNumber = 1; + Found = FALSE; + + while (TRUE) { + + // + // Search this slot + // + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + SearchSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + sizeof(NDIS_EISA_FUNCTION_INFORMATION) + ); + + if ((DataLength == 0) || + (SearchSlotNumber == 0xFF)) { + // + // End of slots. + // + break; + + } + + if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) { + + // + // Found one! + // + + if (Found) { + + // + // Uh-oh, found two of them! Fail + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + Found = TRUE; + FoundSlotNumber = SearchSlotNumber; + + } + + SearchSlotNumber++; + + } + + if (!Found) { + // + // No card found + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Find the SlotNumber parameter in the registry. + // + + *SlotNumber = FoundSlotNumber; + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name); + + PathName = ExAllocatePoolWithTag(NonPagedPool, + sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR), + ' DN' + ); + + if (PathName != NULL) { + + NdisZeroMemory(PathName, sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR) + ); + + NdisMoveMemory(PathName, + NdisConfiguration.KeyQueryTable[3].Name, + Length * sizeof(WCHAR) + ); + + NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters")); + + // + // Update the value + // + + NtStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + PathName, + SlotNumberString, + REG_DWORD, + &FoundSlotNumber, + sizeof(FoundSlotNumber) + ); + + ExFreePool(PathName); + + } + + // + // Get the new information + // + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + FoundSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + sizeof(NDIS_EISA_FUNCTION_INFORMATION) + ); + + } + + EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION) + ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION)); + + *EisaData = *EisaBlockPointer; + *Status = NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisReadEisaSlotInformationEx( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT SlotNumber, + OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData, + OUT PUINT NumberOfFunctions + ) + +/*++ + +Routine Description: + + This routine reads the EISA data from the slot given. + +Arguments: + + Status - Status of request to be returned to the user. + WrapperConfigurationContext - Context passed to MacAddAdapter. + SlotNumber - the EISA Slot where the card is at. + EisaData - pointer to a buffer where the EISA configuration is to be + returned. + NumberOfFunctions - Returns the number of function structures in the EisaData. + +Return Value: + + None. + +--*/ +{ + PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer; + PNDIS_EISA_SLOT_INFORMATION SlotInformation; + NTSTATUS NtStatus; + ULONG BusNumber; + ULONG DataLength; + ULONG SearchSlotNumber; + ULONG FoundSlotNumber; + BOOLEAN Found; + NDIS_INTERFACE_TYPE BusType; + ULONG CompressedId = 0; + PWSTR CompressedIDString = L"EisaCompressedId"; + PWSTR SlotNumberString = L"SlotNumber"; + PWSTR Parameters = L"\\Parameters"; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + NDIS_CONFIGURATION_HANDLE NdisConfiguration; + ULONG Length; + PWSTR PathName; + + // + // Get the BusNumber and the BusType from the Context here!! + // + + NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + + BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType); + + BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength; + + // + // First check if any bus access is allowed + // + + if ((BusType == (NDIS_INTERFACE_TYPE)-1) || + (BusNumber == (ULONG)-1)) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData; + + *SlotNumber = 0; + *NumberOfFunctions = 2; + + if (BusType != Eisa) { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + + // + // Find the CompressedId for this board. + // + + NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if (NtStatus != NDIS_STATUS_SUCCESS) { + CompressedId = 0xffffffff; + } else if (ParameterValue->ParameterType != NdisParameterInteger) { + CompressedId = 0xffffffff; + } else { + CompressedId = ParameterValue->ParameterData.IntegerData; + } + + // + // Was there already a buffer allocated? + // + + if (SlotInformation == NULL) { + + // + // No, allocate a buffer + // + + SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * + sizeof(NDIS_EISA_FUNCTION_INFORMATION)), + 'isDN' + ); + + if (SlotInformation == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + // + // Free any old buffer + // + + if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) { + + ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData); + + } + + NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation; + + } + + // + // Now read the slot number + // + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if ((NtStatus == NDIS_STATUS_SUCCESS) && + (ParameterValue->ParameterType == NdisParameterInteger)) { + + *SlotNumber = ParameterValue->ParameterData.IntegerData; + + } else { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + *SlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)) + ); + + if ((CompressedId != 0xFFFFFFFF) && + ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) { + + // + // The card seems to have been moved on us. Now we search for it. + // + + SearchSlotNumber = 1; + Found = FALSE; + + while (TRUE) { + + // + // Search this slot + // + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + SearchSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)) + ); + + if ((DataLength == 0) || + (SearchSlotNumber == 0xFF)) { + // + // End of slots. + // + break; + + } + + if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) { + + // + // Found one! + // + + if (Found) { + + // + // Uh-oh, found two of them! Fail + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + Found = TRUE; + FoundSlotNumber = SearchSlotNumber; + + } + + SearchSlotNumber++; + + } + + if (!Found) { + // + // No card found + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Find the SlotNumber parameter in the registry. + // + + *SlotNumber = FoundSlotNumber; + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name); + + PathName = ExAllocatePoolWithTag(NonPagedPool, + sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR), + ' DN' + ); + + if (PathName != NULL) { + + NdisZeroMemory(PathName, sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR) + ); + + NdisMoveMemory(PathName, + NdisConfiguration.KeyQueryTable[3].Name, + Length * sizeof(WCHAR) + ); + + NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters")); + + // + // Update the value + // + + NtStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + PathName, + SlotNumberString, + REG_DWORD, + &FoundSlotNumber, + sizeof(FoundSlotNumber) + ); + + ExFreePool(PathName); + + } + + // + // Get the new information + // + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + FoundSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)) + ); + + } + + + // + // Now check for multiple functions in the Eisa data. + // + + while (DataLength == (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))) { + + *NumberOfFunctions++; + + // + // Now allocate a new buffer + // + + SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * + sizeof(NDIS_EISA_FUNCTION_INFORMATION)), + 'isDN' + ); + + if (SlotInformation == NULL) { + + *Status = NDIS_STATUS_RESOURCES; + return; + + } + + // + // Free any old buffer + // + + if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) { + + ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData); + + } + + NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation; + + // + // Get new information + // + + DataLength = HalGetBusData( + EisaConfiguration, + BusNumber, + FoundSlotNumber, + (PVOID)SlotInformation, + sizeof(NDIS_EISA_SLOT_INFORMATION) + + (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION)) + ); + + } + + EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION) + ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION)); + + *EisaData = EisaBlockPointer; + *NumberOfFunctions--; // We overshoot by 1 to verify last one found. + *Status = NDIS_STATUS_SUCCESS; + +} + + +VOID +NdisReadMcaPosInformation( + OUT PNDIS_STATUS Status, + IN NDIS_HANDLE WrapperConfigurationContext, + OUT PUINT ChannelNumber, + OUT PNDIS_MCA_POS_DATA McaData + ) + +/*++ + +Routine Description: + + This routine reads the MCA data from the POS corresponding to + the channel specified. + +Arguments: + + WrapperConfigurationContext - Context passed to MacAddAdapter. + ChannelNumber - the MCA channel number. + McaData - pointer to a buffer where the channel information is to be + returned. + +Return Value: + + None. + +--*/ +{ + OBJECT_ATTRIBUTES ObjectAttributes; + OBJECT_ATTRIBUTES BusObjectAttributes; + PWSTR McaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; + PWSTR ConfigData = L"Configuration Data"; + PWSTR PosIdString = L"McaPosId"; + PWSTR SlotNumberString = L"SlotNumber"; + UNICODE_STRING RootName; + UNICODE_STRING BusName; + UNICODE_STRING ConfigDataName; + NTSTATUS NtStatus; + PKEY_BASIC_INFORMATION BasicInformation; + PKEY_VALUE_FULL_INFORMATION ValueInformation; + PUCHAR BufferPointer; + PCM_FULL_RESOURCE_DESCRIPTOR FullResource; + PCM_PARTIAL_RESOURCE_LIST ResourceList; + PNDIS_MCA_POS_DATA McaBlockPointer; + HANDLE McaHandle, BusHandle; + ULONG BytesWritten, BytesNeeded; + ULONG Index; + ULONG i; + ULONG BusNumber; + ULONG MaxSlotNumber; + ULONG SearchSlotNumber; + ULONG FoundSlotNumber; + BOOLEAN Found; + USHORT PosId; + NDIS_INTERFACE_TYPE BusType; + NDIS_CONFIGURATION_HANDLE NdisConfiguration; + PNDIS_CONFIGURATION_PARAMETER ParameterValue; + PWSTR Parameters = L"\\Parameters"; + ULONG Length; + PWSTR PathName; + + *Status = NDIS_STATUS_FAILURE; + + NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + + // + // Get the BusNumber and the BusType from the Context here!! + // + + BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType); + BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength; + + // + // First check if any bus access is allowed + // + + if ((BusType == (NDIS_INTERFACE_TYPE)-1) || + (BusNumber == (ULONG)-1)) { + + return; + + } + + + if (BusType != MicroChannel) { + + return; + + } + + *ChannelNumber = 0; + + // + // Find the PosId for this board. + // + + NdisConfiguration.KeyQueryTable[1].Name = PosIdString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if (NtStatus != NDIS_STATUS_SUCCESS) { + PosId = 0xffff; + } else if (ParameterValue->ParameterType != NdisParameterInteger) { + PosId = 0xffff; + } else { + PosId = (USHORT)(ParameterValue->ParameterData.IntegerData); + } + + RtlInitUnicodeString( + &RootName, + McaPath + ); + + InitializeObjectAttributes( + &ObjectAttributes, + &RootName, + OBJ_CASE_INSENSITIVE, + (HANDLE)NULL, + NULL + ); + + // + // Open the root. + // + + NtStatus = ZwOpenKey( + &McaHandle, + KEY_READ, + &ObjectAttributes + ); + + if (!NT_SUCCESS(NtStatus)) { + + return; + + } + + Index = 0; + + while (TRUE) { + + // + // Enumerate through keys, searching for the proper bus number + // + + NtStatus = ZwEnumerateKey( + McaHandle, + Index, + KeyBasicInformation, + NULL, + 0, + &BytesNeeded + ); + + // + // That should fail! + // + + if (BytesNeeded == 0) { + + Index++; + continue; + + } + + BasicInformation = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + BytesNeeded, + ' DN' + ); + + if (BasicInformation == NULL) { + + ZwClose(McaHandle); + + return; + } + + NtStatus = ZwEnumerateKey( + McaHandle, + Index, + KeyBasicInformation, + BasicInformation, + BytesNeeded, + &BytesWritten + ); + + if (!NT_SUCCESS(NtStatus)) { + + ExFreePool(BasicInformation); + + ZwClose(McaHandle); + + return; + } + + + // + // Init the BusName String + // + + BusName.MaximumLength = (USHORT)BasicInformation->NameLength; + BusName.Length = (USHORT)BasicInformation->NameLength; + BusName.Buffer = BasicInformation->Name; + + // + // Now try to find Configuration Data within this Key + // + + InitializeObjectAttributes( + &BusObjectAttributes, + &BusName, + OBJ_CASE_INSENSITIVE, + (HANDLE)McaHandle, + NULL + ); + + // + // Open the MCA root + Bus Number + // + + NtStatus = ZwOpenKey( + &BusHandle, + KEY_READ, + &BusObjectAttributes + ); + + ExFreePool(BasicInformation); + + if (!NT_SUCCESS(NtStatus)) { + + Index++; + + continue; + + } + + // + // opening the configuration data. This first call tells us how + // much memory we need to allocate + // + + RtlInitUnicodeString( + &ConfigDataName, + ConfigData + ); + + // + // This should fail + // + + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + NULL, + 0, + &BytesNeeded + ); + + + ValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag( + NonPagedPool, + BytesNeeded, + ' DN' + ); + + + if (ValueInformation == NULL) { + + Index++; + + ZwClose(BusHandle); + + continue; + + } + + NtStatus = ZwQueryValueKey( + BusHandle, + &ConfigDataName, + KeyValueFullInformation, + ValueInformation, + BytesNeeded, + &BytesWritten + ); + + if (!NT_SUCCESS(NtStatus)) { + + Index++; + + ExFreePool(ValueInformation); + + ZwClose(BusHandle); + + continue; + + } + + // + // Search for our bus number and type + // + + + // + // What we got back from the registry is actually a blob of data that + // looks like this + // + // ------------------------------------------ + // |FULL |PAR |PAR |MCA |MCA |MCA | + // |RES. |RES |RES |POS |POS |POS | . . . + // |DESC |LIST|DESC|DATA|DATA|DATA| + // ------------------------------------------ + // slot 0 1 2 . . . + // + // Out of this mess we need to grovel a pointer to the first block + // of MCA_POS_DATA, then we can just index by slot number. + // + + BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset; + FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer; + + if (FullResource->InterfaceType != MicroChannel) { + + // + // Get next key + // + + ExFreePool(ValueInformation); + + Index++; + + ZwClose(BusHandle); + + continue; + + } + + if (FullResource->BusNumber != BusNumber) { + + // + // Get next key + // + + ExFreePool(ValueInformation); + + Index++; + + ZwClose(BusHandle); + + continue; + + } + + + // + // Found it!! + // + + ResourceList = &FullResource->PartialResourceList; + + // + // Find the device-specific information, which is where the POS data is. + // + + for (i=0; iCount; i++) { + if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific) { + break; + } + } + + if (i == ResourceList->Count) { + // + // Couldn't find device-specific information. + // + +#if DBG + DbgPrint("NDIS: couldn't find POS data in registry\n"); +#endif + + ExFreePool(ValueInformation); + *Status = NDIS_STATUS_ADAPTER_NOT_FOUND; + return; + + } + + // + // Was there a buffer already there? + // + + if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) { + + // + // Free it + // + + ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData); + + } + + // + // Now read the slot number + // + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + // + // Get the value from the registry; this chains it on to the + // parameter list at NdisConfiguration. + // + + NtStatus = RtlQueryRegistryValues( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + NdisConfiguration.KeyQueryTable, + &NdisConfiguration, // context + NULL); + + if ((NtStatus == NDIS_STATUS_SUCCESS) && + (ParameterValue->ParameterType == NdisParameterInteger)) { + + *ChannelNumber = ParameterValue->ParameterData.IntegerData; + + } else { + + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Store buffer + // + + NdisConfiguration.KeyQueryTable[3].DefaultData = ValueInformation; + + McaBlockPointer = (PNDIS_MCA_POS_DATA)(&ResourceList->PartialDescriptors[i+1]); + MaxSlotNumber = ResourceList->PartialDescriptors[i].u.DeviceSpecificData.DataSize / + sizeof(NDIS_MCA_POS_DATA); + + *McaData = *(McaBlockPointer + (*ChannelNumber) - 1); + + if ((PosId != 0xFFFF) && + (McaData->AdapterId != PosId)) { + + // + // The card seems to have been moved on us. Now we search for it. + // + + SearchSlotNumber = 1; + Found = FALSE; + + while (SearchSlotNumber <= MaxSlotNumber) { + + *McaData = *(McaBlockPointer + (SearchSlotNumber - 1)); + + if (McaData->AdapterId == PosId) { + + // + // Found one! + // + + if (Found) { + + // + // Uh-oh, found two of them! Fail + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + Found = TRUE; + FoundSlotNumber = SearchSlotNumber; + + } + + SearchSlotNumber++; + + } + + if (!Found) { + // + // No card found + // + *Status = NDIS_STATUS_FAILURE; + return; + + } + + // + // Find the SlotNumber parameter in the registry. + // + + *ChannelNumber = FoundSlotNumber; + + NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString; + NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue; + + Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name); + + PathName = ExAllocatePoolWithTag(NonPagedPool, + sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR), + ' DN' + ); + + if (PathName != NULL) { + + NdisZeroMemory(PathName, sizeof(L"\\Parameters") + + (Length * sizeof(WCHAR)) + + sizeof(WCHAR) + ); + + NdisMoveMemory(PathName, + NdisConfiguration.KeyQueryTable[3].Name, + Length * sizeof(WCHAR) + ); + + NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters")); + + // + // Update the value + // + + NtStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + PathName, + SlotNumberString, + REG_DWORD, + &FoundSlotNumber, + sizeof(FoundSlotNumber) + ); + + ExFreePool(PathName); + + } + + // + // Update the value + // + NtStatus = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + NdisConfiguration.KeyQueryTable[3].Name, + SlotNumberString, + REG_DWORD, + &FoundSlotNumber, + sizeof(FoundSlotNumber) + ); + + // + // Get the new information + // + + *McaData = *(McaBlockPointer + (FoundSlotNumber - 1)); + + } + + *Status = NDIS_STATUS_SUCCESS; + + ZwClose(McaHandle); + + return; + + } + +} + +#if !defined(BUILD_FOR_3_1) + +NDIS_STATUS +NdisPciAssignResources( + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE NdisWrapperHandle, + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + OUT PNDIS_RESOURCE_LIST *AssignedResources + ) +/*++ + +Routine Description: + + This routine uses the Hal to assign a set of resources to a PCI + device. + +Arguments: + + NdisMacHandle - Handle returned from NdisRegisterMac. + + NdisWrapperHandle - Handle returned from NdisInitializeWrapper. + + WrapperConfigurationContext - Handle passed to MacAddAdapter. + + SlotNumber - Slot number of the device. + + AssignedResources - The returned resources. + +Return Value: + + Status of the operation + +--*/ +{ + NTSTATUS NtStatus; + ULONG BusNumber; + NDIS_INTERFACE_TYPE BusType; + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable; + PCM_RESOURCE_LIST AllocatedResources = NULL; + PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle; + + // + // Get the BusNumber and the BusType from the Context here!! + // + + KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + + BusType = (NDIS_INTERFACE_TYPE)KeyQueryTable[3].DefaultType; + + BusNumber = KeyQueryTable[3].DefaultLength; + + NtStatus = HalAssignSlotResources ( + (PUNICODE_STRING)(NdisMacInfo->NdisWrapperConfigurationHandle), + NULL, + NdisMacInfo->NdisWrapperDriver, + NULL, + BusType, + BusNumber, + SlotNumber, + &AllocatedResources + ); + + if (NtStatus != STATUS_SUCCESS) { + *AssignedResources = NULL; + return(NDIS_STATUS_FAILURE); + } + + // + // Store resources into the driver wide block + // + ((PNDIS_MAC_BLOCK)NdisMacHandle)->PciAssignedResources = AllocatedResources; + + *AssignedResources = &(AllocatedResources->List[0].PartialResourceList); + + return(NDIS_STATUS_SUCCESS); + +} + + + +ULONG +NdisReadPciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine reads from the PCI configuration space a specified + length of bytes at a certain offset. + +Arguments: + + NdisAdapterHandle - Adapter we are talking about. + + SlotNumber - The slot number of the device. + + Offset - Offset to read from + + Buffer - Place to store the bytes + + Length - Number of bytes to read + +Return Value: + + Returns the number of bytes read. + +--*/ +{ + PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + ULONG DataLength; + + if (Adapter->DeviceObject == NULL) { + + // + // This is a mini-port + // + +#if DBG + ASSERT(Miniport->BusType == NdisInterfacePci); +#endif + + DataLength = HalGetBusDataByOffset( + PCIConfiguration, + Miniport->BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); + + } else { + +#if DBG + ASSERT(Adapter->BusType == NdisInterfacePci); +#endif + + DataLength = HalGetBusDataByOffset( + PCIConfiguration, + Adapter->BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); + + } + +} + +ULONG +NdisWritePciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine writes to the PCI configuration space a specified + length of bytes at a certain offset. + +Arguments: + + NdisAdapterHandle - Adapter we are talking about. + + SlotNumber - The slot number of the device. + + Offset - Offset to read from + + Buffer - Place to store the bytes + + Length - Number of bytes to read + +Return Value: + + Returns the number of bytes written. + +--*/ +{ + PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle; + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle; + ULONG DataLength; + + if (Adapter->DeviceObject == NULL) { + + // + // This is a mini-port + // + +#if DBG + ASSERT(Miniport->BusType == NdisInterfacePci); +#endif + + DataLength = HalSetBusDataByOffset( + PCIConfiguration, + Miniport->BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); + + } else { + +#if DBG + ASSERT(Adapter->BusType == NdisInterfacePci); +#endif + + DataLength = HalSetBusDataByOffset( + PCIConfiguration, + Adapter->BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); + + } + +} + +#else // !defined(BUILD_FOR_3_1) + +NDIS_STATUS +NdisPciAssignResources( + IN NDIS_HANDLE NdisMacHandle, + IN NDIS_HANDLE NdisWrapperHandle, + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + OUT PNDIS_RESOURCE_LIST *AssignedResources + ) +{ + return NDIS_STATUS_FAILURE; +} + +ULONG +NdisReadPciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +{ + return 0; +} + +ULONG +NdisWritePciSlotInformation( + IN NDIS_HANDLE NdisAdapterHandle, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +{ + return 0; +} + +#endif // else !defined(BUILD_FOR_3_1) + + +VOID +NdisOpenFile( + OUT PNDIS_STATUS Status, + OUT PNDIS_HANDLE FileHandle, + OUT PUINT FileLength, + IN PNDIS_STRING FileName, + IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress + ) + +/*++ + +Routine Description: + + This routine opens a file for future mapping and reads its contents + into allocated memory. + +Arguments: + + Status - The status of the operation + + FileHandle - A handle to be associated with this open + + FileLength - Returns the length of the file + + FileName - The name of the file + + HighestAcceptableAddress - The highest physical address at which + the memory for the file can be allocated. + +Return Value: + + None. + +--*/ +{ + NTSTATUS NtStatus; + IO_STATUS_BLOCK IoStatus; + HANDLE NtFileHandle; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG LengthOfFile; + WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\"; + NDIS_STRING FullFileName; + ULONG FullFileNameLength; + PNDIS_FILE_DESCRIPTOR FileDescriptor; + PVOID FileImage; + + // + // This structure represents the data from the + // NtQueryInformationFile API with an information + // class of FileStandardInformation. + // + + FILE_STANDARD_INFORMATION StandardInfo; + + + // + // Insert the correct path prefix. + // + + FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength; + FullFileName.Buffer = ExAllocatePoolWithTag (NonPagedPool, FullFileNameLength, ' DN'); + + if (FullFileName.Buffer == NULL) { + *Status = NDIS_STATUS_RESOURCES; + return; + } + FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR); + FullFileName.MaximumLength = (USHORT)FullFileNameLength; + RtlCopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix)); + + RtlAppendUnicodeStringToString (&FullFileName, FileName); + +#if DBG + DbgPrint ("NDIS: Attempting to open %Z\n", &FullFileName); +#endif + + InitializeObjectAttributes ( + &ObjectAttributes, + &FullFileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + NtStatus = ZwCreateFile( + &NtFileHandle, + SYNCHRONIZE | FILE_READ_DATA, + &ObjectAttributes, + &IoStatus, + NULL, + 0, + FILE_SHARE_READ, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ); + + if (!NT_SUCCESS(NtStatus)) { +#if DBG + DbgPrint ("Error opening file %x\n", NtStatus); +#endif + ExFreePool (FullFileName.Buffer); + *Status = NDIS_STATUS_FILE_NOT_FOUND; + return; + } + + ExFreePool (FullFileName.Buffer); + + // + // Query the object to determine its length. + // + + NtStatus = ZwQueryInformationFile( + NtFileHandle, + &IoStatus, + &StandardInfo, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation + ); + + if (!NT_SUCCESS(NtStatus)) { +#if DBG + DbgPrint ("Error querying info on file %x\n", NtStatus); +#endif + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + return; + } + + LengthOfFile = StandardInfo.EndOfFile.LowPart; + +#if DBG + DbgPrint ("File length is %d\n", LengthOfFile); +#endif + + // + // Might be corrupted. + // + + if (LengthOfFile < 1) { +#if DBG + DbgPrint ("Bad file length %d\n", LengthOfFile); +#endif + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + return; + } + + // + // Allocate buffer for this file + // + + FileImage = ExAllocatePoolWithTag(NonPagedPool, LengthOfFile, ' DN'); + + if (FileImage == NULL) { + +#if DBG + DbgPrint ("Could not allocate buffer\n"); +#endif + ZwClose(NtFileHandle); + *Status = NDIS_STATUS_ERROR_READING_FILE; + return; + + } + + // + // Read the file into our buffer. + // + + NtStatus = ZwReadFile( + NtFileHandle, + NULL, + NULL, + NULL, + &IoStatus, + FileImage, + LengthOfFile, + NULL, + NULL + ); + + ZwClose(NtFileHandle); + + if ((!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile)) { +#if DBG + DbgPrint ("error reading file %x\n", NtStatus); +#endif + *Status = NDIS_STATUS_ERROR_READING_FILE; + ExFreePool(FileImage); + return; + } + + // + // Allocate a structure to describe the file. + // + + FileDescriptor = ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_FILE_DESCRIPTOR), ' DN'); + + if (FileDescriptor == NULL) { + *Status = NDIS_STATUS_RESOURCES; + ExFreePool(FileImage); + return; + } + + + FileDescriptor->Data = FileImage; + NdisAllocateSpinLock (&FileDescriptor->Lock); + FileDescriptor->Mapped = FALSE; + + *FileHandle = (NDIS_HANDLE)FileDescriptor; + *FileLength = LengthOfFile; + *Status = STATUS_SUCCESS; + +} + + +VOID +NdisCloseFile( + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine closes a file previously opened with NdisOpenFile. + The file is unmapped if needed and the memory is freed. + +Arguments: + + FileHandle - The handle returned by NdisOpenFile + +Return Value: + + None. + +--*/ +{ + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + + ExFreePool (FileDescriptor->Data); + ExFreePool (FileDescriptor); + +} + + +VOID +NdisMapFile( + OUT PNDIS_STATUS Status, + OUT PVOID * MappedBuffer, + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine maps an open file, so that the contents can be accessed. + Files can only have one active mapping at any time. + +Arguments: + + Status - The status of the operation + + MappedBuffer - Returns the virtual address of the mapping. + + FileHandle - The handle returned by NdisOpenFile. + +Return Value: + + None. + +--*/ +{ + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + + ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock); + + if (FileDescriptor->Mapped == TRUE) { + *Status = NDIS_STATUS_ALREADY_MAPPED; + RELEASE_SPIN_LOCK (&FileDescriptor->Lock); + return; + } + + FileDescriptor->Mapped = TRUE; + RELEASE_SPIN_LOCK (&FileDescriptor->Lock); + + *MappedBuffer = FileDescriptor->Data; + *Status = STATUS_SUCCESS; + +} + + +VOID +NdisUnmapFile( + IN NDIS_HANDLE FileHandle + ) + +/*++ + +Routine Description: + + This routine unmaps a file previously mapped with NdisOpenFile. + The file is unmapped if needed and the memory is freed. + +Arguments: + + FileHandle - The handle returned by NdisOpenFile + +Return Value: + + None. + +--*/ + +{ + PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle; + + FileDescriptor->Mapped = FALSE; + +} + + +#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. + +--*/ +{ + PNDIS_LOOKAHEAD_ELEMENT TmpElement; + + ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock); + + if (NdisLookaheadBufferLength < (LookaheadLength + + sizeof(NDIS_LOOKAHEAD_ELEMENT))) { + + // + // Free current list + // + while (NdisLookaheadBufferList != NULL) { + + TmpElement = NdisLookaheadBufferList; + NdisLookaheadBufferList = NdisLookaheadBufferList->Next; + + ExFreePool ( TmpElement ) ; + + } + + NdisLookaheadBufferLength = LookaheadLength + + sizeof(NDIS_LOOKAHEAD_ELEMENT); + + } + + if (NdisLookaheadBufferList == NULL) { + + NdisLookaheadBufferList = (PNDIS_LOOKAHEAD_ELEMENT)ExAllocatePoolWithTag( + NonPagedPool, + NdisLookaheadBufferLength, + 'blDN' + ); + + if (NdisLookaheadBufferList == NULL) { + + *pLookaheadBuffer = NULL; + RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock); + return; + + } + + NdisLookaheadBufferList->Next = NULL; + NdisLookaheadBufferList->Length = NdisLookaheadBufferLength; + + } + + + // + // Get the buffer + // + + *pLookaheadBuffer = (PVOID)(NdisLookaheadBufferList + 1); + NdisLookaheadBufferList = NdisLookaheadBufferList->Next; + + RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock); + + // + // 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; + + Element--; + + if (Element->Length != NdisLookaheadBufferLength) { + + ExFreePool(Element); + + } else { + + ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock); + + Element->Next = NdisLookaheadBufferList; + NdisLookaheadBufferList = Element; + + RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock); + + } + +} + +#endif // _ALPHA_ + + +BOOLEAN CheckPortUsage( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG PortNumber, + IN ULONG Length, + IN PDRIVER_OBJECT DriverObject +) +/*++ + +Routine Description: + + This routine checks if a port is currently in use somewhere in the + system via IoReportUsage -- which fails if there is a conflict. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + PortNumber - Address of the port to access. + Length - Number of ports from the base address to access. + +Return Value: + + FALSE if there is a conflict, else TRUE + +--*/ + +{ + NTSTATUS NtStatus; + BOOLEAN Conflict; + NTSTATUS FirstNtStatus; + BOOLEAN FirstConflict; + PCM_RESOURCE_LIST Resources; + + // + // Allocate space for resources + // + + Resources = (PCM_RESOURCE_LIST)ExAllocatePool( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + ); + + if (Resources == NULL) { + + // + // Error out + // + + return(FALSE); + + } + + Resources->Count = 1; + Resources->List[0].InterfaceType = InterfaceType; + Resources->List[0].BusNumber = BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 1; + + // + // Setup port + // + Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort; + Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags = + (InterfaceType == Internal)? + CM_RESOURCE_PORT_MEMORY : + CM_RESOURCE_PORT_IO; +#if !defined(BUILD_FOR_3_1) + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber; +#else + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start = + RtlConvertUlongToLargeInteger((ULONG)(PortNumber)); +#endif + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length = + Length; + + // + // Submit Resources + // + + FirstNtStatus = IoReportResourceUsage( + NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &FirstConflict + ); + + // + // Now clear it out + // + Resources->List[0].PartialResourceList.Count = 0; + + NtStatus = IoReportResourceUsage( + NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &Conflict + ); + + ExFreePool(Resources); + + // + // Check for conflict. + // + + if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) { + + return(FALSE); + } + + return(TRUE); +} + +NTSTATUS +StartMapping( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG InitialAddress, + IN ULONG Length, + OUT PVOID *InitialMapping, + OUT PBOOLEAN Mapped + ) + +/*++ + +Routine Description: + + This routine initialize the mapping of a address into virtual + space dependent on the bus number, etc. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + InitialAddress - Address to access. + Length - Number of bytes from the base address to access. + InitialMapping - The virtual address space to use when accessing the + address. + Mapped - Did an MmMapIoSpace() take place. + +Return Value: + + The function value is the status of the operation. + +--*/ +{ + PHYSICAL_ADDRESS Address; + PHYSICAL_ADDRESS InitialPhysAddress; + ULONG addressSpace; + + // + // Get the system physical address for this card. The card uses + // I/O space, except for "internal" Jazz devices which use + // memory space. + // + + *Mapped = FALSE; + + addressSpace = (InterfaceType == Internal) ? 0 : 1; + + InitialPhysAddress.LowPart = InitialAddress; + + InitialPhysAddress.HighPart = 0; + + if ( !HalTranslateBusAddress( + InterfaceType, // InterfaceType + BusNumber, // BusNumber + InitialPhysAddress, // Bus Address + &addressSpace, // AddressSpace + &Address // Translated address + ) ) { + + // + // It would be nice to return a better status here, but we only get + // TRUE/FALSE back from HalTranslateBusAddress. + // + + return NDIS_STATUS_FAILURE; + } + + if (addressSpace == 0) { + + // + // memory space + // + + *InitialMapping = MmMapIoSpace( + Address, + Length, + FALSE + ); + + if (*InitialMapping == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + *Mapped = TRUE; + + } else { + + // + // I/O space + // + + *InitialMapping = (PVOID)Address.LowPart; + + } + + return(STATUS_SUCCESS); + +} + + +NTSTATUS +EndMapping( + IN PVOID InitialMapping, + IN ULONG Length, + IN BOOLEAN Mapped + ) + +/*++ + +Routine Description: + + This routine undoes the mapping of an address into virtual + space dependent on the bus number, etc. + +Arguments: + + InitialMapping - The virtual address space to use when accessing the + address. + Length - Number of bytes from the base address to access. + Mapped - Do we need to call MmUnmapIoSpace. + +Return Value: + + The function value is the status of the operation. + +--*/ +{ + + if (Mapped) { + + // + // memory space + // + + MmUnmapIoSpace(InitialMapping, Length); + + } + + return(STATUS_SUCCESS); + +} + + +VOID +NdisImmediateReadPortUchar( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PUCHAR Data + ) +/*++ + +Routine Description: + + This routine reads from a port a UCHAR. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(UCHAR), + DriverObject + ) == FALSE) { + + *Data = (UCHAR)0xFF; + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(UCHAR), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + *Data = (UCHAR)0xFF; + return; + + } + + // + // Read from the port + // + + *Data = READ_PORT_UCHAR((PUCHAR)PortMapping); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(UCHAR), + Mapped + ); + +} + +VOID +NdisImmediateReadPortUshort( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PUSHORT Data + ) +/*++ + +Routine Description: + + This routine reads from a port a USHORT. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(USHORT), + DriverObject + ) == FALSE) { + + *Data = (USHORT)0xFFFF; + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(USHORT), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + *Data = (USHORT)0xFFFF; + return; + + } + + // + // Read from the port + // + + *Data = READ_PORT_USHORT((PUSHORT)PortMapping); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(USHORT), + Mapped + ); + +} + +VOID +NdisImmediateReadPortUlong( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + OUT PULONG Data + ) +/*++ + +Routine Description: + + This routine reads from a port a ULONG. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(ULONG), + DriverObject + ) == FALSE) { + + *Data = (ULONG)0xFFFFFFFF; + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(ULONG), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + *Data = (ULONG)0xFFFFFFFF; + return; + + } + + // + // Read from the port + // + + *Data = READ_PORT_ULONG((PULONG)PortMapping); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(ULONG), + Mapped + ); + +} + +VOID +NdisImmediateWritePortUchar( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN UCHAR Data + ) +/*++ + +Routine Description: + + This routine writes to a port a UCHAR. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(UCHAR), + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(UCHAR), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Read from the port + // + + WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(UCHAR), + Mapped + ); + +} + +VOID +NdisImmediateWritePortUshort( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN USHORT Data + ) +/*++ + +Routine Description: + + This routine writes to a port a USHORT. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(USHORT), + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(USHORT), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Read from the port + // + + WRITE_PORT_USHORT((PUSHORT)PortMapping, Data); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(USHORT), + Mapped + ); + +} + +VOID +NdisImmediateWritePortUlong( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG Port, + IN ULONG Data + ) +/*++ + +Routine Description: + + This routine writes to a port a ULONG. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + Port - Port number to read from. + + Data - Pointer to place to store the result. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID PortMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the port is available. + // + if (CheckPortUsage( + BusType, + BusNumber, + Port, + sizeof(ULONG), + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + Port, + sizeof(ULONG), + &PortMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Read from the port + // + + WRITE_PORT_ULONG((PULONG)PortMapping, Data); + + // + // End port mapping + // + + EndMapping( + PortMapping, + sizeof(ULONG), + Mapped + ); + +} + +BOOLEAN CheckMemoryUsage( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG Address, + IN ULONG Length, + IN PDRIVER_OBJECT DriverObject +) +/*++ +Routine Description: + + This routine checks if a range of memory is currently in use somewhere + in the system via IoReportUsage -- which fails if there is a conflict. + +Arguments: + + InterfaceType - The bus type (ISA, EISA) + BusNumber - Bus number in the system + Address - Starting Address of the memory to access. + Length - Length of memory from the base address to access. + +Return Value: + + FALSE if there is a conflict, else TRUE + +--*/ +{ + NTSTATUS NtStatus; + BOOLEAN Conflict; + NTSTATUS FirstNtStatus; + BOOLEAN FirstConflict; + PCM_RESOURCE_LIST Resources; + + // + // Allocate space for resources + // + + Resources = (PCM_RESOURCE_LIST)ExAllocatePool( + NonPagedPool, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) + ); + + if (Resources == NULL) { + + // + // Error out + // + + return(FALSE); + + } + + Resources->Count = 1; + Resources->List[0].InterfaceType = InterfaceType; + Resources->List[0].BusNumber = BusNumber; + Resources->List[0].PartialResourceList.Version = 0; + Resources->List[0].PartialResourceList.Revision = 0; + Resources->List[0].PartialResourceList.Count = 1; + + // + // Setup memory + // + + Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = + CmResourceTypeMemory; + Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = + CmResourceShareDriverExclusive; + Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags = + CM_RESOURCE_MEMORY_READ_WRITE; +#if !defined(BUILD_FOR_3_1) + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address; +#else + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start = + RtlConvertUlongToLargeInteger((ULONG)(Address)); +#endif + Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length = + Length; + + + // + // Submit Resources + // + + FirstNtStatus = IoReportResourceUsage( + NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &FirstConflict + ); + + // + // Now clear it out + // + Resources->List[0].PartialResourceList.Count = 0; + + NtStatus = IoReportResourceUsage( + NULL, + DriverObject, + Resources, + sizeof(CM_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), + NULL, + NULL, + 0, + TRUE, + &Conflict + ); + + ExFreePool(Resources); + + // + // Check for conflict. + // + + if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) { + + return(FALSE); + } + + return(TRUE); +} + +VOID +NdisImmediateReadSharedMemory( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SharedMemoryAddress, + OUT PUCHAR Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine read into a buffer from shared ram. It does all the mapping, + etc, to do the read here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + SharedMemoryAddress - The physical address to read from. + + Buffer - The buffer to read into. + + Length - Length of the buffer in bytes. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID MemoryMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the memory is available. + // + if (CheckMemoryUsage( + BusType, + BusNumber, + SharedMemoryAddress, + Length, + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + SharedMemoryAddress, + Length, + &MemoryMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Read from memory + // + +#ifdef _M_IX86 + + memcpy(Buffer, MemoryMapping, Length); + +#else + + READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length); + +#endif + + // + // End mapping + // + + EndMapping( + MemoryMapping, + Length, + Mapped + ); + +} + +VOID +NdisImmediateWriteSharedMemory( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SharedMemoryAddress, + IN PUCHAR Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine writes a buffer to shared ram. It does all the mapping, + etc, to do the write here. + +Arguments: + + WrapperConfigurationContext - The handle used to call NdisOpenConfig. + + SharedMemoryAddress - The physical address to write to. + + Buffer - The buffer to write. + + Length - Length of the buffer in bytes. + +Return Value: + + None. + +--*/ + +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject; + BOOLEAN Mapped; + PVOID MemoryMapping; + NDIS_INTERFACE_TYPE BusType; + ULONG BusNumber; + NTSTATUS Status; + + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + BusNumber = KeyQueryTable[3].DefaultLength; + + // + // Check that the memory is available. + // + if (CheckMemoryUsage( + BusType, + BusNumber, + SharedMemoryAddress, + Length, + DriverObject + ) == FALSE) { + + return; + + } + + // + // Map the space + // + + Status = StartMapping( + BusType, + BusNumber, + SharedMemoryAddress, + Length, + &MemoryMapping, + &Mapped + ); + + if (!NT_SUCCESS(Status)) { + + return; + + } + + // + // Write to memory + // + +#ifdef _M_IX86 + + memcpy(MemoryMapping, Buffer, Length); + +#else + + WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length); + +#endif + + // + // End mapping + // + + EndMapping( + MemoryMapping, + Length, + Mapped + ); + +} + +#if !defined(BUILD_FOR_3_1) + +ULONG +NdisImmediateReadPciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine reads from the PCI configuration space a specified + length of bytes at a certain offset. + +Arguments: + + WrapperConfigurationContext - Context passed to MacAddAdapter. + + SlotNumber - The slot number of the device. + + Offset - Offset to read from + + Buffer - Place to store the bytes + + Length - Number of bytes to read + +Return Value: + + Returns the number of bytes read. + +--*/ +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + ULONG BusNumber; + ULONG DataLength; + + BusNumber = KeyQueryTable[3].DefaultLength; + +#if DBG + { + NDIS_INTERFACE_TYPE BusType; + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + ASSERT(BusType == NdisInterfacePci); + } +#endif + + DataLength = HalGetBusDataByOffset( + PCIConfiguration, + BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); +} + +ULONG +NdisImmediateWritePciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +/*++ + +Routine Description: + + This routine writes to the PCI configuration space a specified + length of bytes at a certain offset. + +Arguments: + + WrapperConfigurationContext - Context passed to MacAddAdapter. + + SlotNumber - The slot number of the device. + + Offset - Offset to read from + + Buffer - Place to store the bytes + + Length - Number of bytes to read + +Return Value: + + Returns the number of bytes written. + +--*/ +{ + PRTL_QUERY_REGISTRY_TABLE KeyQueryTable = + (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext; + ULONG BusNumber; + ULONG DataLength; + + BusNumber = KeyQueryTable[3].DefaultLength; + +#if DBG + { + NDIS_INTERFACE_TYPE BusType; + BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType); + ASSERT(BusType == NdisInterfacePci); + } +#endif + + DataLength = HalSetBusDataByOffset( + PCIConfiguration, + BusNumber, + SlotNumber, + Buffer, + Offset, + Length + ); + + return(DataLength); +} + +#else // !defined(BUILD_FOR_3_1) + +ULONG +NdisImmediateReadPciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +{ + return 0; +} + +ULONG +NdisImmediateWritePciSlotInformation( + IN NDIS_HANDLE WrapperConfigurationContext, + IN ULONG SlotNumber, + IN ULONG Offset, + IN PVOID Buffer, + IN ULONG Length + ) +{ + return 0; +} + +#endif // !defined(BUILD_FOR_3_1) + + +CCHAR +NdisSystemProcessorCount( + VOID + ) +{ + return *KeNumberProcessors; +} + + +VOID +NdisOverrideBusNumber( + IN NDIS_HANDLE WrapperConfigurationContext, + IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL, + IN ULONG BusNumber + ) + +/*++ + +Routine Description: + + This routine is used to override the BusNumber value retrieved + from the registry. It is expected to be used by PCI drivers + that discover that their adapter's bus number has changed. + +Arguments: + + WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE + that is set up for this driver's parameters. + + MiniportAdapterHandle - points to the adapter block, if the calling + driver is a miniport. If the calling driver is a full MAC, this + parameter must be NULL. + + BusNumber - the new bus number. + +Return Value: + + None. + +--*/ + +{ + PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle; + + ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength = BusNumber; + + if (Miniport != NULL) { + Miniport->BusNumber = BusNumber; + } + + return; +} + -- cgit v1.2.3