diff --git a/reactos/drivers/net/ndis/ndis/enum.c b/reactos/drivers/net/ndis/ndis/enum.c new file mode 100644 index 00000000000..47be38910dd --- /dev/null +++ b/reactos/drivers/net/ndis/ndis/enum.c @@ -0,0 +1,453 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS NDIS library + * FILE: ndis/config.c + * PURPOSE: NDIS Configuration Services + * PROGRAMMERS: Vizzini (vizzini@plasmic.com) + * REVISIONS: + * Vizzini 08-20-2003 Created + * NOTES: + * - Currently this only supports enumeration of Root and PCI devices + * - This whole thing is really just a band-aid until we have real PnP + * - Strictly speaking, I'm not even sure it's my job to call + * HalAssignSlotResources(), but the vmware nic driver likes it + * - Please send me feedback if there is a better way :) + * TODO: + * - Break these functions up a bit; i hate 200-line functions + */ + +#include +#include + +/* Registry path to the enumeration database */ +#define ENUM_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum" + +/* Registry path to the services database */ +#define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services" + +/* + * This has to be big enough to hold enumerated registry paths until + * registry accesses are properly re-coded + */ +#define KEY_INFORMATION_SIZE 512 + +/* same sort of deal as above */ +#define VALUE_INFORMATION_SIZE 100 + +/* + * NET class GUID, as defined by Microsoft, used to tell if a + * device belongs to NDIS or not. + */ +#define NET_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define RZ() do { DbgPrint("%s:%i Checking RedZone\n", __FILE__, __LINE__ ); ExAllocatePool(PagedPool,0); } while (0); + +/* see miniport.c */ +extern LIST_ENTRY OrphanAdapterListHead; +extern KSPIN_LOCK OrphanAdapterListLock; + + +BOOLEAN NdisFindDevicePci(UINT VendorID, UINT DeviceID, PUINT BusNumber, PUINT SlotNumber) +/* + * FUNCTION: Find a PCI device given its Vendor and Device IDs + * ARGUMENTS: + * VendorID: The card's PCI Vendor ID + * DeviceID: The card's PCI Device ID + * BusNumber: The card's bus number on success + * SlotNumber: The card's slot number on success + * RETURNS: + * TRUE if the card is fouund + * FALSE Otherwise + * NOTES: + * - This only finds the first card of a type + * - This doesn't handle function enumeration correctly + * - Based loosely on Dekker & Newcomer examples + */ +{ + PCI_COMMON_CONFIG PciData; + int i, j, k; + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + /* dekker says there are 256 possible PCI buses */ + for(i = 0; i < 256; i++) + { + for(j = 0; j < PCI_MAX_DEVICES; j++) + { + for(k = 0; k < PCI_MAX_FUNCTION; k++) + { + /* TODO: figure out what to do with k */ + + if(HalGetBusData(PCIConfiguration, i, j, &PciData, sizeof(PciData))) + { + if(PciData.VendorID == 0xffff) /* Is this handled right? */ + continue; + + if(PciData.VendorID == VendorID && PciData.DeviceID == DeviceID) + { + if(BusNumber) + *BusNumber = i; + if(SlotNumber) + *SlotNumber = j; + + return TRUE; + } + } + } + } + } + + NDIS_DbgPrint(MAX_TRACE, ("Didn't find device 0x%x:0x%x\n", VendorID, DeviceID)); + + return FALSE; +} + + +VOID NdisStartDriver(PUNICODE_STRING uBusName, PUNICODE_STRING uDeviceId, PUNICODE_STRING uServiceName) +/* + * FUNCTION: Starts an NDIS driver + * ARGUMENTS: + * uBusName: the card's bus type, by name, as extracted from the + * enumeration database in the registry + * uDeviceId: the card's device ID + * uServiceName: the driver (scm db entry) associated with the card + * NOTES: + * - This doesn't prooperly handle multiple instances of the same card or driver + * - for PCI cards, this finds the card and creates an "orphan" adapter object for + * it. This object is tagged with the registry key to the driver and includes + * the slot number and bus number of the card. NOTE that some stupid nic drivers + * still depend on a registry key for slot number, so this isn't always enough. + * Whatever the case, all of the card's resources are enumerated and assigned + * via HalAssignSlotResources() and the orphan adapter is put onto the list. + * When the miniport calls NdisMRegisterMiniport(), ndis loops through the list + * of orphans and associates any orphans that belong to that miniport with + * its corresponding LOGICAL_ADAPTER objects. + */ +{ + ULONG VendorId; + ULONG DeviceId; + UINT SlotNumber; + UINT BusNumber; + UNICODE_STRING Temp; + UNICODE_STRING ServiceKey; + PWCHAR ServiceKeyStr; + NTSTATUS NtStatus; + PORPHAN_ADAPTER OrphanAdapter; + + NDIS_DbgPrint(MAX_TRACE, ("Called; Starting %wZ\n", uServiceName)); + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + /* prepare a services key */ + ServiceKeyStr = ExAllocatePool(PagedPool, sizeof(SERVICES_KEY) + sizeof(WCHAR) + uServiceName->Length); + if(!ServiceKeyStr) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient Resources.\n")); + return; + } + + wcscpy(ServiceKeyStr, SERVICES_KEY); + wcscat(ServiceKeyStr, L"\\"); + wcsncat(ServiceKeyStr, uServiceName->Buffer, uServiceName->Length/sizeof(WCHAR)); + ServiceKeyStr[wcslen(SERVICES_KEY)+1+uServiceName->Length/sizeof(WCHAR)] = 0; + + RtlInitUnicodeString(&ServiceKey, ServiceKeyStr); + + if(!wcsncmp(uBusName->Buffer, L"PCI", uBusName->Length)) + { + /* + * first see if a card with the requested id exists. + * PCI IDs are formatted VEN_ABCD&DEV_ABCD[&...] + */ + + if(wcsncmp(uDeviceId->Buffer, L"VEN_", 4)) + { + NDIS_DbgPrint(MIN_TRACE, ("Bogus uDeviceId parsing VEN\n")); + ExFreePool(ServiceKeyStr); + return; + } + + Temp.Buffer = &(uDeviceId->Buffer[4]); /* offset of vendor id */ + Temp.Length = Temp.MaximumLength = 4 * sizeof(WCHAR); /* 4-digit id */ + + NtStatus = RtlUnicodeStringToInteger(&Temp, 16, &VendorId); + if(!NT_SUCCESS(NtStatus)) + { + NDIS_DbgPrint(MIN_TRACE, ("RtlUnicodeStringToInteger returned 0x%x\n", NtStatus)); + ExFreePool(ServiceKeyStr); + return; + } + + if(wcsncmp(&(uDeviceId->Buffer[9]), L"DEV_", 4)) + { + NDIS_DbgPrint(MIN_TRACE, ("Bogus uDeviceId parsing DEV\n")); + ExFreePool(ServiceKeyStr); + return; + } + + Temp.Buffer = &(uDeviceId->Buffer[13]); /* offset of device id */ + Temp.Length = 4 * sizeof(WCHAR); /* 4-dight id */ + + NtStatus = RtlUnicodeStringToInteger(&Temp, 16, &DeviceId); + if(!NT_SUCCESS(NtStatus)) + { + NDIS_DbgPrint(MIN_TRACE, ("RtlUnicodeStringToInteger returned 0x%x\n", NtStatus)); + ExFreePool(ServiceKeyStr); + return; + } + + if(!NdisFindDevicePci(VendorId, DeviceId, &BusNumber, &SlotNumber)) + { + NDIS_DbgPrint(MIN_TRACE, ("Didn't find a configured card 0x%x 0x%x\n", VendorId, DeviceId)); + ExFreePool(ServiceKeyStr); + return; + } + + NDIS_DbgPrint(MAX_TRACE, ("Found a card 0x%x 0x%x at bus 0x%x slot 0x%x\n", VendorId, DeviceId, BusNumber, SlotNumber)); + + OrphanAdapter = ExAllocatePool(PagedPool, sizeof(ORPHAN_ADAPTER)); + if(!OrphanAdapter) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient Resources.\n")); + ExFreePool(ServiceKeyStr); + return; + } + + OrphanAdapter->RegistryPath.Buffer = ExAllocatePool(PagedPool, Temp.MaximumLength); + if(!OrphanAdapter->RegistryPath.Buffer) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient Resources.\n")); + ExFreePool(ServiceKeyStr); + return; + } + + OrphanAdapter->RegistryPath.Length = Temp.Length; + OrphanAdapter->RegistryPath.MaximumLength = Temp.MaximumLength; + memcpy(OrphanAdapter->RegistryPath.Buffer, Temp.Buffer, Temp.Length); + + OrphanAdapter->BusType = PCIBus; + OrphanAdapter->BusNumber = BusNumber; + OrphanAdapter->SlotNumber = SlotNumber; + + ExInterlockedInsertTailList(&OrphanAdapterListHead, &OrphanAdapter->ListEntry, &OrphanAdapterListLock); + } + + /* + * found a card; start its driver. this should be done from a + * system thread, after NDIS.SYS's DriverEntry returns, but I + * really don't know how to block on DriverEntry returning, so + * what the hell. + */ + + NDIS_DbgPrint(MID_TRACE, ("Loading driver %wZ\n", &ServiceKey)); + ZwLoadDriver(&ServiceKey); + + ExFreePool(ServiceKeyStr); +} + + +VOID NdisStartDevices() +/* + * FUNCTION: Find and start all NDIS Net class devices + * NOTES: + * - Not sure if this handles multiple instances of the same + * device or driver correctly yet + */ +{ + HANDLE EnumHandle; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName; + NTSTATUS NtStatus; + ULONG EnumIndex = 0; + ULONG ResultLength; + PKEY_BASIC_INFORMATION KeyInformation; + ULONG KeyInformationLength; + + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + RtlInitUnicodeString(&KeyName, ENUM_KEY); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, 0); + NtStatus = ZwOpenKey(&EnumHandle, KEY_ALL_ACCESS, &ObjectAttributes); + if(!NT_SUCCESS(NtStatus)) + { + NDIS_DbgPrint(MIN_TRACE, ("Unable to open the Enum key\n")); + return; + } + + NDIS_DbgPrint(MAX_TRACE, ("Opened the enum key\n")); + + KeyInformation = ExAllocatePool(PagedPool, KEY_INFORMATION_SIZE); // should be enough for most key names? + if(!KeyInformation) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return; + } + + KeyInformationLength = KEY_INFORMATION_SIZE; + + while(NT_SUCCESS(ZwEnumerateKey(EnumHandle, EnumIndex, + KeyBasicInformation, KeyInformation, KeyInformationLength, &ResultLength))) + { + /* iterate through each enumerator (PCI, Root, ISAPNP, etc) */ + + HANDLE EnumeratorHandle; + WCHAR *EnumeratorStr; + UINT EnumeratorIndex = 0; + + NDIS_DbgPrint(MAX_TRACE, ("Enum iteration 0x%x\n", EnumIndex)); + + EnumIndex++; + + EnumeratorStr = ExAllocatePool(PagedPool, sizeof(WCHAR) + KeyInformation->NameLength); + if(!EnumeratorStr) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return; + } + + wcsncpy(EnumeratorStr, KeyInformation->Name, KeyInformation->NameLength/sizeof(WCHAR)); + EnumeratorStr[KeyInformation->NameLength/sizeof(WCHAR)] = 0; + + RtlInitUnicodeString(&KeyName, EnumeratorStr); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, EnumHandle, 0); + if(!NT_SUCCESS(ZwOpenKey(&EnumeratorHandle, KEY_ALL_ACCESS, &ObjectAttributes))) + { + NDIS_DbgPrint(MIN_TRACE, ("Failed to open key %wZ\n", &KeyName)); + return; + } + + while(NT_SUCCESS(ZwEnumerateKey(EnumeratorHandle, EnumeratorIndex, KeyBasicInformation, + KeyInformation, KeyInformationLength, &ResultLength))) + { + /* iterate through each device id */ + + HANDLE DeviceHandle; + WCHAR *DeviceStr; + UINT DeviceIndex = 0; + UNICODE_STRING BusName; + + BusName.Buffer = KeyName.Buffer; + BusName.Length = KeyName.Length; + BusName.MaximumLength = KeyName.MaximumLength; + + EnumeratorIndex++; + + DeviceStr = ExAllocatePool(PagedPool, KeyInformation->NameLength + sizeof(WCHAR)); + if(!DeviceStr) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return; + } + + wcsncpy(DeviceStr, KeyInformation->Name, KeyInformation->NameLength/sizeof(WCHAR)); + DeviceStr[KeyInformation->NameLength/sizeof(WCHAR)] = 0; + + RtlInitUnicodeString(&KeyName, DeviceStr); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, EnumeratorHandle, 0); + if(!NT_SUCCESS(ZwOpenKey(&DeviceHandle, KEY_ALL_ACCESS, &ObjectAttributes))) + { + NDIS_DbgPrint(MIN_TRACE, ("Failed to open key %wZ\n", &KeyName)); + return; + } + + while(NT_SUCCESS(ZwEnumerateKey(DeviceHandle, DeviceIndex, KeyBasicInformation, + KeyInformation, KeyInformationLength, &ResultLength))) + { + /* iterate through each instance id, starting drivers in the process */ + HANDLE InstanceHandle; + WCHAR *InstanceStr; + UNICODE_STRING ValueName; + UNICODE_STRING ServiceName; + PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; + ULONG KeyValueInformationLength; + UNICODE_STRING DeviceId; + + DeviceId.Buffer = KeyName.Buffer; + DeviceId.Length = KeyName.Length; + DeviceId.MaximumLength = KeyName.MaximumLength; + + DeviceIndex++; + + InstanceStr = ExAllocatePool(PagedPool, KeyInformation->NameLength + sizeof(WCHAR)); + if(!InstanceStr) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return; + } + + wcsncpy(InstanceStr, KeyInformation->Name, KeyInformation->NameLength/sizeof(WCHAR)); + InstanceStr[KeyInformation->NameLength/sizeof(WCHAR)] = 0; + + NDIS_DbgPrint(MAX_TRACE, ("NameLength = 0x%x and InstanceStr: %ws\n", KeyInformation->NameLength, InstanceStr)); + + RtlInitUnicodeString(&KeyName, InstanceStr); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DeviceHandle, 0); + if(!NT_SUCCESS(ZwOpenKey(&InstanceHandle, KEY_ALL_ACCESS, &ObjectAttributes))) + { + NDIS_DbgPrint(MIN_TRACE, ("Failed to open key %wZ\n", &KeyName)); + return; + } + + /* read class, looking for net guid */ + RtlInitUnicodeString(&ValueName, L"ClassGUID"); + + NDIS_DbgPrint(MAX_TRACE, ("About to ask for 0x%x bytes\n", VALUE_INFORMATION_SIZE)); + + KeyValueInformation = ExAllocatePool(PagedPool, VALUE_INFORMATION_SIZE); + if(!KeyValueInformation) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return; + } + + KeyValueInformationLength = VALUE_INFORMATION_SIZE; + + NtStatus = ZwQueryValueKey(InstanceHandle, &ValueName, KeyValuePartialInformation, + KeyValueInformation, KeyValueInformationLength, &ResultLength); + if(!NT_SUCCESS(NtStatus)) + { + /* this isn't fatal, it just means that this device isn't ours */ + NDIS_DbgPrint(MID_TRACE, ("Failed to query value %wZ from key %wZ\n", &ValueName, &KeyName)); + continue; + } + + if(!wcsncmp(NET_GUID, (PWCHAR)KeyValueInformation->Data, KeyValueInformation->DataLength/sizeof(WCHAR))) + { + RtlInitUnicodeString(&ValueName, L"Service"); + + NtStatus = ZwQueryValueKey(InstanceHandle, &ValueName, KeyValuePartialInformation, + KeyValueInformation, KeyValueInformationLength, &ResultLength); + if(!NT_SUCCESS(NtStatus)) + { + /* non-fatal also */ + NDIS_DbgPrint(MID_TRACE, ("Failed to query value %wZ from key %wZ\n", &ValueName, &KeyName)); + continue; + } + + /* this is a net driver; start it */ + ServiceName.Length = ServiceName.MaximumLength = KeyValueInformation->DataLength; + ServiceName.Buffer = (PWCHAR)KeyValueInformation->Data; + NdisStartDriver(&BusName, &DeviceId, &ServiceName); + } + else + NDIS_DbgPrint(MAX_TRACE, ("...this device is not ours\n")); + + ExFreePool(KeyValueInformation); + ExFreePool(InstanceStr); + ZwClose(InstanceHandle); + } + + ExFreePool(DeviceStr); + ZwClose(DeviceHandle); + } + + ExFreePool(EnumeratorStr); + ZwClose(EnumeratorHandle); + } + + ZwClose(EnumHandle); + ExFreePool(KeyInformation); +} +