--- /dev/null
+/*
+ * 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 <ndissys.h>
+#include <miniport.h>
+
+/* 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;
+}
+
+\f
+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);
+}
+
+\f
+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);
+}
+