nic enumerator
[reactos.git] / reactos / drivers / net / ndis / ndis / enum.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
4 * FILE: ndis/config.c
5 * PURPOSE: NDIS Configuration Services
6 * PROGRAMMERS: Vizzini (vizzini@plasmic.com)
7 * REVISIONS:
8 * Vizzini 08-20-2003 Created
9 * NOTES:
10 * - Currently this only supports enumeration of Root and PCI devices
11 * - This whole thing is really just a band-aid until we have real PnP
12 * - Strictly speaking, I'm not even sure it's my job to call
13 * HalAssignSlotResources(), but the vmware nic driver likes it
14 * - Please send me feedback if there is a better way :)
15 * TODO:
16 * - Break these functions up a bit; i hate 200-line functions
17 */
18
19 #include <ndissys.h>
20 #include <miniport.h>
21
22 /* Registry path to the enumeration database */
23 #define ENUM_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum"
24
25 /* Registry path to the services database */
26 #define SERVICES_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
27
28 /*
29 * This has to be big enough to hold enumerated registry paths until
30 * registry accesses are properly re-coded
31 */
32 #define KEY_INFORMATION_SIZE 512
33
34 /* same sort of deal as above */
35 #define VALUE_INFORMATION_SIZE 100
36
37 /*
38 * NET class GUID, as defined by Microsoft, used to tell if a
39 * device belongs to NDIS or not.
40 */
41 #define NET_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
42
43 #define RZ() do { DbgPrint("%s:%i Checking RedZone\n", __FILE__, __LINE__ ); ExAllocatePool(PagedPool,0); } while (0);
44
45 /* see miniport.c */
46 extern LIST_ENTRY OrphanAdapterListHead;
47 extern KSPIN_LOCK OrphanAdapterListLock;
48
49
50 BOOLEAN NdisFindDevicePci(UINT VendorID, UINT DeviceID, PUINT BusNumber, PUINT SlotNumber)
51 /*
52 * FUNCTION: Find a PCI device given its Vendor and Device IDs
53 * ARGUMENTS:
54 * VendorID: The card's PCI Vendor ID
55 * DeviceID: The card's PCI Device ID
56 * BusNumber: The card's bus number on success
57 * SlotNumber: The card's slot number on success
58 * RETURNS:
59 * TRUE if the card is fouund
60 * FALSE Otherwise
61 * NOTES:
62 * - This only finds the first card of a type
63 * - This doesn't handle function enumeration correctly
64 * - Based loosely on Dekker & Newcomer examples
65 */
66 {
67 PCI_COMMON_CONFIG PciData;
68 int i, j, k;
69
70 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
71
72 /* dekker says there are 256 possible PCI buses */
73 for(i = 0; i < 256; i++)
74 {
75 for(j = 0; j < PCI_MAX_DEVICES; j++)
76 {
77 for(k = 0; k < PCI_MAX_FUNCTION; k++)
78 {
79 /* TODO: figure out what to do with k */
80
81 if(HalGetBusData(PCIConfiguration, i, j, &PciData, sizeof(PciData)))
82 {
83 if(PciData.VendorID == 0xffff) /* Is this handled right? */
84 continue;
85
86 if(PciData.VendorID == VendorID && PciData.DeviceID == DeviceID)
87 {
88 if(BusNumber)
89 *BusNumber = i;
90 if(SlotNumber)
91 *SlotNumber = j;
92
93 return TRUE;
94 }
95 }
96 }
97 }
98 }
99
100 NDIS_DbgPrint(MAX_TRACE, ("Didn't find device 0x%x:0x%x\n", VendorID, DeviceID));
101
102 return FALSE;
103 }
104
105 \f
106 VOID NdisStartDriver(PUNICODE_STRING uBusName, PUNICODE_STRING uDeviceId, PUNICODE_STRING uServiceName)
107 /*
108 * FUNCTION: Starts an NDIS driver
109 * ARGUMENTS:
110 * uBusName: the card's bus type, by name, as extracted from the
111 * enumeration database in the registry
112 * uDeviceId: the card's device ID
113 * uServiceName: the driver (scm db entry) associated with the card
114 * NOTES:
115 * - This doesn't prooperly handle multiple instances of the same card or driver
116 * - for PCI cards, this finds the card and creates an "orphan" adapter object for
117 * it. This object is tagged with the registry key to the driver and includes
118 * the slot number and bus number of the card. NOTE that some stupid nic drivers
119 * still depend on a registry key for slot number, so this isn't always enough.
120 * Whatever the case, all of the card's resources are enumerated and assigned
121 * via HalAssignSlotResources() and the orphan adapter is put onto the list.
122 * When the miniport calls NdisMRegisterMiniport(), ndis loops through the list
123 * of orphans and associates any orphans that belong to that miniport with
124 * its corresponding LOGICAL_ADAPTER objects.
125 */
126 {
127 ULONG VendorId;
128 ULONG DeviceId;
129 UINT SlotNumber;
130 UINT BusNumber;
131 UNICODE_STRING Temp;
132 UNICODE_STRING ServiceKey;
133 PWCHAR ServiceKeyStr;
134 NTSTATUS NtStatus;
135 PORPHAN_ADAPTER OrphanAdapter;
136
137 NDIS_DbgPrint(MAX_TRACE, ("Called; Starting %wZ\n", uServiceName));
138
139 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
140
141 /* prepare a services key */
142 ServiceKeyStr = ExAllocatePool(PagedPool, sizeof(SERVICES_KEY) + sizeof(WCHAR) + uServiceName->Length);
143 if(!ServiceKeyStr)
144 {
145 NDIS_DbgPrint(MIN_TRACE, ("Insufficient Resources.\n"));
146 return;
147 }
148
149 wcscpy(ServiceKeyStr, SERVICES_KEY);
150 wcscat(ServiceKeyStr, L"\\");
151 wcsncat(ServiceKeyStr, uServiceName->Buffer, uServiceName->Length/sizeof(WCHAR));
152 ServiceKeyStr[wcslen(SERVICES_KEY)+1+uServiceName->Length/sizeof(WCHAR)] = 0;
153
154 RtlInitUnicodeString(&ServiceKey, ServiceKeyStr);
155
156 if(!wcsncmp(uBusName->Buffer, L"PCI", uBusName->Length))
157 {
158 /*
159 * first see if a card with the requested id exists.
160 * PCI IDs are formatted VEN_ABCD&DEV_ABCD[&...]
161 */
162
163 if(wcsncmp(uDeviceId->Buffer, L"VEN_", 4))
164 {
165 NDIS_DbgPrint(MIN_TRACE, ("Bogus uDeviceId parsing VEN\n"));
166 ExFreePool(ServiceKeyStr);
167 return;
168 }
169
170 Temp.Buffer = &(uDeviceId->Buffer[4]); /* offset of vendor id */
171 Temp.Length = Temp.MaximumLength = 4 * sizeof(WCHAR); /* 4-digit id */
172
173 NtStatus = RtlUnicodeStringToInteger(&Temp, 16, &VendorId);
174 if(!NT_SUCCESS(NtStatus))
175 {
176 NDIS_DbgPrint(MIN_TRACE, ("RtlUnicodeStringToInteger returned 0x%x\n", NtStatus));
177 ExFreePool(ServiceKeyStr);
178 return;
179 }
180
181 if(wcsncmp(&(uDeviceId->Buffer[9]), L"DEV_", 4))
182 {
183 NDIS_DbgPrint(MIN_TRACE, ("Bogus uDeviceId parsing DEV\n"));
184 ExFreePool(ServiceKeyStr);
185 return;
186 }
187
188 Temp.Buffer = &(uDeviceId->Buffer[13]); /* offset of device id */
189 Temp.Length = 4 * sizeof(WCHAR); /* 4-dight id */
190
191 NtStatus = RtlUnicodeStringToInteger(&Temp, 16, &DeviceId);
192 if(!NT_SUCCESS(NtStatus))
193 {
194 NDIS_DbgPrint(MIN_TRACE, ("RtlUnicodeStringToInteger returned 0x%x\n", NtStatus));
195 ExFreePool(ServiceKeyStr);
196 return;
197 }
198
199 if(!NdisFindDevicePci(VendorId, DeviceId, &BusNumber, &SlotNumber))
200 {
201 NDIS_DbgPrint(MIN_TRACE, ("Didn't find a configured card 0x%x 0x%x\n", VendorId, DeviceId));
202 ExFreePool(ServiceKeyStr);
203 return;
204 }
205
206 NDIS_DbgPrint(MAX_TRACE, ("Found a card 0x%x 0x%x at bus 0x%x slot 0x%x\n", VendorId, DeviceId, BusNumber, SlotNumber));
207
208 OrphanAdapter = ExAllocatePool(PagedPool, sizeof(ORPHAN_ADAPTER));
209 if(!OrphanAdapter)
210 {
211 NDIS_DbgPrint(MIN_TRACE, ("Insufficient Resources.\n"));
212 ExFreePool(ServiceKeyStr);
213 return;
214 }
215
216 OrphanAdapter->RegistryPath.Buffer = ExAllocatePool(PagedPool, Temp.MaximumLength);
217 if(!OrphanAdapter->RegistryPath.Buffer)
218 {
219 NDIS_DbgPrint(MIN_TRACE, ("Insufficient Resources.\n"));
220 ExFreePool(ServiceKeyStr);
221 return;
222 }
223
224 OrphanAdapter->RegistryPath.Length = Temp.Length;
225 OrphanAdapter->RegistryPath.MaximumLength = Temp.MaximumLength;
226 memcpy(OrphanAdapter->RegistryPath.Buffer, Temp.Buffer, Temp.Length);
227
228 OrphanAdapter->BusType = PCIBus;
229 OrphanAdapter->BusNumber = BusNumber;
230 OrphanAdapter->SlotNumber = SlotNumber;
231
232 ExInterlockedInsertTailList(&OrphanAdapterListHead, &OrphanAdapter->ListEntry, &OrphanAdapterListLock);
233 }
234
235 /*
236 * found a card; start its driver. this should be done from a
237 * system thread, after NDIS.SYS's DriverEntry returns, but I
238 * really don't know how to block on DriverEntry returning, so
239 * what the hell.
240 */
241
242 NDIS_DbgPrint(MID_TRACE, ("Loading driver %wZ\n", &ServiceKey));
243 ZwLoadDriver(&ServiceKey);
244
245 ExFreePool(ServiceKeyStr);
246 }
247
248 \f
249 VOID NdisStartDevices()
250 /*
251 * FUNCTION: Find and start all NDIS Net class devices
252 * NOTES:
253 * - Not sure if this handles multiple instances of the same
254 * device or driver correctly yet
255 */
256 {
257 HANDLE EnumHandle;
258 OBJECT_ATTRIBUTES ObjectAttributes;
259 UNICODE_STRING KeyName;
260 NTSTATUS NtStatus;
261 ULONG EnumIndex = 0;
262 ULONG ResultLength;
263 PKEY_BASIC_INFORMATION KeyInformation;
264 ULONG KeyInformationLength;
265
266 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
267
268 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
269
270 RtlInitUnicodeString(&KeyName, ENUM_KEY);
271 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, 0);
272 NtStatus = ZwOpenKey(&EnumHandle, KEY_ALL_ACCESS, &ObjectAttributes);
273 if(!NT_SUCCESS(NtStatus))
274 {
275 NDIS_DbgPrint(MIN_TRACE, ("Unable to open the Enum key\n"));
276 return;
277 }
278
279 NDIS_DbgPrint(MAX_TRACE, ("Opened the enum key\n"));
280
281 KeyInformation = ExAllocatePool(PagedPool, KEY_INFORMATION_SIZE); // should be enough for most key names?
282 if(!KeyInformation)
283 {
284 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
285 return;
286 }
287
288 KeyInformationLength = KEY_INFORMATION_SIZE;
289
290 while(NT_SUCCESS(ZwEnumerateKey(EnumHandle, EnumIndex,
291 KeyBasicInformation, KeyInformation, KeyInformationLength, &ResultLength)))
292 {
293 /* iterate through each enumerator (PCI, Root, ISAPNP, etc) */
294
295 HANDLE EnumeratorHandle;
296 WCHAR *EnumeratorStr;
297 UINT EnumeratorIndex = 0;
298
299 NDIS_DbgPrint(MAX_TRACE, ("Enum iteration 0x%x\n", EnumIndex));
300
301 EnumIndex++;
302
303 EnumeratorStr = ExAllocatePool(PagedPool, sizeof(WCHAR) + KeyInformation->NameLength);
304 if(!EnumeratorStr)
305 {
306 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
307 return;
308 }
309
310 wcsncpy(EnumeratorStr, KeyInformation->Name, KeyInformation->NameLength/sizeof(WCHAR));
311 EnumeratorStr[KeyInformation->NameLength/sizeof(WCHAR)] = 0;
312
313 RtlInitUnicodeString(&KeyName, EnumeratorStr);
314 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, EnumHandle, 0);
315 if(!NT_SUCCESS(ZwOpenKey(&EnumeratorHandle, KEY_ALL_ACCESS, &ObjectAttributes)))
316 {
317 NDIS_DbgPrint(MIN_TRACE, ("Failed to open key %wZ\n", &KeyName));
318 return;
319 }
320
321 while(NT_SUCCESS(ZwEnumerateKey(EnumeratorHandle, EnumeratorIndex, KeyBasicInformation,
322 KeyInformation, KeyInformationLength, &ResultLength)))
323 {
324 /* iterate through each device id */
325
326 HANDLE DeviceHandle;
327 WCHAR *DeviceStr;
328 UINT DeviceIndex = 0;
329 UNICODE_STRING BusName;
330
331 BusName.Buffer = KeyName.Buffer;
332 BusName.Length = KeyName.Length;
333 BusName.MaximumLength = KeyName.MaximumLength;
334
335 EnumeratorIndex++;
336
337 DeviceStr = ExAllocatePool(PagedPool, KeyInformation->NameLength + sizeof(WCHAR));
338 if(!DeviceStr)
339 {
340 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
341 return;
342 }
343
344 wcsncpy(DeviceStr, KeyInformation->Name, KeyInformation->NameLength/sizeof(WCHAR));
345 DeviceStr[KeyInformation->NameLength/sizeof(WCHAR)] = 0;
346
347 RtlInitUnicodeString(&KeyName, DeviceStr);
348 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, EnumeratorHandle, 0);
349 if(!NT_SUCCESS(ZwOpenKey(&DeviceHandle, KEY_ALL_ACCESS, &ObjectAttributes)))
350 {
351 NDIS_DbgPrint(MIN_TRACE, ("Failed to open key %wZ\n", &KeyName));
352 return;
353 }
354
355 while(NT_SUCCESS(ZwEnumerateKey(DeviceHandle, DeviceIndex, KeyBasicInformation,
356 KeyInformation, KeyInformationLength, &ResultLength)))
357 {
358 /* iterate through each instance id, starting drivers in the process */
359 HANDLE InstanceHandle;
360 WCHAR *InstanceStr;
361 UNICODE_STRING ValueName;
362 UNICODE_STRING ServiceName;
363 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
364 ULONG KeyValueInformationLength;
365 UNICODE_STRING DeviceId;
366
367 DeviceId.Buffer = KeyName.Buffer;
368 DeviceId.Length = KeyName.Length;
369 DeviceId.MaximumLength = KeyName.MaximumLength;
370
371 DeviceIndex++;
372
373 InstanceStr = ExAllocatePool(PagedPool, KeyInformation->NameLength + sizeof(WCHAR));
374 if(!InstanceStr)
375 {
376 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
377 return;
378 }
379
380 wcsncpy(InstanceStr, KeyInformation->Name, KeyInformation->NameLength/sizeof(WCHAR));
381 InstanceStr[KeyInformation->NameLength/sizeof(WCHAR)] = 0;
382
383 NDIS_DbgPrint(MAX_TRACE, ("NameLength = 0x%x and InstanceStr: %ws\n", KeyInformation->NameLength, InstanceStr));
384
385 RtlInitUnicodeString(&KeyName, InstanceStr);
386 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, DeviceHandle, 0);
387 if(!NT_SUCCESS(ZwOpenKey(&InstanceHandle, KEY_ALL_ACCESS, &ObjectAttributes)))
388 {
389 NDIS_DbgPrint(MIN_TRACE, ("Failed to open key %wZ\n", &KeyName));
390 return;
391 }
392
393 /* read class, looking for net guid */
394 RtlInitUnicodeString(&ValueName, L"ClassGUID");
395
396 NDIS_DbgPrint(MAX_TRACE, ("About to ask for 0x%x bytes\n", VALUE_INFORMATION_SIZE));
397
398 KeyValueInformation = ExAllocatePool(PagedPool, VALUE_INFORMATION_SIZE);
399 if(!KeyValueInformation)
400 {
401 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
402 return;
403 }
404
405 KeyValueInformationLength = VALUE_INFORMATION_SIZE;
406
407 NtStatus = ZwQueryValueKey(InstanceHandle, &ValueName, KeyValuePartialInformation,
408 KeyValueInformation, KeyValueInformationLength, &ResultLength);
409 if(!NT_SUCCESS(NtStatus))
410 {
411 /* this isn't fatal, it just means that this device isn't ours */
412 NDIS_DbgPrint(MID_TRACE, ("Failed to query value %wZ from key %wZ\n", &ValueName, &KeyName));
413 continue;
414 }
415
416 if(!wcsncmp(NET_GUID, (PWCHAR)KeyValueInformation->Data, KeyValueInformation->DataLength/sizeof(WCHAR)))
417 {
418 RtlInitUnicodeString(&ValueName, L"Service");
419
420 NtStatus = ZwQueryValueKey(InstanceHandle, &ValueName, KeyValuePartialInformation,
421 KeyValueInformation, KeyValueInformationLength, &ResultLength);
422 if(!NT_SUCCESS(NtStatus))
423 {
424 /* non-fatal also */
425 NDIS_DbgPrint(MID_TRACE, ("Failed to query value %wZ from key %wZ\n", &ValueName, &KeyName));
426 continue;
427 }
428
429 /* this is a net driver; start it */
430 ServiceName.Length = ServiceName.MaximumLength = KeyValueInformation->DataLength;
431 ServiceName.Buffer = (PWCHAR)KeyValueInformation->Data;
432 NdisStartDriver(&BusName, &DeviceId, &ServiceName);
433 }
434 else
435 NDIS_DbgPrint(MAX_TRACE, ("...this device is not ours\n"));
436
437 ExFreePool(KeyValueInformation);
438 ExFreePool(InstanceStr);
439 ZwClose(InstanceHandle);
440 }
441
442 ExFreePool(DeviceStr);
443 ZwClose(DeviceHandle);
444 }
445
446 ExFreePool(EnumeratorStr);
447 ZwClose(EnumeratorHandle);
448 }
449
450 ZwClose(EnumHandle);
451 ExFreePool(KeyInformation);
452 }
453