Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3793 lines
110 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
ndis.c
Abstract:
NDIS wrapper functions
Author:
Adam Barr (adamba) 11-Jul-1990
Environment:
Kernel mode, FSD
Revision History:
10-Jul-1995 JameelH Make NDIS.SYS a device-driver and add PnP support
--*/
#include <precomp.h>
#pragma hdrstop
// #include "ndis.tmh"
//
// Define the module number for debug code.
//
#define MODULE_NUMBER MODULE_NDIS
#define NDIS_DEVICE_NAME L"\\Device\\Ndis"
#define NDIS_SYMBOLIC_NAME L"\\Global??\\NDIS"
#define GET_TEXT_1(_T) #_T
#define GET_TEXT(_T) GET_TEXT_1(_T)
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
NDIS wrapper driver entry point.
Arguments:
DriverObject - Pointer to the driver object created by the system.
RegistryPath - Pointer to the registry section where the parameters reside.
Return Value:
Return value from IoCreateDevice
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING DeviceName;
UINT i;
OBJECT_ATTRIBUTES ObjectAttr;
UNICODE_STRING CallbackObjectName;
NTSTATUS NtStatus;
SYSTEM_BATTERY_STATE ndisSystemBatteryState;
HANDLE ThreadHandle;
BOOLEAN fDerefCallbackObject = FALSE, fDeregisterCallback = FALSE;
UNREFERENCED_PARAMETER(RegistryPath);
// WPP_INIT_TRACING(DriverObject, RegistryPath);
// LOG_INFO("==>Ndis: DriverEntry");
NdisInitializeString(&ndisBuildDate, (PUCHAR)__DATE__);
NdisInitializeString(&ndisBuildTime, (PUCHAR)__TIME__);
NdisInitializeString(&ndisBuiltBy, (PUCHAR)GET_TEXT(BUILT_BY));
ndisDriverObject = DriverObject;
//
// Create the device object.
//
RtlInitUnicodeString(&DeviceName, NDIS_DEVICE_NAME);
//1 in Longhorn, number of processors may vary during a session
ndisNumberOfProcessors = KeNumberProcessors;
Status = IoCreateDevice(DriverObject, // DriverObject
0, // DeviceExtension
&DeviceName, // DeviceName
FILE_DEVICE_NETWORK, // DeviceType
FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics
FALSE, // Exclusive
&ndisDeviceObject); // DeviceObject
if (NT_SUCCESS(Status))
{
UNICODE_STRING SymbolicLinkName;
// Create a symbolic link to this device
RtlInitUnicodeString(&SymbolicLinkName, NDIS_SYMBOLIC_NAME);
Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
ndisDeviceObject->Flags |= DO_DIRECT_IO;
// Initialize the driver object for this file system driver.
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = ndisDispatchRequest;
}
//
// create a security descriptor for NDIS device object
//
Status = ndisCreateSecurityDescriptor(ndisDeviceObject,
&ndisSecurityDescriptor,
TRUE,
TRUE);
//1 check for status
Status = CreateDeviceDriverSecurityDescriptor(DriverObject, TRUE, NULL);
Status = CreateDeviceDriverSecurityDescriptor(DriverObject->DeviceObject, TRUE, NULL);
Status = CreateDeviceDriverSecurityDescriptor(ndisDeviceObject, TRUE, NULL);
//
// disable for now
//
#if NDIS_UNLOAD
DriverObject->DriverUnload = ndisUnload;
#else
DriverObject->DriverUnload = NULL;
#endif
INITIALIZE_SPIN_LOCK(&ndisGlobalLock);
INITIALIZE_SPIN_LOCK(&ndisMiniDriverListLock);
INITIALIZE_SPIN_LOCK(&ndisProtocolListLock);
INITIALIZE_SPIN_LOCK(&ndisMiniportListLock);
INITIALIZE_SPIN_LOCK(&ndisGlobalPacketPoolListLock);
INITIALIZE_SPIN_LOCK(&ndisGlobalOpenListLock);
ndisDmaAlignment = HalGetDmaAlignmentRequirement();
if (sizeof(ULONG) > ndisDmaAlignment)
{
ndisDmaAlignment = sizeof(ULONG);
}
ndisTimeIncrement = KeQueryTimeIncrement();
//
// Get handles for all conditionally lockable sections
//
for (i = 0; i < MAX_PKG; i++)
{
ndisInitializePackage(&ndisPkgs[i]);
}
ExInitializeResourceLite(&SharedMemoryResource);
ndisReadRegistry();
//
// don't let use set this bit through registry
//
ndisFlags &= ~NDIS_GFLAG_TRACK_MEM_ALLOCATION;
Status = STATUS_SUCCESS;
ndisSystemProcess = NtCurrentProcess();
//
// Now create a worker thread for use by NDIS
// This is so that when we queue PnP events upto transports
// and they need worker threads as well ...
//
KeInitializeQueue(&ndisWorkerQueue, 0);
Status = PsCreateSystemThread(&ThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NtCurrentProcess(),
NULL,
ndisWorkerThread,
NULL);
if (!NT_SUCCESS(Status))
{
//1 do more error processing here
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NDIS DriverEntry: Cannot create worker thread, Status %lx\n", Status));
}
else
{
NtClose(ThreadHandle);
}
}
KeQuerySystemTime(&KeBootTime);
ConvertSecondsToTicks(POOL_AGING_TIME, &PoolAgingTicks);
//
// verifir intialization. in case ndis tester wants to verify
// the drivers by intercepting ndis entry points, ndis should
// not verify the calls
//
if (!(ndisFlags & NDIS_GFLAG_DONT_VERIFY))
ndisVerifierInitialization();
#if DBG
if (ndisDebugBreakPoint)
{
DbgPrint("Ndis: DriverEntry\n");
DbgBreakPoint();
}
#endif
#ifdef TRACK_MOPEN_REFCOUNTS
NdisZeroMemory (&ndisLogfile, sizeof(UINT) * NDIS_LOGFILE_SIZE);
#endif
#ifdef TRACK_MINIPORT_REFCOUNTS
NdisZeroMemory (&ndisMiniportLogfile, sizeof(UINT) * NDIS_MINIPORT_LOGFILE_SIZE);
#endif
#ifdef NDIS_LOG_ABORTED_REQUESTS
for (i = 0; i < 16; i++)
{
NdisZeroMemory (&ndisAbortedRequests[i], sizeof (NDIS_REQUEST));
}
#endif
//
// create a callback options for those kernel mode components that like
// to hear about Bind/Unbind events
//
RtlInitUnicodeString(&CallbackObjectName, NDIS_BIND_UNBIND_CALLBACK_NAME);
InitializeObjectAttributes(&ObjectAttr,
&CallbackObjectName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
NULL,
NULL);
NtStatus = ExCreateCallback(&ndisBindUnbindCallbackObject,
&ObjectAttr,
TRUE, // create
TRUE); // allow multiple callback registeration
if (!NT_SUCCESS(NtStatus))
{
DbgPrint("Ndis: failed to create a Callback object. Status %lx\n", NtStatus);
}
#if 0
else
{
//
// for test purpose
//
ndisBindUnbindCallbackRegisterationHandle = ExRegisterCallback(ndisBindUnbindCallbackObject,
ndisBindUnbindCallback,
(PVOID)NULL);
if (ndisBindUnbindCallbackRegisterationHandle == NULL)
{
DbgPrint("Ndis: failed to register a BindUnbind callback routine\n");
}
}
#endif
//
// register a notification callback for power state changes
//
RtlInitUnicodeString(&CallbackObjectName, L"\\CallBack\\PowerState");
InitializeObjectAttributes(&ObjectAttr,
&CallbackObjectName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
NULL,
NULL);
NtStatus = ExCreateCallback(&ndisPowerStateCallbackObject,
&ObjectAttr,
FALSE,
TRUE);
if (!NT_SUCCESS(Status))
{
DbgPrint("Ndis: failed to create a Callback object. Status %lx\n", NtStatus);
}
else
{
fDerefCallbackObject = TRUE;
ndisPowerStateCallbackHandle = ExRegisterCallback(ndisPowerStateCallbackObject,
(PCALLBACK_FUNCTION)&ndisPowerStateCallback,
(PVOID)NULL);
if (ndisPowerStateCallbackHandle == NULL)
{
DbgPrint("Ndis: failed to register a power state Callback routine\n");
}
else
{
fDeregisterCallback = TRUE;
}
RtlZeroMemory(&ndisSystemBatteryState, sizeof(SYSTEM_BATTERY_STATE));
//
// get the current power source
//
NtStatus = ZwPowerInformation(SystemBatteryState,
NULL,
0,
&ndisSystemBatteryState,
sizeof(SYSTEM_BATTERY_STATE));
if (NT_SUCCESS(NtStatus))
{
ndisAcOnLine = (ndisSystemBatteryState.AcOnLine == TRUE) ? 1 : 0;
}
fDerefCallbackObject = FALSE;
fDeregisterCallback = FALSE;
}
InitializeListHead(&ndisGlobalPacketPoolList);
if (fDeregisterCallback)
{
ExUnregisterCallback(ndisPowerStateCallbackHandle);
}
if (fDerefCallbackObject)
{
ObDereferenceObject(ndisPowerStateCallbackObject);
}
INITIALIZE_MUTEX(&ndisPnPMutex);
//
// create an ACL for all users
//
AllUsersAclRead = ndisCreateAcl(TRUE, // Admins
TRUE, //LocalSystem
TRUE, //LocalService
TRUE, //NetworkService
TRUE, //NetConfigOps
TRUE, //Users
GENERIC_READ | WMIGUID_QUERY
);
ASSERT(AllUsersAclRead != NULL);
AllUsersAclWrite = ndisCreateAcl(TRUE, // Admins
TRUE, //LocalSystem
TRUE, //LocalService
TRUE, //NetworkService
TRUE, //NetConfigOps
TRUE, //Users
GENERIC_WRITE | WMIGUID_SET
);
ASSERT(AllUsersAclWrite != NULL);
AllUsersAclReadWrite = ndisCreateAcl(TRUE, // Admins
TRUE, //LocalSystem
TRUE, //LocalService
TRUE, //NetworkService
TRUE, //NetConfigOps
TRUE, //Users
GENERIC_READ | GENERIC_WRITE | WMIGUID_QUERY | WMIGUID_SET
);
ASSERT(AllUsersAclReadWrite != NULL);
AllUsersAclNotification = ndisCreateAcl(TRUE, // Admins
TRUE, //LocalSystem
TRUE, //LocalService
TRUE, //NetworkService
TRUE, //NetConfigOps
TRUE, //Users
SYNCHRONIZE | WMIGUID_NOTIFICATION
);
ASSERT(AllUsersAclNotification != NULL);
//
// create an ACL for admin types
//
AdminsAcl = ndisCreateAcl(TRUE, // Admins
TRUE, //LocalSystem
TRUE, //LocalService
TRUE, //NetworkService
TRUE, //NetConfigOps
FALSE, //Users
GENERIC_READ | GENERIC_WRITE | WMIGUID_QUERY | WMIGUID_SET
);
ASSERT(AdminsAcl != NULL);
//
// Create an SD for All Users
//
Status = ndisCreateGenericSD(AllUsersAclRead, AllUsersReadSecurityDescriptor);
ASSERT(NT_SUCCESS(Status));
Status = ndisCreateGenericSD(AllUsersAclWrite, AllUsersWriteSecurityDescriptor);
ASSERT(NT_SUCCESS(Status));
Status = ndisCreateGenericSD(AllUsersAclReadWrite, AllUsersReadWriteSecurityDescriptor);
ASSERT(NT_SUCCESS(Status));
Status = ndisCreateGenericSD(AllUsersAclNotification, AllUsersNotificationSecurityDescriptor);
ASSERT(NT_SUCCESS(Status));
Status = ndisCreateGenericSD(AdminsAcl, AdminsSecurityDescriptor);
ASSERT(NT_SUCCESS(Status));
/*
//
// set the security descriptor for all known guids
//
for (i = 0; i < sizeof(ndisSupportedGuids)/sizeof(NDIS_GUID); i++)
{
Status = ndisSetWmiSecurity(&ndisSupportedGuids[i]);
if (NT_SUCCESS(Status))
{
DbgPrint("Successfully added ndisSupportedGuids[%ld].\n", i);
}
else
{
DbgPrint("setting security failed for %ld\n.", i);
}
}
for (i = 0; i < sizeof(ndisCoSupportedGuids)/sizeof(NDIS_GUID); i++)
{
Status = ndisSetWmiSecurity(&ndisCoSupportedGuids[i]);
if (NT_SUCCESS(Status))
{
DbgPrint("Successfully added ndisCoSupportedGuids[%ld].\n", i);
}
else
{
DbgPrint("setting security failed for ndisCoSupportedGuids[%ld].\n", i);
}
}
for (i = 0; i < sizeof(ndisMediaSupportedGuids)/sizeof(NDIS_GUID); i++)
{
Status = ndisSetWmiSecurity(&ndisMediaSupportedGuids[i]);
if (NT_SUCCESS(Status))
{
DbgPrint("Successfully added ndisMediaSupportedGuids[%ld].\n", i);
}
else
{
DbgPrint("setting security failed for ndisMediaSupportedGuids[%ld].\n", i);
}
}
for (i = 0; i < sizeof(ndisStatusSupportedGuids)/sizeof(NDIS_GUID); i++)
{
Status = ndisSetWmiSecurity(&ndisStatusSupportedGuids[i]);
if (NT_SUCCESS(Status))
{
DbgPrint("Successfully added ndisStatusSupportedGuids[%ld].\n", i);
}
else
{
DbgPrint("setting security failed for ndisStatusSupportedGuids[%ld].\n", i);
}
}
*/
return Status;
}
#if NDIS_UNLOAD
VOID
ndisUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This is the unload routine for the Appletalk driver.
NOTE: Unload will not be called until all the handles have been
closed successfully. We just shutdown all the ports, and do
misc. cleanup.
Arguments:
DriverObject - Pointer to driver object for this driver.
Return Value:
None.
--*/
{
NTSTATUS Status;
UNICODE_STRING SymbolicLinkName;
UINT i;
NdisFreeString(ndisBuildDate);
NdisFreeString(ndisBuildTime);
NdisFreeString(ndisBuiltBy);
if (ndisPowerStateCallbackHandle)
{
ExUnregisterCallback(ndisPowerStateCallbackHandle);
}
if (ndisPowerStateCallbackObject)
{
ObDereferenceObject(ndisPowerStateCallbackObject);
}
ExDeleteResourceLite(&SharedMemoryResource);
//
// Tell the ndisWorkerThread to quit
//
INITIALIZE_WORK_ITEM(&ndisPoisonPill, NULL, &ndisPoisonPill);
QUEUE_WORK_ITEM(&ndisPoisonPill, CriticalWorkQueue);
WAIT_FOR_OBJECT(ndisThreadObject, 0);
ObDereferenceObject(ndisThreadObject);
RtlInitUnicodeString(&SymbolicLinkName, NDIS_SYMBOLIC_NAME);
Status = IoDeleteSymbolicLink(&SymbolicLinkName);
ASSERT(NT_SUCCESS(Status));
IoDeleteDevice(ndisDeviceObject);
//
// ASSERT that all the packages are unlocked
//
for (i = 0; i < MAX_PKG; i++)
{
ASSERT(ndisPkgs[i].ReferenceCount == 0);
}
}
#endif
VOID
ndisReadRegistry(
VOID
)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[8];
UCHAR c;
ULONG DefaultZero = 0;
//
// First we need to initialize the processor information incase
// the registry is empty.
//
for (c = 0; (c < NDIS_MAX_CPU_COUNT) && (c < ndisNumberOfProcessors) ; c++)
{
ndisValidProcessors[c] = c;
}
ndisCurrentProcessor = ndisMaximumProcessor = c - 1;
//
// 1) Switch to the MediaTypes key below the service (NDIS) key
//
QueryTable[0].QueryRoutine = NULL;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
QueryTable[0].Name = L"MediaTypes";
//
// Setup to enumerate the values in the registry section (shown above).
// For each such value, we'll add it to the ndisMediumArray
//
QueryTable[1].QueryRoutine = ndisAddMediaTypeToArray;
QueryTable[1].DefaultType = REG_DWORD;
QueryTable[1].DefaultData = (PVOID)&DefaultZero;
QueryTable[1].DefaultLength = 0;
QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
QueryTable[1].Name = NULL;
//
// Query terminator
//
QueryTable[2].QueryRoutine = NULL;
QueryTable[2].Flags = 0;
QueryTable[2].Name = NULL;
//
// The rest of the work is done in the callback routine ndisAddMediaTypeToArray.
//
RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
L"NDIS",
QueryTable,
(PVOID)NULL, // no context needed
NULL);
//
// Switch to the parameters key below the service (NDIS) key and
// read the parameters.
//
QueryTable[0].QueryRoutine = NULL;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
QueryTable[0].Name = L"Parameters";
//
// Read in the processor affinity mask.
//
QueryTable[1].QueryRoutine = ndisReadProcessorAffinityMask;
QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
QueryTable[1].DefaultData = (PVOID)&DefaultZero;
QueryTable[1].DefaultLength = 0;
QueryTable[1].DefaultType = REG_DWORD;
QueryTable[1].Name = L"ProcessorAffinityMask";
QueryTable[2].QueryRoutine = ndisReadRegParameters;
QueryTable[2].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
QueryTable[2].DefaultData = (PVOID)&ndisFlags;
QueryTable[2].DefaultLength = 0;
QueryTable[2].DefaultType = REG_DWORD;
QueryTable[2].Name = L"Flags";
QueryTable[2].EntryContext = (PVOID)&ndisFlags;
//1 check for an upper bound on # of stack locations.
QueryTable[3].QueryRoutine = ndisReadRegParameters;
QueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
QueryTable[3].DefaultData = (PVOID)&ndisPacketStackSize;
QueryTable[3].DefaultLength = 0;
QueryTable[3].DefaultType = REG_DWORD;
QueryTable[3].Name = L"PacketStackSize";
QueryTable[3].EntryContext = (PVOID)&ndisPacketStackSize;
//
// Query terminator
//
QueryTable[4].QueryRoutine = NULL;
QueryTable[4].Flags = 0;
QueryTable[4].Name = NULL;
#if DBG
#ifdef NDIS_TRACE
ndisDebugBreakPoint = 1;
ndisDebugLevel = 0;
ndisDebugSystems = 0x3003;
#else
QueryTable[4].QueryRoutine = ndisReadRegParameters;
QueryTable[4].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
QueryTable[4].Name = L"DebugBreakPoint";
QueryTable[4].DefaultData = (PVOID)&ndisDebugBreakPoint;
QueryTable[4].DefaultLength = 0;
QueryTable[4].EntryContext = (PVOID)&ndisDebugBreakPoint;
QueryTable[4].DefaultType = REG_DWORD;
QueryTable[5].QueryRoutine = ndisReadRegParameters;
QueryTable[5].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
QueryTable[5].Name = L"DebugLevel";
QueryTable[5].DefaultData = (PVOID)&ndisDebugLevel;
QueryTable[5].DefaultLength = 0;
QueryTable[5].EntryContext = (PVOID)&ndisDebugLevel;
QueryTable[5].DefaultType = REG_DWORD;
QueryTable[6].QueryRoutine = ndisReadRegParameters;
QueryTable[6].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
QueryTable[6].Name = L"DebugSystems";
QueryTable[6].DefaultData = (PVOID)&ndisDebugSystems;
QueryTable[6].DefaultLength = 0;
QueryTable[6].EntryContext = (PVOID)&ndisDebugSystems;
QueryTable[6].DefaultType = REG_DWORD;
//
// Query terminator
//
QueryTable[7].QueryRoutine = NULL;
QueryTable[7].Flags = 0;
QueryTable[7].Name = NULL;
#endif
#endif
//
// The rest of the work is done in the callback routines
//
RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
L"NDIS",
QueryTable,
(PVOID)NULL, // no context needed
NULL);
//
// Make sure ndisPacketStackSize isn't zero
//
if (ndisPacketStackSize == 0)
ndisPacketStackSize = 1;
}
NTSTATUS
ndisReadRegParameters(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
/*++
Arguments:
ValueName - The name of the value
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
--*/
{
UNREFERENCED_PARAMETER(ValueName);
UNREFERENCED_PARAMETER(ValueLength);
UNREFERENCED_PARAMETER(Context);
if ((ValueType != REG_DWORD) || (ValueData == NULL))
return STATUS_UNSUCCESSFUL;
*((PULONG)EntryContext) = *((PULONG)ValueData);
return STATUS_SUCCESS;
}
NTSTATUS
ndisReadProcessorAffinityMask(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
UNREFERENCED_PARAMETER(EntryContext);
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(ValueLength);
UNREFERENCED_PARAMETER(ValueName);
//
// If we have valid data then build our array of valid processors
// to use.... Treat the special case of 0 or default -1 to signify
// that DPC affinity will follow interrupt affinity
//
if ((REG_DWORD == ValueType) && (ValueData != NULL))
{
if ((*(PULONG)ValueData == 0) ||
(*(PULONG)ValueData == 0xFFFFFFFF))
{
ndisSkipProcessorAffinity = TRUE;
}
else
{
ULONG ProcessorAffinity;
UCHAR c1, c2;
//
// Save the processor affinity.
//
ProcessorAffinity = *(PULONG)ValueData;
//
// Fill in the valid processor array.
//
for (c1 = c2 = 0;
(c1 <= ndisMaximumProcessor) && (ProcessorAffinity != 0);
c1++)
{
if (ProcessorAffinity & 1)
{
ndisValidProcessors[c2++] = c1;
}
ProcessorAffinity >>= 1;
}
ndisCurrentProcessor = ndisMaximumProcessor = c2 - 1;
}
}
return STATUS_SUCCESS;
}
NTSTATUS
ndisAddMediaTypeToArray(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
{
#if DBG
NDIS_STRING Str;
RtlInitUnicodeString(&Str, ValueName);
#else
UNREFERENCED_PARAMETER(ValueName);
#endif
UNREFERENCED_PARAMETER(EntryContext);
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(ValueLength);
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
("ExperimentalMediaType %Z - %x\n", &Str, *(PULONG)ValueData));
//
// Ignore all values that we already know about. These should not be in the
// registry anyway, but just in case somebody is messing with it.
//
if ((ValueType == REG_DWORD) && (ValueData != NULL) && (*(PULONG)ValueData > NdisMediumIrda))
{
NDIS_MEDIUM *pTemp;
ULONG size;
//
// See if we have enough space to add this value. If not allocate space for the
// new array, copy the old one into this (and free the old if not static).
//
ASSERT (ndisMediumArraySize <= ndisMediumArrayMaxSize);
//
// Check for duplicates. If so drop it
//
for (pTemp = ndisMediumArray, size = ndisMediumArraySize;
size > 0; pTemp ++, size -= sizeof(NDIS_MEDIUM))
{
if (*(NDIS_MEDIUM *)ValueData == *pTemp)
{
//
// Duplicate.
//
return STATUS_SUCCESS;
}
}
if (ndisMediumArraySize == ndisMediumArrayMaxSize)
{
//
// We do not have any space in the array. Need to re-alloc. Be generous.
//
pTemp = (NDIS_MEDIUM *)ALLOC_FROM_POOL(ndisMediumArraySize + EXPERIMENTAL_SIZE*sizeof(NDIS_MEDIUM),
NDIS_TAG_MEDIA_TYPE_ARRAY);
if (pTemp != NULL)
{
CopyMemory(pTemp, ndisMediumArray, ndisMediumArraySize);
if (ndisMediumArray != ndisMediumBuffer)
{
FREE_POOL(ndisMediumArray);
}
ndisMediumArray = pTemp;
}
}
if (ndisMediumArraySize < ndisMediumArrayMaxSize)
{
ndisMediumArray[ndisMediumArraySize/sizeof(NDIS_MEDIUM)] = *(NDIS_MEDIUM *)ValueData;
ndisMediumArraySize += sizeof(NDIS_MEDIUM);
}
}
return STATUS_SUCCESS;
}
VOID
ndisWorkerThread(
IN PVOID Context
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
BOOLEAN FirstThread = (Context == NULL);
PLIST_ENTRY pList;
HANDLE ThreadHandle;
PWORK_QUEUE_ITEM pWI;
NTSTATUS Status;
if (FirstThread)
{
ndisThreadObject = PsGetCurrentThread();
ObReferenceObject(ndisThreadObject);
do
{
//
// Block here waiting for work-items to do
//
pList = KeRemoveQueue(&ndisWorkerQueue, KernelMode, NULL);
DBGPRINT_RAW(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
("ndisWorkerThread: WorkItem %p\n", pList));
pWI = CONTAINING_RECORD(pList, WORK_QUEUE_ITEM, List);
#if NDIS_UNLOAD
//
// Unload asking us to quit, comply.
//
if (pWI == &ndisPoisonPill)
{
break;
}
#endif
Status = PsCreateSystemThread(&ThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NtCurrentProcess(),
NULL,
ndisWorkerThread,
pWI);
if (NT_SUCCESS(Status))
{
NtClose(ThreadHandle);
}
else
{
DBGPRINT_RAW(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
("ndisWorkerThread: Failed to create a thread, using EX worker thread\n"));
XQUEUE_WORK_ITEM(pWI, CriticalWorkQueue);
ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
}
} while (TRUE);
}
else
{
//
// Not the main thread, just do the thing and die.
//
LastWorkerThreadWI = *((PWORK_QUEUE_ITEM)Context);
pWI = (PWORK_QUEUE_ITEM)Context;
(*pWI->WorkerRoutine)(pWI->Parameter);
ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
}
}
NTSTATUS
ndisDispatchRequest(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
Dispatcher for Irps intended for the NDIS Device.
Arguments:
Return Value:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION pIrpSp;
PNDIS_DEVICE_OBJECT_OPEN_CONTEXT OpenContext = NULL;
NTSTATUS SecurityStatus;
static LONG OpenCount = 0;
UNREFERENCED_PARAMETER(pDeviceObject);
PAGED_CODE( );
#if defined(_WIN64)
if (IoIs32bitProcess(pIrp))
{
pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
#endif
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pIrp->IoStatus.Status = STATUS_PENDING;
pIrp->IoStatus.Information = 0;
PnPReferencePackage();
switch (pIrpSp->MajorFunction)
{
case IRP_MJ_CREATE:
OpenContext = (PNDIS_DEVICE_OBJECT_OPEN_CONTEXT)ALLOC_FROM_POOL(sizeof(NDIS_DEVICE_OBJECT_OPEN_CONTEXT),
NDIS_TAG_OPEN_CONTEXT);
if (OpenContext == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
ZeroMemory(OpenContext, sizeof(NDIS_DEVICE_OBJECT_OPEN_CONTEXT));
OpenContext->AdminAccessAllowed = ndisCheckAccess(pIrp,
pIrpSp,
&SecurityStatus,
ndisSecurityDescriptor);
//
// save the caller's access right
//
pIrpSp->FileObject->FsContext = OpenContext;
Increment(&OpenCount, &Lock);
break;
case IRP_MJ_CLEANUP:
OpenContext = pIrpSp->FileObject->FsContext;
ASSERT(OpenContext != NULL);
pIrpSp->FileObject->FsContext = NULL;
FREE_POOL(OpenContext);
Decrement(&OpenCount, &Lock);
break;
case IRP_MJ_CLOSE:
break;
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
break;
case IRP_MJ_DEVICE_CONTROL:
Status = ndisHandlePnPRequest(pIrp);
break;
default:
Status = STATUS_NOT_IMPLEMENTED;
break;
}
ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
ASSERT (Status != STATUS_PENDING);
pIrp->IoStatus.Status = Status;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
PnPDereferencePackage();
return Status;
}
NTSTATUS
ndispConvOffsetToPointer(
IN PVOID MasterBuffer,
IN ULONG MasterLength,
IN OUT PULONG_PTR Offset,
IN ULONG Length,
IN ULONG Alignment
)
/*++
Routine Description:
This function validates a buffer within an IOCTL and converts a buffer
offset to a pointer.
Argumens:
MasterBuffer - Pointer to the start of the IOCTL buffer
MasterLength - Length of the IOCTL buffer
Offset - Offset of the data buffer within the IOCTL buffer
Length - Length of the data buffer within the IOCTL buffer
Alignment - Required alignment of the type within the data buffer
Return Value:
The function status is the final status of the operation.
--*/
{
ULONG_PTR masterStart;
ULONG_PTR masterEnd;
ULONG_PTR bufStart;
ULONG_PTR bufEnd;
if (Length == 0)
{
//
// Nothing to do.
//
return STATUS_SUCCESS;
}
masterStart = (ULONG_PTR)MasterBuffer;
masterEnd = masterStart + MasterLength;
bufStart = masterStart + *Offset;
bufEnd = bufStart + Length;
//
// Ensure that neither of the buffers wrap
//
if (masterEnd < masterStart || bufEnd < bufStart)
{
return STATUS_INVALID_PARAMETER;
}
//
// Ensure that buf is wholly contained within master
//
if (bufStart < masterStart || bufEnd > masterEnd)
{
return STATUS_INVALID_PARAMETER;
}
//
// Make sure that buf is properly aligned
//
if ((bufStart & (Alignment - 1)) != 0)
{
return STATUS_INVALID_PARAMETER;
}
//
// Everything looks good, perform the conversion
//
*Offset += masterStart;
return STATUS_SUCCESS;
}
NTSTATUS
ndispConvVar(
IN PVOID MasterBuffer,
IN ULONG MasterLength,
IN OUT PNDIS_VAR_DATA_DESC Var
)
/*++
Routine Description:
This function validates an NDIS_VAR_DATA_DESC buffer within an IOCTL
and converts its data offset to a pointer.
Argumens:
MasterBuffer - Pointer to the start of the IOCTL buffer
MasterLength - Length of the IOCTL buffer
Var - Pointer to an NDIS_VAR_DATA_DESC structure.
Return Value:
The function status is the final status of the operation.
--*/
{
return ndispConvOffsetToPointer( MasterBuffer,
MasterLength,
&Var->Offset,
Var->Length,
sizeof(WCHAR) );
}
NTSTATUS
FASTCALL
ndisHandlePnPRequest(
IN PIRP pIrp
)
/*++
Routine Description:
Handler for PnP ioctls.
Arguments:
Return Value:
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PNDIS_DEVICE_OBJECT_OPEN_CONTEXT OpenContext;
PNDIS_PNP_OPERATION PnPOp;
PNDIS_ENUM_INTF EnumIntf;
PIO_STACK_LOCATION pIrpSp;
UNICODE_STRING Device;
ULONG Method;
PVOID pBuf;
UINT iBufLen, oBufLen;
UINT OutputLength = 0;
BOOLEAN AdminAccessAllowed = FALSE;
PAGED_CODE( );
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
OpenContext = pIrpSp->FileObject->FsContext;
if (OpenContext == NULL)
{
return STATUS_NO_SUCH_FILE;
}
AdminAccessAllowed = OpenContext->AdminAccessAllowed;
Method = pIrpSp->Parameters.DeviceIoControl.IoControlCode & 3;
// Ensure that the method is buffered - we always use that.
if (Method == METHOD_BUFFERED)
{
// Get the output buffer and its length. Input and Output buffers are
// both pointed to by the SystemBuffer
iBufLen = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
oBufLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
pBuf = pIrp->AssociatedIrp.SystemBuffer;
}
else
{
return STATUS_INVALID_PARAMETER;
}
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_NDIS_ADD_TDI_DEVICE:
if (!AdminAccessAllowed)
{
return STATUS_ACCESS_DENIED;
}
//
// Validate the DeviceName
//
Status = STATUS_INVALID_PARAMETER;
if ((iBufLen > 0) && ((iBufLen % sizeof(WCHAR)) == 0))
{
((PWCHAR)pBuf)[iBufLen/sizeof(WCHAR) - 1] = 0;
RtlInitUnicodeString(&Device, pBuf);
Status = ndisHandleLegacyTransport(&Device);
}
break;
case IOCTL_NDIS_DO_PNP_OPERATION:
if (!AdminAccessAllowed)
{
return STATUS_ACCESS_DENIED;
}
Status = STATUS_BUFFER_TOO_SMALL;
PnPOp = (PNDIS_PNP_OPERATION)pBuf;
//
// check to make sure the input buffer is big enough to
// have all the information that NDIS_PNP_OPERATION structure
// claims to contain.
//
if ((iBufLen < sizeof(NDIS_PNP_OPERATION)) ||
(iBufLen < (sizeof(NDIS_PNP_OPERATION) +
PnPOp->LowerComponent.MaximumLength +
PnPOp->UpperComponent.MaximumLength +
PnPOp->ReConfigBufferSize +
PnPOp->BindList.MaximumLength
)))
{
break;
}
//
// Convert the four buffer offsets within NDIS_PNP_OPERATION
// to pointers.
//
Status = ndispConvVar( PnPOp, iBufLen, &PnPOp->LowerComponent );
if (!NT_SUCCESS(Status))
{
break;
}
Status = ndispConvVar( PnPOp, iBufLen, &PnPOp->UpperComponent );
if (!NT_SUCCESS(Status))
{
break;
}
Status = ndispConvVar( PnPOp, iBufLen, &PnPOp->BindList );
if (!NT_SUCCESS(Status))
{
break;
}
Status = ndispConvOffsetToPointer( PnPOp,
iBufLen,
&PnPOp->ReConfigBufferOff,
PnPOp->ReConfigBufferSize,
sizeof(ULONG_PTR) );
if (!NT_SUCCESS(Status))
{
break;
}
Status = ndisHandleUModePnPOp(PnPOp);
break;
case IOCTL_NDIS_ENUMERATE_INTERFACES:
if (oBufLen >= sizeof(NDIS_ENUM_INTF))
{
EnumIntf = (PNDIS_ENUM_INTF)pBuf;
Status = ndisEnumerateInterfaces(pBuf, oBufLen, &OutputLength);
}
else
{
Status = STATUS_BUFFER_TOO_SMALL;
}
pIrp->IoStatus.Information = OutputLength;
break;
case IOCTL_NDIS_GET_VERSION:
if (oBufLen < sizeof(UINT))
{
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
*((PUINT)pBuf) = NdisGetVersion();
OutputLength = sizeof(UINT);
if (oBufLen >= 2 * sizeof(UINT))
{
*((PUINT)pBuf + 1) = (UINT)ndisChecked;
OutputLength += sizeof(UINT);
}
Status = STATUS_SUCCESS;
}
pIrp->IoStatus.Information = OutputLength;
break;
default:
break;
}
ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
return Status;
}
NTSTATUS
FASTCALL
ndisHandleUModePnPOp(
IN PNDIS_PNP_OPERATION PnPOp
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
PUNICODE_STRING Protocol, Device, BindList;
WAIT_FOR_OBJECT(&ndisPnPMutex, NULL);
ndisPnPMutexOwner = MODULE_NUMBER + __LINE__;
//
// Upcase the protocol and device names
//
Protocol = (PUNICODE_STRING)&PnPOp->UpperComponent;
Device = (PUNICODE_STRING)&PnPOp->LowerComponent;
BindList = (PUNICODE_STRING)&PnPOp->BindList;
if (PnPOp->Operation == BIND)
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("BIND (%s) %Z to %Z\n", (PnPOp->Layer == NDIS) ? "NDIS" : "TDI ", Protocol, Device));
}
else if (PnPOp->Operation == UNBIND)
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("UNBIND(%s) %Z to %Z\n", (PnPOp->Layer == NDIS) ? "NDIS" : "TDI ", Protocol, Device));
}
switch (PnPOp->Layer)
{
case TDI:
//
// Call into the TDI handler to do this
//
if (ndisTdiPnPHandler != NULL)
{
Status = (*ndisTdiPnPHandler)(Protocol,
Device,
BindList,
PnPOp->ReConfigBufferPtr,
PnPOp->ReConfigBufferSize,
PnPOp->Operation);
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
break;
case NDIS:
switch (PnPOp->Operation)
{
case BIND:
Status = ndisHandleProtocolBindNotification(Device, Protocol);
break;
case UNBIND:
Status = ndisHandleProtocolUnbindNotification(Device, Protocol);
break;
case RECONFIGURE:
case BIND_LIST:
//1 for BIND_LIST, validate the buffer to have the correct format
Status = ndisHandleProtocolReconfigNotification(Device,
Protocol,
PnPOp->ReConfigBufferPtr,
PnPOp->ReConfigBufferSize,
PnPOp->Operation);
break;
case UNLOAD:
Status = ndisHandleProtocolUnloadNotification(Protocol);
break;
//1 check to see when this is called
case REMOVE_DEVICE:
Status = ndisHandleOrphanDevice(Device);
break;
default:
Status = STATUS_INVALID_PARAMETER;
break;
}
break;
default:
Status = STATUS_INVALID_PARAMETER;
break;
}
ndisPnPMutexOwner = 0;
RELEASE_MUTEX(&ndisPnPMutex);
return Status;
}
NTSTATUS
FASTCALL
ndisHandleProtocolBindNotification(
IN PUNICODE_STRING DeviceName,
IN PUNICODE_STRING ProtocolName
)
/*++
Routine Description:
Given a erotocol's name and an adapter's name, this routine creates a binding between
a protocol and an adapter (assuming protocol has a BindAdapterHandler)
Arguments:
DeviceName: Adapter device name i.e. \Device\{GUID}
ProtocolName Protocols name i.e. TCPIP
Return Value:
STATUS_SUCCESS if we could call BindAdapterHandler
STATUS_UNSUCCESSFUL otherwise
Note
This routine does not return the status of attempted bind, rather if it -could- attempt to bind!
--*/
{
//1 check to see if this routine should return back the status of attempted bind
NTSTATUS Status = STATUS_SUCCESS;
PNDIS_PROTOCOL_BLOCK Protocol = NULL;
PNDIS_MINIPORT_BLOCK Miniport = NULL;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>ndisHandleProtocolBindNotification\n"));
do
{
ndisReferenceMiniportByName(DeviceName, &Miniport);
if (Miniport == NULL)
{
Status = STATUS_OBJECT_NAME_NOT_FOUND;
break;
}
//
// Map ProtocolName to the Protocol block
//
Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, FALSE);
if (!NT_SUCCESS(Status))
{
Protocol = NULL;
Status = STATUS_SUCCESS;
break;
}
//
// Bind this protocols
//
ndisCheckAdapterBindings(Miniport, Protocol);
} while (FALSE);
if (Protocol != NULL)
{
ndisDereferenceProtocol(Protocol, FALSE);
}
if (Miniport != NULL)
{
MINIPORT_DECREMENT_REF(Miniport);
}
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==ndisHandleProtocolBindNotification\n"));
return Status;
}
NTSTATUS
FASTCALL
ndisHandleProtocolUnbindNotification(
IN PUNICODE_STRING DeviceName,
IN PUNICODE_STRING ProtocolName
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
PNDIS_OPEN_BLOCK Open;
PNDIS_PROTOCOL_BLOCK Protocol = NULL;
PNDIS_MINIPORT_BLOCK Miniport = NULL;
//1 change the name of fPartial variable. what this does is to keep track
//1 of whether or not we are running our partial search for the first
//1 time or not.
BOOLEAN fPartial = FALSE;
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>ndisHandleProtocolUnbindNotification\n"));
do
{
//
// Map ProtocolName to the Protocol block
//
Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, FALSE);
if (!NT_SUCCESS(Status))
{
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("ndisHandleProtocolUnbindNotification: ndisReferenceProtocolByName failed %lx\n", Status));
Status = STATUS_SUCCESS;
Protocol = NULL;
break;
}
//1 add comments what this loop does
do
{
//1 add comments what this call does
Open = ndisMapOpenByName(DeviceName, Protocol, TRUE);
if (Open == NULL)
{
//
// There is no -active- binding between this adapter and protocol.
// This would normally be an error but we need one special case for
// TCP/IP Arp modules. We can unbind notifications for TCP/IP which
// are actually destined for the ARP module.
// We also know that either TCP/IP or ONE and ONLY ONE arp module can be
// bound to an adapter. Make use of that knowledge.
//
ndisDereferenceProtocol(Protocol, FALSE);
if (!fPartial)
{
fPartial = TRUE;
Protocol = NULL;
}
Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, TRUE);
if (!NT_SUCCESS(Status))
{
break;
}
}
} while (Open == NULL);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("ndisHandleProtocolUnbindNotification: Open %p\n", Open));
if (Open != NULL)
{
Miniport = Open->MiniportHandle;
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
ndisMDereferenceOpen(Open);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
Status = ndisUnbindProtocol(Open, Protocol, Miniport, TRUE);
if (Status != NDIS_STATUS_SUCCESS)
{
PNDIS_OPEN_BLOCK tmpOpen;
//
// check to see if the open is still there and if it is
// clear the UNBIND flag. Note that we were the one
// setting the flag, so we can clear it ourselves
//
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
for (tmpOpen = Protocol->OpenQueue;
tmpOpen != NULL;
tmpOpen = tmpOpen->ProtocolNextOpen)
{
if(tmpOpen == Open)
{
ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
OPEN_CLEAR_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
fMINIPORT_OPEN_DONT_FREE |
fMINIPORT_OPEN_PROCESSING);
RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
break;
}
}
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
}
}
} while (FALSE);
if (Miniport != NULL)
{
MINIPORT_DECREMENT_REF(Miniport);
}
if (Protocol != NULL)
{
ndisDereferenceProtocol(Protocol, FALSE);
}
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==ndisHandleProtocolUnbindNotification: Protocol %p, Status %lx\n", Protocol, Status));
return Status;
}
NTSTATUS
ndisHandleProtocolReconfigNotification(
IN PUNICODE_STRING DeviceName,
IN PUNICODE_STRING ProtocolName,
IN PVOID ReConfigBuffer,
IN UINT ReConfigBufferSize,
IN UINT Operation
)
/*++
Routine Description:
This routine will notify protocols of a change in their configuration -or-
their bind list.
This routine can also be called to notify protocols of a change in bind list
Arguments:
DeviceName: Adapter's name (if specified). if NULL, it means the change is global and not bind specific
ProtocolName: Protocol's name
ReConfigBuffer: information buffer
ReConfigBufferSize: Information buffer size
Operation: RECONFIGURE or BIND_LIST
Return Value:
--*/
{
NTSTATUS Status;
KIRQL OldIrql;
PNDIS_PROTOCOL_BLOCK Protocol = NULL;
PNDIS_MINIPORT_BLOCK Miniport = NULL;
PNDIS_OPEN_BLOCK Open = NULL;
NET_PNP_EVENT NetPnpEvent;
PNDIS_PNP_EVENT_RESERVED EventReserved;
KEVENT Event;
BOOLEAN fPartial = FALSE;
BOOLEAN DeRefOpen = FALSE;
BOOLEAN DeRefMiniport = FALSE;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>ndisHandleProtocolReconfigNotification\n"));
do
{
//
// Map ProtocolName to the Protocol block
//
Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, FALSE);
if (!NT_SUCCESS(Status))
{
Protocol = NULL;
break;
}
//
// We can be passed a NULL device-name which implies global reconfig and we call
// the protocol's event handler with a NULL BindingContext
//
if (DeviceName->Length != 0)
{
ASSERT(Operation == RECONFIGURE);
do
{
WAIT_FOR_PROTO_MUTEX(Protocol);
Open = ndisMapOpenByName(DeviceName, Protocol, FALSE);
if (Open == NULL)
{
RELEASE_PROT_MUTEX(Protocol);
//
// There is no -active- binding between this adapter and protocol.
// This would normally be an error but we need one special case for
// TCP/IP Arp modules. We can unbind notifications for TCP/IP which
// are actually destined for the ARP module.
// We also know that either TCP/IP or ONE and ONLY ONE arp module can be
// bound to an adapter. Make use of that knowledge.
//
ndisDereferenceProtocol(Protocol, FALSE);
if (!fPartial)
{
fPartial = TRUE;
Protocol = NULL;
}
Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, TRUE);
if (!NT_SUCCESS(Status))
{
break;
}
}
else
{
DeRefOpen = TRUE;
DeRefMiniport = TRUE;
Miniport = Open->MiniportHandle;
}
} while (Open == NULL);
if (Open == NULL)
{
//
// if Open == NULL we are not holding the protocol mutex
//
Status = STATUS_OBJECT_NAME_NOT_FOUND;
break;
}
else if (Protocol->ProtocolCharacteristics.PnPEventHandler == NULL)
{
//
// Open is not NULL, we -are- holding the protocol mutex. release
// it before breaking out
//
RELEASE_PROT_MUTEX(Protocol);
Status = STATUS_UNSUCCESSFUL;
break;
}
}
else
{
//
// the device is NULL, just grab the protocol mutex
//
if (Protocol->ProtocolCharacteristics.PnPEventHandler != NULL)
{
WAIT_FOR_PROTO_MUTEX(Protocol);
}
else
{
Status = STATUS_UNSUCCESSFUL;
break;
}
}
//
// Setup the PnPEvent buffer
//
NdisZeroMemory(&NetPnpEvent, sizeof(NetPnpEvent));
Status = STATUS_SUCCESS;
switch (Operation)
{
case RECONFIGURE:
NetPnpEvent.NetEvent = NetEventReconfigure;
break;
case BIND_LIST:
NetPnpEvent.NetEvent = NetEventBindList;
break;
default:
ASSERT(FALSE);
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (Status == STATUS_INVALID_DEVICE_REQUEST)
{
break;
}
NetPnpEvent.Buffer = ReConfigBuffer;
NetPnpEvent.BufferLength = ReConfigBufferSize;
//
// Get a pointer to the NDIS reserved are in the PnP event.
//
EventReserved = PNDIS_PNP_EVENT_RESERVED_FROM_NET_PNP_EVENT(&NetPnpEvent);
INITIALIZE_EVENT(&Event);
EventReserved->pEvent = &Event;
//
// Notify the protocol now
//
Status = (Protocol->ProtocolCharacteristics.PnPEventHandler)(
(Open != NULL) ? Open->ProtocolBindingContext : NULL,
&NetPnpEvent);
if (Status == NDIS_STATUS_PENDING)
{
//
// Wait for completion.
//
WAIT_FOR_PROTOCOL(Protocol, &Event);
//
// Get the completion status.
//
Status = EventReserved->Status;
}
//
// IPX may return NDIS_STATUS_NOT_ACCEPTED to ask NDIS to
// Unbind/Bind the adapter. In this case, Open cannot be NULL.
//
if (Status != NDIS_STATUS_NOT_ACCEPTED)
{
if (Open)
{
ACQUIRE_SPIN_LOCK(&Open->SpinLock, &OldIrql);
OPEN_CLEAR_FLAG(Open, fMINIPORT_OPEN_PROCESSING);
RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
}
RELEASE_PROT_MUTEX(Protocol);
break;
}
RELEASE_PROT_MUTEX(Protocol);
ASSERT(DeRefOpen);
//
// Ndis need to Unbind/Bind the adapter for the protocol(Especially for IPX)
//
ACQUIRE_SPIN_LOCK(&Open->SpinLock, &OldIrql);
//
// If the open has gotten a unbind anyway, just return success and don't
// need to unbind/bind.
//
if (OPEN_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING | fMINIPORT_OPEN_CLOSING))
{
RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
Status = NDIS_STATUS_SUCCESS;
break;
}
//
// Going to Unbind the adaper
//
OPEN_SET_FLAG(Open, fMINIPORT_OPEN_UNBINDING | fMINIPORT_OPEN_DONT_FREE);
RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
ndisMDereferenceOpen(Open);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
DeRefOpen = FALSE;
Status = ndisUnbindProtocol(Open, Protocol, Miniport, FALSE);
//
// If cannot unbind the adapter
//
if (Status != NDIS_STATUS_SUCCESS)
{
PNDIS_OPEN_BLOCK tmpOpen;
//
// check to see if the open is still there and if it is
// clear the UNBIND flag. Note that we were the one
// setting the flag, so we can clear it ourselves
//
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
for (tmpOpen = Protocol->OpenQueue;
tmpOpen != NULL;
tmpOpen = tmpOpen->ProtocolNextOpen)
{
if(tmpOpen == Open)
{
ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
OPEN_CLEAR_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
fMINIPORT_OPEN_DONT_FREE |
fMINIPORT_OPEN_PROCESSING);
RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
break;
}
}
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
break;
}
//
// Then bind the adapter again.
//
ndisCheckAdapterBindings(Miniport, Protocol);
} while (FALSE);
if (DeRefOpen)
{
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
ndisMDereferenceOpen(Open);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
}
if (Protocol != NULL)
{
ndisDereferenceProtocol(Protocol, FALSE);
}
if (DeRefMiniport)
{
MINIPORT_DECREMENT_REF(Miniport);
}
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==ndisHandleProtocolReconfigNotification\n"));
return Status;
}
NTSTATUS
FASTCALL
ndisHandleProtocolUnloadNotification(
IN PUNICODE_STRING ProtocolName
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
PNDIS_PROTOCOL_BLOCK Protocol = NULL;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>ndisHandleProtocolUnloadNotification\n"));
//
// Map ProtocolName to the Protocol block
//
Status = ndisReferenceProtocolByName(ProtocolName, &Protocol, FALSE);
if (NT_SUCCESS(Status))
{
ndisDereferenceProtocol(Protocol, FALSE);
if (Protocol->ProtocolCharacteristics.UnloadHandler != NULL)
{
//1 investigate if this can be called with open bindings
(Protocol->ProtocolCharacteristics.UnloadHandler)();
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
}
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==ndisHandleProtocolUnloadNotification\n"));
return Status;
}
//1 when do we hit this?
NTSTATUS
FASTCALL
ndisHandleOrphanDevice(
IN PUNICODE_STRING pDevice
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
KIRQL OldIrql;
BOOLEAN fFound = FALSE;
PNDIS_M_DRIVER_BLOCK MiniBlock;
PNDIS_MINIPORT_BLOCK Miniport = NULL;
UNICODE_STRING UpcaseDevice;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("==>ndisHandleOrphanDevice\n"));
UpcaseDevice.Length = pDevice->Length;
UpcaseDevice.MaximumLength = pDevice->Length + sizeof(WCHAR);
UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
if (UpcaseDevice.Buffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = RtlUpcaseUnicodeString(&UpcaseDevice, pDevice, FALSE);
ASSERT (NT_SUCCESS(Status));
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
for (MiniBlock = ndisMiniDriverList;
(MiniBlock != NULL) && !fFound;
MiniBlock = MiniBlock->NextDriver)
{
ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
for (Miniport = MiniBlock->MiniportQueue;
Miniport != NULL;
Miniport = Miniport->NextMiniport)
{
if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->MiniportName))
{
fFound = TRUE;
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_ORPHANED);
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
break;
}
}
RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
}
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
FREE_POOL(UpcaseDevice.Buffer);
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("<==ndisHandleOrphanDevice\n"));
return STATUS_SUCCESS;
}
NTSTATUS
FASTCALL
ndisEnumerateInterfaces(
IN PNDIS_ENUM_INTF EnumIntf,
IN UINT BufferLength,
IN PUINT OutputLength
)
{
PNDIS_MINIPORT_BLOCK Miniport;
PNDIS_M_DRIVER_BLOCK MiniBlock;
PNDIS_INTERFACE Interface;
UINT SpaceLeft;
UINT SpaceNeeded;
PUCHAR pBuf;
NTSTATUS Status = STATUS_SUCCESS;
KIRQL OldIrql;
do
{
*OutputLength = 0;
if (BufferLength < sizeof(NDIS_ENUM_INTF))
{
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
SpaceLeft = BufferLength - sizeof(NDIS_ENUM_INTF);
NdisZeroMemory(EnumIntf, BufferLength);
Interface = &EnumIntf->Interface[0];
pBuf = (PUCHAR)EnumIntf + BufferLength;
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
for (MiniBlock = ndisMiniDriverList;
MiniBlock != NULL;
MiniBlock = MiniBlock->NextDriver)
{
ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
for (Miniport = MiniBlock->MiniportQueue;
Miniport != NULL;
Miniport = Miniport->NextMiniport)
{
if (Miniport->PnPDeviceState != NdisPnPDeviceStarted)
{
continue;
}
EnumIntf->AvailableInterfaces ++;
SpaceNeeded = sizeof(NDIS_INTERFACE) +
Miniport->MiniportName.Length +
Miniport->pAdapterInstanceName->Length;
EnumIntf->BytesNeeded += SpaceNeeded;
if (SpaceLeft >= SpaceNeeded)
{
EnumIntf->TotalInterfaces ++;
SpaceLeft -= SpaceNeeded;
pBuf -= Miniport->MiniportName.Length;
Interface->DeviceName.Buffer = (PWSTR)pBuf;
Interface->DeviceName.MaximumLength =
Interface->DeviceName.Length = Miniport->MiniportName.Length;
CopyMemory(pBuf, Miniport->MiniportName.Buffer, Interface->DeviceName.Length);
POINTER_TO_OFFSET(Interface->DeviceName.Buffer, EnumIntf);
pBuf -= Miniport->pAdapterInstanceName->Length;
Interface->DeviceDescription.Buffer = (PWSTR)pBuf;
Interface->DeviceDescription.MaximumLength =
Interface->DeviceDescription.Length = Miniport->pAdapterInstanceName->Length;
CopyMemory(pBuf, Miniport->pAdapterInstanceName->Buffer, Interface->DeviceDescription.Length);
POINTER_TO_OFFSET(Interface->DeviceDescription.Buffer, EnumIntf);
Interface ++;
}
#if 0
else
{
//
// we should report the cases that buffer was too small
//
//1 for .NET leave the behavior as before (return success)
//1 because some apps do not handle this properly
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
#endif
}
RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
if (Status != STATUS_SUCCESS)
{
//
// if we failed, get out
//
break;
}
}
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
//
// since we zero'ed out the entire output buffer and started
// writing to it from the end, this should be the original output buffer
// length
//
*OutputLength = BufferLength;
}while (FALSE);
return Status;
}
NTSTATUS
ndisUnbindProtocol(
IN PNDIS_OPEN_BLOCK Open,
IN PNDIS_PROTOCOL_BLOCK Protocol,
IN PNDIS_MINIPORT_BLOCK Miniport,
IN BOOLEAN Notify
)
/*+++
Routine Description:
Arguments:
Return Value:
None
---*/
{
NDIS_STATUS Status = STATUS_SUCCESS;
NDIS_BIND_CONTEXT UnbindContext;
PKEVENT CloseCompleteEvent = NULL;
PNDIS_OPEN_BLOCK TmpOpen = NULL;
KIRQL OldIrql;
BOOLEAN fDerefProtocol = FALSE;
BOOLEAN FreeOpen = FALSE;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>ndisUnbindProtocol: Open %p, Notify %d\n", Open, Notify));
PnPReferencePackage();
//
// if this is called outside the context of the protocol deregistering, increment
// the ref count to make sure the protocol deregisteration does not go through
// otherwise make note of the fact that we could not increment the ref count and avoid
// deref at the end
//
if (ndisReferenceProtocol(Protocol))
{
fDerefProtocol = TRUE;
}
WAIT_FOR_PROTO_MUTEX(Protocol);
do
{
//
// make sure the open didn't go away while we were waiting for
// protocol mutex.
//
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
for (TmpOpen = Protocol->OpenQueue;
TmpOpen != NULL;
TmpOpen = TmpOpen->ProtocolNextOpen)
{
if (TmpOpen == Open)
break;
}
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
if (TmpOpen == NULL)
{
//
// open went away while we were trying to get the protocol mutex
// return right away
//
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("ndisUnbindProtocol: Open %p, Flags %lx was closed while we were waiting for the protocol mutex.\n", Open, Open->Flags));
break;
}
ASSERT(OPEN_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING));
CloseCompleteEvent = Open->CloseCompleteEvent;
//
// wait for all AF notifications to go through
//
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
{
KEVENT AfNotifyCompleteEvent;
INITIALIZE_EVENT(&AfNotifyCompleteEvent);
//1 check to see if we need to get the Open Spinlock here
Open->AfNotifyCompleteEvent = &AfNotifyCompleteEvent;
if (Open->PendingAfNotifications != 0)
{
WAIT_FOR_OBJECT(Open->AfNotifyCompleteEvent , 0);
}
Open->AfNotifyCompleteEvent = NULL;
}
//
// Do a query-remove here first
//
if (Notify && (Protocol->ProtocolCharacteristics.PnPEventHandler != NULL))
{
NET_PNP_EVENT NetPnpEvent;
PNDIS_PNP_EVENT_RESERVED EventReserved;
KEVENT Event;
RtlZeroMemory(&NetPnpEvent, sizeof(NET_PNP_EVENT));
INITIALIZE_EVENT(&Event);
EventReserved = PNDIS_PNP_EVENT_RESERVED_FROM_NET_PNP_EVENT(&NetPnpEvent);
NetPnpEvent.NetEvent = NetEventQueryRemoveDevice;
NetPnpEvent.Buffer = NULL;
NetPnpEvent.BufferLength = 0;
EventReserved->pEvent = &Event;
//
// Indicate the event to the protocol.
//
Status = (Protocol->ProtocolCharacteristics.PnPEventHandler)(
Open->ProtocolBindingContext,
&NetPnpEvent);
if (NDIS_STATUS_PENDING == Status)
{
//
// Wait for completion.
//
WAIT_FOR_PROTOCOL(Protocol, &Event);
//
// Get the completion status.
//
Status = EventReserved->Status;
}
//
// Is the status OK?
//
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
}
if (CloseCompleteEvent != NULL)
{
INITIALIZE_EVENT(CloseCompleteEvent);
}
//
// Protocol ok with remove so now do it.
//
INITIALIZE_EVENT(&UnbindContext.Event);
Status = NDIS_STATUS_SUCCESS;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
(*Protocol->ProtocolCharacteristics.UnbindAdapterHandler)(
&Status,
Open->ProtocolBindingContext,
&UnbindContext);
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
if (Status == NDIS_STATUS_PENDING)
{
WAIT_FOR_PROTOCOL(Protocol, &UnbindContext.Event);
Status = UnbindContext.BindStatus;
}
ASSERT(Status == NDIS_STATUS_SUCCESS);
ndisNotifyWmiBindUnbind(Miniport, Protocol, FALSE);
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
if (CloseCompleteEvent != NULL)
{
//
// make sure the open is gone
//
WAIT_FOR_PROTOCOL(Protocol, CloseCompleteEvent);
}
} while (FALSE);
RELEASE_PROT_MUTEX(Protocol);
if (TmpOpen != NULL)
{
ACQUIRE_SPIN_LOCK(&Open->SpinLock, &OldIrql);
//
// did the close routine get our message not to free the open structure?
//
if (OPEN_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSE_COMPLETE))
{
//
// we have to get rid of open ourselves
//
FreeOpen = TRUE;
}
else
{
//
// for some reason, unbind did not go through or close is
// still in progress
//
OPEN_CLEAR_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
fMINIPORT_OPEN_DONT_FREE |
fMINIPORT_OPEN_PROCESSING);
FreeOpen = FALSE;
}
RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
}
PnPDereferencePackage();
if (FreeOpen)
{
ndisRemoveOpenFromGlobalList(Open);
FREE_POOL(Open);
}
if (fDerefProtocol)
{
ndisDereferenceProtocol(Protocol, FALSE);
}
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==ndisUnbindProtocol: Open %p, Notify %d, Status %lx\n", Open, Notify, Status));
return(Status);
}
VOID
ndisReferenceMiniportByName(
IN PUNICODE_STRING DeviceName,
OUT PNDIS_MINIPORT_BLOCK * pMiniport
)
{
KIRQL OldIrql;
PNDIS_M_DRIVER_BLOCK MiniBlock;
PNDIS_MINIPORT_BLOCK Miniport = NULL;
UNICODE_STRING UpcaseDevice;
UINT Depth = 1;
DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
("==>ndisReferenceMiniportByName\n"));
*pMiniport = NULL;
UpcaseDevice.Length = DeviceName->Length;
UpcaseDevice.MaximumLength = DeviceName->Length + sizeof(WCHAR);
UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
if (UpcaseDevice.Buffer == NULL)
{
return;
}
RtlUpcaseUnicodeString(&UpcaseDevice, DeviceName, FALSE);
do
{
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
for (MiniBlock = ndisMiniDriverList;
MiniBlock != NULL;
MiniBlock = MiniBlock->NextDriver)
{
ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
for (Miniport = MiniBlock->MiniportQueue;
Miniport != NULL;
Miniport = Miniport->NextMiniport)
{
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_ORPHANED) &&
(Miniport->BindPaths != NULL) &&
(Miniport->BindPaths->Number >= Depth) &&
NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->BindPaths->Paths[0]))
{
if (*pMiniport != NULL)
{
MINIPORT_DECREMENT_REF(*pMiniport);
*pMiniport = NULL;
}
Depth = Miniport->BindPaths->Number;
if (MINIPORT_INCREMENT_REF(Miniport))
{
*pMiniport = Miniport;
}
break;
}
}
RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
}
} while (FALSE);
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
FREE_POOL(UpcaseDevice.Buffer);
DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
("<==ndisReferenceMiniportByName\n"));
}
PNDIS_OPEN_BLOCK
FASTCALL
ndisMapOpenByName(
IN PUNICODE_STRING DeviceName,
IN PNDIS_PROTOCOL_BLOCK Protocol,
IN BOOLEAN fUnbinding
)
/*
Routine Description:
ndisMapOpenByName searches a protocol's open queue and tries to find an
open block that its RootDevice name matches Devicename passed to this function.
if the Open is found, miniport for that open is referenced. if we are -not-
trying to unbind the open, we will reference it.
Arguments:
DeviceName: RootDevice name of the open.
Protocol: protocol block to search.
fUnbinding: whether we are searching for the open so we can close it. if that is
the case, then some additional checks will be perfomred and the some flags on open
will be set.
Return Value:
Open block or NULL.
*/
{
UNICODE_STRING UpcaseDevice;
PNDIS_OPEN_BLOCK Open, tmpOpen;
PNDIS_MINIPORT_BLOCK Miniport;
KIRQL OldIrql;
BOOLEAN DeRefOpen = FALSE;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>ndisReferenceOpenByName, DeviceName %p, Protocol %p, fUnbinding %d\n",
DeviceName, Protocol, fUnbinding));
Open = NULL;
UpcaseDevice.Length = DeviceName->Length;
UpcaseDevice.MaximumLength = DeviceName->Length + sizeof(WCHAR);
UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
if (UpcaseDevice.Buffer == NULL)
{
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_ERR,
("<==ndisReferenceOpenByName: failed to allocate memory.\n"));
return NULL;
}
RtlUpcaseUnicodeString(&UpcaseDevice, DeviceName, FALSE);
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
//
// Now walk the open list and get to the open representing the DeviceName
//
for (Open = Protocol->OpenQueue;
Open != NULL;
Open = Open->ProtocolNextOpen)
{
if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, Open->RootDeviceName))
{
tmpOpen = Open;
ACQUIRE_SPIN_LOCK_DPC(&tmpOpen->SpinLock);
if (fUnbinding)
{
if (OPEN_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
fMINIPORT_OPEN_CLOSING |
fMINIPORT_OPEN_PROCESSING))
{
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("ndisReferenceOpenByName: Open %p is already getting unbind\n", Open));
Open = NULL;
}
else
{
M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
OPEN_SET_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
fMINIPORT_OPEN_DONT_FREE |
fMINIPORT_OPEN_PROCESSING);
}
}
else
{
if (OPEN_TEST_FLAG(Open, fMINIPORT_OPEN_PROCESSING))
{
Open = NULL;
}
else
{
M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
OPEN_SET_FLAG(Open, fMINIPORT_OPEN_PROCESSING);
}
}
RELEASE_SPIN_LOCK_DPC(&tmpOpen->SpinLock);
break;
}
}
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
if (Open != NULL)
{
Miniport = Open->MiniportHandle;
if (!MINIPORT_INCREMENT_REF(Miniport))
{
if (fUnbinding)
{
OPEN_CLEAR_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
fMINIPORT_OPEN_PROCESSING |
fMINIPORT_OPEN_DONT_FREE);
}
else
{
OPEN_CLEAR_FLAG(Open, fMINIPORT_OPEN_PROCESSING);
}
DeRefOpen = TRUE;
}
else
{
DeRefOpen = FALSE;
}
}
FREE_POOL(UpcaseDevice.Buffer);
if (DeRefOpen)
{
Miniport = Open->MiniportHandle;
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
ndisMDereferenceOpen(Open);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
Open = NULL;
}
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==ndisReferenceOpenByName: Open %p\n", Open ));
return(Open);
}
NTSTATUS
FASTCALL
ndisHandleLegacyTransport(
IN PUNICODE_STRING pDevice
)
{
NTSTATUS Status = STATUS_SUCCESS;
RTL_QUERY_REGISTRY_TABLE LinkQueryTable[3];
PWSTR Export = NULL;
HANDLE TdiHandle;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>ndisHandleLegacyTransport\n"));
if (ndisTdiRegisterCallback == NULL)
{
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==ndisHandleLegacyTransport\n"));
return STATUS_UNSUCCESSFUL;
}
//
// Set up LinkQueryTable to do the following:
//
//
// 1) Switch to the Linkage key below the xports registry key
//
LinkQueryTable[0].QueryRoutine = NULL;
LinkQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
LinkQueryTable[0].Name = L"Linkage";
//
// 2) Call ndisReadParameter for "Export" (as a single multi-string),
// which will allocate storage and save the data in Export.
//
LinkQueryTable[1].QueryRoutine = ndisReadParameter;
LinkQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
LinkQueryTable[1].Name = L"Export";
LinkQueryTable[1].EntryContext = (PVOID)&Export;
LinkQueryTable[1].DefaultType = REG_NONE;
//
// 3) Stop
//
LinkQueryTable[2].QueryRoutine = NULL;
LinkQueryTable[2].Flags = 0;
LinkQueryTable[2].Name = NULL;
do
{
UNICODE_STRING Us;
PWSTR CurExport;
//1 Context parameter probably should be use to verify data type
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
pDevice->Buffer,
LinkQueryTable,
(PVOID)NULL, // no context needed
NULL);
if (!NT_SUCCESS(Status))
{
//
// Do not complain about TDI drivers which do not
// have any linkages
//
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
Status = STATUS_SUCCESS;
}
break;
}
//
// Walk the list of exports and call TdiRegisterDevice for each
//
for (CurExport = Export;
*CurExport != 0;
CurExport = (PWCHAR)((PUCHAR)CurExport + Us.MaximumLength))
{
RtlInitUnicodeString (&Us, CurExport);
Status = (*ndisTdiRegisterCallback)(&Us, &TdiHandle);
if (!NT_SUCCESS(Status))
{
break;
}
}
} while (FALSE);
if (Export != NULL)
FREE_POOL(Export);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==ndisHandleLegacyTransport\n"));
return(Status);
}
VOID
FASTCALL
ndisInitializeBinding(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN PNDIS_PROTOCOL_BLOCK Protocol
)
{
PUNICODE_STRING ExportName;
NDIS_BIND_CONTEXT BindContext;
PDEVICE_OBJECT PhysicalDeviceObject;
NDIS_STATUS BindStatus;
UNICODE_STRING ProtocolSection;
UNICODE_STRING DerivedBaseName, Parms;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>ndisInitializeBinding\n"));
//
// Call the protocol to bind to the Miniport
//
WAIT_FOR_PROTO_MUTEX(Protocol);
do
{
//
// once we grabbed the protocol mutex, check again to see if
// the adapter is still there
//
if (!ndisIsMiniportStarted(Miniport) ||
((Miniport->PnPDeviceState != NdisPnPDeviceStarted) &&
(Miniport->PnPDeviceState != NdisPnPDeviceQueryStopped) &&
(Miniport->PnPDeviceState != NdisPnPDeviceQueryRemoved)))
{
break;
}
if (TRUE == ndisProtocolAlreadyBound(Protocol, Miniport))
{
//
// these two are already bound. just return
//
break;
}
ExportName = &Miniport->BindPaths->Paths[0];
Protocol->BindDeviceName = &Miniport->MiniportName;
Protocol->RootDeviceName = ExportName;
PhysicalDeviceObject = Miniport->PhysicalDeviceObject;
if (ndisReferenceProtocol(Protocol) == FALSE)
{
break;
}
RtlInitUnicodeString(&Parms, L"\\Parameters\\Adapters\\");
DerivedBaseName = *ExportName;
DerivedBaseName.Length -= ndisDeviceStr.Length;
DerivedBaseName.MaximumLength -= ndisDeviceStr.Length;
(PUCHAR)(DerivedBaseName.Buffer) += ndisDeviceStr.Length;
ProtocolSection.MaximumLength = Protocol->ProtocolCharacteristics.Name.Length + // "tcpip"
Parms.Length + // "\Parameters\Adapters\"
ExportName->Length - ndisDeviceStr.Length + // "{GUID}"
sizeof(WCHAR);
ProtocolSection.Length = 0;
ProtocolSection.Buffer = (PWSTR)ALLOC_FROM_POOL(ProtocolSection.MaximumLength,
NDIS_TAG_DEFAULT);
if (ProtocolSection.Buffer != NULL)
{
ZeroMemory(ProtocolSection.Buffer, ProtocolSection.MaximumLength);
RtlCopyUnicodeString(&ProtocolSection,
&Protocol->ProtocolCharacteristics.Name);
RtlAppendUnicodeStringToString(&ProtocolSection,
&Parms);
RtlAppendUnicodeStringToString(&ProtocolSection,
&DerivedBaseName);
}
else
{
ndisDereferenceProtocol(Protocol, FALSE);
break;
}
BindContext.Next = NULL;
BindContext.Protocol = Protocol;
BindContext.Miniport = Miniport;
BindContext.ProtocolSection = ProtocolSection;
BindContext.DeviceName = ExportName;
INITIALIZE_EVENT(&BindContext.Event);
if (!Protocol->Ref.Closing)
{
BindStatus = NDIS_STATUS_SUCCESS;
Protocol->BindingAdapter = Miniport;
(*Protocol->ProtocolCharacteristics.BindAdapterHandler)(&BindStatus,
&BindContext,
ExportName,
&ProtocolSection,
(PVOID)PhysicalDeviceObject);
if (BindStatus == NDIS_STATUS_PENDING)
{
WAIT_FOR_PROTOCOL(Protocol, &BindContext.Event);
BindStatus = BindContext.BindStatus;
}
Protocol->BindingAdapter = NULL;
if (BindStatus == NDIS_STATUS_SUCCESS)
{
ndisNotifyWmiBindUnbind(Miniport, Protocol, TRUE);
}
#if DBG
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
(" ndisInitializeBinding\n"));
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
&Protocol->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("\n Adapter: "));
if (Miniport->pAdapterInstanceName)
{
DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
Miniport->pAdapterInstanceName);
}
else
{
DBGPRINT_UNICODE(DBG_COMP_INIT, DBG_LEVEL_INFO,
&Miniport->BaseName);
}
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("\n Result: %lx\n", BindStatus));
#endif
}
FREE_POOL(ProtocolSection.Buffer);
Protocol->BindDeviceName = NULL;
ndisDereferenceProtocol(Protocol, FALSE);
} while (FALSE);
RELEASE_PROT_MUTEX(Protocol);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==ndisInitializeBinding\n"));
}
VOID
NdisCompleteBindAdapter(
IN NDIS_HANDLE BindAdapterContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenStatus
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PNDIS_BIND_CONTEXT pContext = (PNDIS_BIND_CONTEXT)BindAdapterContext;
UNREFERENCED_PARAMETER(OpenStatus);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>NdisCompleteBindAdapter\n"));
pContext->BindStatus = Status;
SET_EVENT(&pContext->Event);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==NdisCompleteBindAdapter\n"));
}
VOID
NdisCompleteUnbindAdapter(
IN NDIS_HANDLE UnbindAdapterContext,
IN NDIS_STATUS Status
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PNDIS_BIND_CONTEXT pContext = (PNDIS_BIND_CONTEXT)UnbindAdapterContext;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>NdisCompleteUnbindAdapter\n"));
pContext->BindStatus = Status;
SET_EVENT(&pContext->Event);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==NdisCompleteUnbindAdapter\n"));
}
VOID
NdisRegisterTdiCallBack(
IN TDI_REGISTER_CALLBACK RegisterCallback,
IN TDI_PNP_HANDLER PnPHandler
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>NdisRegisterTdiCallBack\n"));
if (ndisTdiRegisterCallback == NULL)
{
ndisTdiRegisterCallback = RegisterCallback;
}
if (ndisTdiPnPHandler == NULL)
{
ndisTdiPnPHandler = PnPHandler;
}
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==NdisRegisterTdiCallBack\n"));
}
VOID
NdisDeregisterTdiCallBack(
VOID
)
{
ndisTdiRegisterCallback = NULL;
ndisTdiPnPHandler = NULL;
}
VOID
ndisFindRootDevice(
IN PNDIS_STRING DeviceName,
IN BOOLEAN fTester,
OUT PNDIS_STRING * pBindDevice,
OUT PNDIS_STRING * pRootDevice,
OUT PNDIS_MINIPORT_BLOCK * pAdapter
)
/*++
Routine Description:
Find the Miniport which is the highest level filter given the target root name.
Arguments:
Return Value:
--*/
{
KIRQL OldIrql;
PNDIS_M_DRIVER_BLOCK MiniBlock;
PNDIS_MINIPORT_BLOCK Miniport;
PNDIS_STRING RootDevice = NULL, BindDevice = NULL;
NDIS_STRING UpcaseDevice;
PWSTR pwch;
UINT Depth = 1;
BOOLEAN Found = FALSE;
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisFindRootDevice\n"));
*pBindDevice = NULL;
*pRootDevice = NULL;
*pAdapter = NULL;
//
// First we need to upcase the device-name before checking
//
UpcaseDevice.Length = DeviceName->Length;
UpcaseDevice.MaximumLength = DeviceName->Length + sizeof(WCHAR);
UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
if ((pwch = UpcaseDevice.Buffer) == NULL)
{
return;
}
RtlUpcaseUnicodeString(&UpcaseDevice, DeviceName, FALSE);
BindDevice = &UpcaseDevice;
ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
PnPReferencePackage();
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
for (MiniBlock = ndisMiniDriverList;
MiniBlock != NULL;
MiniBlock = MiniBlock->NextDriver)
{
ACQUIRE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
for (Miniport = MiniBlock->MiniportQueue;
Miniport != NULL;
Miniport = Miniport->NextMiniport)
{
if (fTester)
{
if (NDIS_EQUAL_UNICODE_STRING(BindDevice, &Miniport->MiniportName))
{
BindDevice = &Miniport->MiniportName;
RootDevice = &Miniport->MiniportName;
*pAdapter = Miniport;
Found = TRUE;
break;
}
}
else if ((Miniport->BindPaths->Number >= Depth) &&
NDIS_EQUAL_UNICODE_STRING(BindDevice, &Miniport->BindPaths->Paths[0]))
{
RootDevice = &Miniport->BindPaths->Paths[0];
BindDevice = &Miniport->MiniportName;
*pAdapter = Miniport;
Depth = Miniport->BindPaths->Number;
Found = TRUE;
}
}
RELEASE_SPIN_LOCK_DPC(&MiniBlock->Ref.SpinLock);
if (fTester && Found)
{
break;
}
}
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
PnPDereferencePackage();
FREE_POOL(pwch);
if (Found)
{
*pBindDevice = BindDevice;
*pRootDevice = RootDevice;
}
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisFindRootDevice\n"));
}
VOID
ndisNotifyWmiBindUnbind(
PNDIS_MINIPORT_BLOCK Miniport,
PNDIS_PROTOCOL_BLOCK Protocol,
BOOLEAN fBind
)
/*++
Routine Description:
Notify WMI that either a bind or an unbind has occured.
Arguments:
Return Value:
--*/
{
PWNODE_SINGLE_INSTANCE wnode;
PUCHAR ptmp;
NTSTATUS NtStatus;
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisNotifyWmiBindUnbind: Miniport %p, Protocol %p, fBind %lx\n", Miniport, Protocol, fBind));
ndisSetupWmiNode(Miniport,
Miniport->pAdapterInstanceName,
Miniport->BindPaths->Paths[0].Length + sizeof(WCHAR) +
Protocol->ProtocolCharacteristics.Name.Length + sizeof(WCHAR),
fBind ? (PVOID)&GUID_NDIS_NOTIFY_BIND : (PVOID)&GUID_NDIS_NOTIFY_UNBIND,
&wnode);
if (wnode != NULL)
{
//
// Save the number of elements in the first ULONG.
//
ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
//
// Copy the data which is the protocol name + the miniport name in the data field
// Protocol<NULL>MiniportName<NULL>
//
RtlCopyMemory(ptmp,
Protocol->ProtocolCharacteristics.Name.Buffer,
Protocol->ProtocolCharacteristics.Name.Length);
RtlCopyMemory(ptmp + Protocol->ProtocolCharacteristics.Name.Length + sizeof(WCHAR),
Miniport->BindPaths->Paths[0].Buffer,
Miniport->BindPaths->Paths[0].Length);
//
// notify kernel mode components who have registered for Ndis BindUnbind event
//
if (ndisBindUnbindCallbackObject != NULL)
{
ExNotifyCallback(ndisBindUnbindCallbackObject,
(PVOID)wnode,
NULL);
}
//
// Indicate the event to WMI. WMI will take care of freeing
// the WMI struct back to pool.
//
NtStatus = IoWMIWriteEvent(wnode);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("IoWMIWriteEvent failed %lx\n", NtStatus));
FREE_POOL(wnode);
}
}
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisNotifyWmiBindUnbind: Miniport %p, Protocol %p, fBind %lx\n", Miniport, Protocol, fBind));
return;
}
VOID
ndisNotifyDevicePowerStateChange(
PNDIS_MINIPORT_BLOCK Miniport,
NDIS_DEVICE_POWER_STATE PowerState
)
/*++
Routine Description:
Notify WMI that that the power state of a NIC is changed.
Arguments:
Return Value:
--*/
{
PWNODE_SINGLE_INSTANCE wnode;
PUCHAR ptmp;
NTSTATUS NtStatus;
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisNotifyDevicePowerStateChange: Miniport %p, PowerState %lx\n", Miniport, PowerState));
ndisSetupWmiNode(Miniport,
Miniport->pAdapterInstanceName,
Miniport->MiniportName.Length + sizeof(WCHAR),
(PowerState == NdisDeviceStateD0) ? (PVOID)&GUID_NDIS_NOTIFY_DEVICE_POWER_ON : (PVOID)&GUID_NDIS_NOTIFY_DEVICE_POWER_OFF,
&wnode);
if (wnode != NULL)
{
//
// Save the number of elements in the first ULONG.
//
ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
RtlCopyMemory(ptmp,
Miniport->MiniportName.Buffer,
Miniport->MiniportName.Length);
//
// Indicate the event to WMI. WMI will take care of freeing
// the WMI struct back to pool.
//
NtStatus = IoWMIWriteEvent(wnode);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("IoWMIWriteEvent failed %lx\n", NtStatus));
FREE_POOL(wnode);
}
}
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisNotifyDevicePowerStateChange: Miniport %p, PowerState %lx\n", Miniport, PowerState));
return;
}
BOOLEAN
NdisMatchPdoWithPacket(
IN PNDIS_PACKET Packet,
IN PVOID Pdo
)
{
PNDIS_STACK_RESERVED NSR;
PNDIS_MINIPORT_BLOCK Miniport;
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR);
Miniport = NSR->Miniport;
return (Pdo == Miniport->PhysicalDeviceObject);
}
VOID
ndisPowerStateCallback(
PVOID CallBackContext,
PVOID Argument1,
PVOID Argument2
)
{
ULONG Action = (ULONG)((ULONG_PTR)Argument1);
ULONG State = (ULONG)((ULONG_PTR)Argument2);
NDIS_POWER_PROFILE PowerProfile;
UNREFERENCED_PARAMETER(CallBackContext);
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPowerStateCallback: Action %lx, State %lx\n", Action, State));
if (Action == PO_CB_AC_STATUS)
{
ndisAcOnLine = State;
PowerProfile = ((BOOLEAN)ndisAcOnLine == TRUE) ? NdisPowerProfileAcOnLine : NdisPowerProfileBattery;
ndisNotifyMiniports((PNDIS_MINIPORT_BLOCK)NULL,
NdisDevicePnPEventPowerProfileChanged,
&PowerProfile,
sizeof(NDIS_POWER_PROFILE));
}
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPowerStateCallback: Action %lx, State %lx\n", Action, State));
}
VOID
ndisNotifyMiniports(
IN PNDIS_MINIPORT_BLOCK Miniport OPTIONAL,
IN NDIS_DEVICE_PNP_EVENT DevicePnPEvent,
IN PVOID Buffer,
IN ULONG Length
)
{
PNDIS_M_DRIVER_BLOCK MiniBlock, NextMiniBlock;
PNDIS_MINIPORT_BLOCK CurMiniport;
KIRQL OldIrql;
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisNotifyMiniportsPowerProfileChange: Miniport %p, Event %lx, Buffer %p\n",
Miniport,
DevicePnPEvent,
Buffer));
PnPReferencePackage();
do
{
if (Miniport)
{
if(Miniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler != NULL)
{
//
// if Miniport has been specified, the caller is responsible to make sure it is valid and appropriate
// to call the miniport
//
Miniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler(Miniport->MiniportAdapterContext,
DevicePnPEvent,
Buffer,
Length);
}
break;
}
//
// notification is for all the miniports
//
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
for (MiniBlock = ndisMiniDriverList;
MiniBlock != NULL;
MiniBlock = NextMiniBlock)
{
if (ndisReferenceDriver(MiniBlock))
{
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
while ((CurMiniport = ndisReferenceNextUnprocessedMiniport(MiniBlock)) != NULL)
{
if (CurMiniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler != NULL)
{
CurMiniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler(CurMiniport->MiniportAdapterContext,
NdisDevicePnPEventPowerProfileChanged,
Buffer,
Length);
}
}
ndisUnprocessAllMiniports(MiniBlock);
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
NextMiniBlock = MiniBlock->NextDriver;
ndisDereferenceDriver(MiniBlock, TRUE);
}
else
{
NextMiniBlock = MiniBlock->NextDriver;
}
}
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
} while (FALSE);
PnPDereferencePackage();
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==>ndisNotifyMiniportsPowerProfileChange: Miniport %p\n", Miniport));
return;
}
PNDIS_MINIPORT_BLOCK
ndisReferenceNextUnprocessedMiniport(
IN PNDIS_M_DRIVER_BLOCK MiniBlock
)
{
PNDIS_MINIPORT_BLOCK Miniport;
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisReferenceNextUnprocessedMiniport: MiniBlock %p\n", MiniBlock));
ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
for (Miniport = MiniBlock->MiniportQueue;
Miniport != NULL;
Miniport = Miniport->NextMiniport)
{
if (!MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_DEREGISTERED_INTERRUPT |
fMINIPORT_RESET_IN_PROGRESS |
fMINIPORT_PM_HALTING)) &&
!MINIPORT_PNP_TEST_FLAG(Miniport, (fMINIPORT_REMOVE_IN_PROGRESS |
fMINIPORT_DEVICE_FAILED |
fMINIPORT_PM_HALTED |
fMINIPORT_HALTING |
fMINIPORT_SHUTTING_DOWN |
fMINIPORT_PROCESSING)) &&
(Miniport->PnPDeviceState == NdisPnPDeviceStarted) &&
(Miniport->CurrentDevicePowerState == PowerDeviceD0) &&
MINIPORT_INCREMENT_REF(Miniport))
{
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_PROCESSING);
break;
}
}
RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisReferenceNextUnprocessedMiniport: MiniBlock %p\n", MiniBlock));
return(Miniport);
}
VOID
ndisUnprocessAllMiniports(
IN PNDIS_M_DRIVER_BLOCK MiniBlock
)
{
PNDIS_MINIPORT_BLOCK Miniport;
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisUnprocessAllMiniports: MiniBlock %p\n", MiniBlock));
while (TRUE)
{
ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
//
// find the first miniport that is being proccessed. clear the flag, dereference the
// miniport and go through the whole process again.
//
for (Miniport = MiniBlock->MiniportQueue;
Miniport != NULL;
Miniport = Miniport->NextMiniport)
{
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PROCESSING))
{
MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_PROCESSING);
break;
}
}
RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
if (Miniport == NULL)
break;
//
// dereferencing the miniport could make it to go away
//
MINIPORT_DECREMENT_REF(Miniport);
}
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisUnprocessAllMiniports: MiniBlock %p\n", MiniBlock));
}
//1 add function header
PVOID
NdisGetRoutineAddress(
IN PNDIS_STRING NdisRoutineName
)
{
PVOID Address;
ANSI_STRING AnsiString;
NTSTATUS Status;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
Status = RtlUnicodeStringToAnsiString(&AnsiString,
(PUNICODE_STRING)NdisRoutineName,
TRUE);
if (!NT_SUCCESS(Status))
{
return NULL;
}
Address = FindExportedRoutineByName(ndisDriverObject->DriverStart, &AnsiString);
RtlFreeAnsiString (&AnsiString);
return Address;
}
PVOID
FindExportedRoutineByName (
IN PVOID DllBase,
IN PANSI_STRING AnsiImageRoutineName
)
/*++
Routine Description:
This function searches the argument module looking for the requested
exported function name.
Arguments:
DllBase - Supplies the base address of the requested module.
AnsiImageRoutineName - Supplies the ANSI routine name being searched for.
Return Value:
The virtual address of the requested routine or NULL if not found.
--*/
{
USHORT OrdinalNumber;
PULONG NameTableBase;
PUSHORT NameOrdinalTableBase;
PULONG Addr;
ULONG High;
ULONG Low;
ULONG Middle;
LONG Result;
ULONG ExportSize;
PVOID FunctionAddress;
PIMAGE_EXPORT_DIRECTORY ExportDirectory;
PAGED_CODE();
FunctionAddress = NULL;
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
DllBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportSize
);
if (ExportDirectory == NULL) {
return NULL;
}
//
// Initialize the pointer to the array of RVA-based ansi export strings.
//
NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);
//
// Initialize the pointer to the array of USHORT ordinal numbers.
//
NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);
//
// Lookup the desired name in the name table using a binary search.
//
Low = 0;
High = ExportDirectory->NumberOfNames - 1;
//
// Initializing Middle is not needed for correctness, but without it
// the compiler cannot compile this code W4 to check for use of
// uninitialized variables.
//
Middle = 0;
while (High >= Low && (LONG)High >= 0) {
//
// Compute the next probe index and compare the import name
// with the export name entry.
//
Middle = (Low + High) >> 1;
//1 investigate using strncmp
Result = strcmp (AnsiImageRoutineName->Buffer,
(PCHAR)DllBase + NameTableBase[Middle]);
if (Result < 0) {
High = Middle - 1;
}
else if (Result > 0) {
Low = Middle + 1;
}
else {
break;
}
}
//
// If the high index is less than the low index, then a matching
// table entry was not found. Otherwise, get the ordinal number
// from the ordinal table.
//
if ((LONG)High < (LONG)Low) {
return NULL;
}
OrdinalNumber = NameOrdinalTableBase[Middle];
//
// If the OrdinalNumber is not within the Export Address Table,
// then this image does not implement the function. Return not found.
//
if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {
return NULL;
}
//
// Index into the array of RVA export addresses by ordinal number.
//
Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);
FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);
//
// Forwarders are not used by the kernel and HAL to each other.
//
if ((ULONG_PTR)FunctionAddress > (ULONG_PTR)ExportDirectory &&
(ULONG_PTR)FunctionAddress < ((ULONG_PTR)ExportDirectory + ExportSize)) {
FunctionAddress = NULL;
}
return FunctionAddress;
}
UINT
NdisGetVersion(
VOID
)
{
return ((NDIS_MAJOR_VERSION << 16) | NDIS_MINOR_VERSION);
}
#if 0
VOID
ndisBindUnbindCallback(
PVOID CallBackContext,
PVOID Argument1,
PVOID Argument2
)
{
PWNODE_SINGLE_INSTANCE wnode = (PWNODE_SINGLE_INSTANCE)Argument1;
PUCHAR ptmp;
UNICODE_STRING ProtocolName, MiniportName;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisBindUnbindCallback\n"));
if (wnode != NULL)
{
ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
RtlInitUnicodeString(&ProtocolName, (PWCHAR)ptmp);
ptmp += ProtocolName.Length + sizeof(WCHAR);
RtlInitUnicodeString(&MiniportName, (PWCHAR)ptmp);
ndisDbgPrintUnicodeString(&ProtocolName);
DbgPrint("\n");
ndisDbgPrintUnicodeString(&MiniportName);
DbgPrint("\n");
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisBindUnbindCallback\n"));
}
}
#endif