update for HEAD-2003091401
[reactos.git] / 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