xref: /reactos/drivers/network/ndis/ndis/config.c (revision 2196a06f)
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 07-28-2003 Created
9  * NOTES:
10  *     - Resource tracking has to be implemented here because of the design of the NDIS API.
11  *       Whenever a read operation is performed, the NDIS library allocates space and returns
12  *       it.  A linked list is kept associated with every handle of the memory allocated to
13  *       it.  When the handle is closed, the resources are systematically released.
14  *     - The NDIS_HANDLE Configuration context is no longer a registry handle.  An opaque struct
15  *       had to be created to allow for resource tracking.  This means that Miniports cannot just
16  *       pass this NDIS_HANDLE to things like ZwQueryValueKey().  I don't thknk they do (they
17  *       certainly should not), but it should be kept in mind.
18  *         UPDATE:  I just found this in the NTDDK:
19  *         NdisOpenProtocolConfiguration returns a handle for the
20  *         HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NICDriverInstance\Parameters\ProtocolName
21  *         registry key.  XXX This is a problem.  Following that, the DDK instructs programmers
22  *         to use NdisReadConfiguration and NdisWriteConfiguration.  No telling what the world's idiots
23  *         have done with this.
24  *     - I have tried to stick to the DDK's definition of what return values are possible, which
25  *       has resulted in stupid return values in some cases.  I do use STATUS_RESOURCES in a few
26  *       places that the DDK doesn't explicitly mention it, though.
27  *     - There's a general reliance on the fact that UNICODE_STRING.Length doesn't include a trailing
28  *       0, which it shouldn't
29  *     - I added support for NdisParameterBinary.  It's at the end of the struct.  I wonder if
30  *       it'll break things.
31  *     - All the routines in this file are PASSIVE_LEVEL only, and all memory is PagedPool
32  */
33 
34 #include "ndissys.h"
35 
36 #include <ntifs.h>
37 
38 #define PARAMETERS_KEY L"Parameters"     /* The parameters subkey under the device-specific key */
39 
40 /*
41  * @implemented
42  */
43 VOID
44 EXPORT
45 NdisWriteConfiguration(
46     OUT PNDIS_STATUS                    Status,
47     IN  NDIS_HANDLE                     ConfigurationHandle,
48     IN  PNDIS_STRING                    Keyword,
49     IN  PNDIS_CONFIGURATION_PARAMETER   ParameterValue)
50 /*
51  * FUNCTION: Writes a configuration value to the registry
52  * ARGUMENTS:
53  *     Status: Pointer to a caller-supplied NDIS_STATUS where we return status
54  *     ConfigurationHandle: The Configuration Handle passed back from the call to one of the Open functions
55  *     Keyword: The registry value name to write
56  *     ParameterValue: The value data to write
57  * RETURNS:
58  *     NDIS_STATUS_SUCCESS - the operation completed successfully
59  *     NDIS_STATUS_NOT_SUPPORTED - The parameter type is not supported
60  *     NDIS_STATUS_RESOURCES - out of memory, etc.
61  *     NDIS_STATUS_FAILURE - any other failure
62  * NOTES:
63  *    There's a cryptic comment in the ddk implying that this function allocates and keeps memory.
64  *    I don't know why tho so i free everything before return.  comments welcome.
65  */
66 {
67     ULONG ParameterType;
68     ULONG DataSize;
69     PVOID Data;
70     WCHAR Buff[11];
71 
72     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
73 
74     NDIS_DbgPrint(MID_TRACE, ("Parameter type: %d\n", ParameterValue->ParameterType));
75 
76     /* reset parameter type to standard reg types */
77     switch(ParameterValue->ParameterType)
78     {
79         case NdisParameterHexInteger:
80         case NdisParameterInteger:
81              {
82                  UNICODE_STRING Str;
83 
84                  Str.Buffer = (PWSTR) &Buff;
85                  Str.MaximumLength = (USHORT)sizeof(Buff);
86                  Str.Length = 0;
87 
88                  ParameterType = REG_SZ;
89                  if (!NT_SUCCESS(RtlIntegerToUnicodeString(
90                       ParameterValue->ParameterData.IntegerData,
91                       (ParameterValue->ParameterType == NdisParameterInteger) ? 10 : 16, &Str)))
92                  {
93                       NDIS_DbgPrint(MIN_TRACE, ("RtlIntegerToUnicodeString failed (%x)\n", *Status));
94                       *Status = NDIS_STATUS_FAILURE;
95                       return;
96                  }
97                  Data = Str.Buffer;
98                  DataSize = Str.Length;
99              }
100              break;
101         case NdisParameterString:
102         case NdisParameterMultiString:
103             ParameterType = (ParameterValue->ParameterType == NdisParameterString) ? REG_SZ : REG_MULTI_SZ;
104             Data = ParameterValue->ParameterData.StringData.Buffer;
105             DataSize = ParameterValue->ParameterData.StringData.Length;
106             break;
107 
108         /* New (undocumented) addition to 2k ddk */
109         case NdisParameterBinary:
110             ParameterType = REG_BINARY;
111             Data = ParameterValue->ParameterData.BinaryData.Buffer;
112             DataSize = ParameterValue->ParameterData.BinaryData.Length;
113             break;
114 
115         default:
116             *Status = NDIS_STATUS_NOT_SUPPORTED;
117             return;
118     }
119 
120     *Status = ZwSetValueKey(((PMINIPORT_CONFIGURATION_CONTEXT)ConfigurationHandle)->Handle,
121             Keyword, 0, ParameterType, Data, DataSize);
122 
123     if(*Status != STATUS_SUCCESS) {
124         NDIS_DbgPrint(MIN_TRACE, ("ZwSetValueKey failed (%x)\n", *Status));
125         *Status = NDIS_STATUS_FAILURE;
126     } else
127         *Status = NDIS_STATUS_SUCCESS;
128 }
129 
130 
131 /*
132  * @implemented
133  */
134 VOID
135 EXPORT
136 NdisCloseConfiguration(
137     IN  NDIS_HANDLE ConfigurationHandle)
138 /*
139  * FUNCTION: Closes handles and releases per-handle resources
140  * ARGUMENTS:
141  *     ConfigurationHandle - pointer to the context with the resources to free
142  */
143 {
144     PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext = (PMINIPORT_CONFIGURATION_CONTEXT)ConfigurationHandle;
145     PMINIPORT_RESOURCE Resource;
146     PNDIS_CONFIGURATION_PARAMETER ParameterValue;
147     PLIST_ENTRY CurrentEntry;
148 
149     while((CurrentEntry = ExInterlockedRemoveHeadList(&ConfigurationContext->ResourceListHead,
150                                                       &ConfigurationContext->ResourceLock)) != NULL)
151     {
152         Resource = CONTAINING_RECORD(CurrentEntry, MINIPORT_RESOURCE, ListEntry);
153         switch(Resource->ResourceType)
154         {
155           case MINIPORT_RESOURCE_TYPE_REGISTRY_DATA:
156             ParameterValue = Resource->Resource;
157 
158             switch (ParameterValue->ParameterType)
159             {
160                case NdisParameterBinary:
161                  ExFreePool(ParameterValue->ParameterData.BinaryData.Buffer);
162                  break;
163 
164                case NdisParameterString:
165                case NdisParameterMultiString:
166                  ExFreePool(ParameterValue->ParameterData.StringData.Buffer);
167                  break;
168 
169                default:
170                  break;
171             }
172 
173           /* Fall through to free NDIS_CONFIGURATION_PARAMETER struct */
174 
175           case MINIPORT_RESOURCE_TYPE_MEMORY:
176             NDIS_DbgPrint(MAX_TRACE,("freeing 0x%x\n", Resource->Resource));
177             ExFreePool(Resource->Resource);
178             break;
179 
180           default:
181             NDIS_DbgPrint(MIN_TRACE,("Unknown resource type: %d\n", Resource->ResourceType));
182             break;
183         }
184 
185         ExFreePool(Resource);
186     }
187 
188     ZwClose(ConfigurationContext->Handle);
189 }
190 
191 
192 /*
193  * @implemented
194  */
195 VOID
196 EXPORT
197 NdisOpenConfiguration(
198     OUT PNDIS_STATUS    Status,
199     OUT PNDIS_HANDLE    ConfigurationHandle,
200     IN  NDIS_HANDLE     WrapperConfigurationContext)
201 /*
202  * FUNCTION: Opens the configuration key and sets up resource tracking for the returned handle
203  * ARGUMENTS:
204  *     Status: Pointer to a caller-supplied NDIS_STATUS that is filled in with a return value
205  *     ConfigurationHandle: Pointer to an opaque configuration handle returned on success
206  *     WrapperConfigurationContext: handle originally passed back from NdisInitializeWrapper
207  * RETURNS:
208  *     NDIS_STATUS_SUCCESS: the operation completed successfully
209  *     NDIS_STATUS_FAILURE: the operation failed
210  * NOTES:
211  *     I think this is the parameters key; please verify.
212  */
213 {
214     HANDLE KeyHandle;
215     PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext;
216     PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)WrapperConfigurationContext;
217     HANDLE RootKeyHandle = WrapperContext->RegistryHandle;
218     OBJECT_ATTRIBUTES ObjectAttributes;
219     UNICODE_STRING NoName = RTL_CONSTANT_STRING(L"");
220 
221     NDIS_DbgPrint(MAX_TRACE, ("Called\n"));
222 
223     *ConfigurationHandle = NULL;
224 
225     InitializeObjectAttributes(&ObjectAttributes,
226                                &NoName,
227                                OBJ_KERNEL_HANDLE,
228                                RootKeyHandle,
229                                NULL);
230     *Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
231     if(!NT_SUCCESS(*Status))
232     {
233         NDIS_DbgPrint(MIN_TRACE, ("Failed to open registry configuration for this miniport\n"));
234         *Status = NDIS_STATUS_FAILURE;
235         return;
236     }
237 
238     ConfigurationContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_CONFIGURATION_CONTEXT));
239     if(!ConfigurationContext)
240     {
241         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
242         ZwClose(KeyHandle);
243         *Status = NDIS_STATUS_RESOURCES;
244         return;
245     }
246 
247     KeInitializeSpinLock(&ConfigurationContext->ResourceLock);
248     InitializeListHead(&ConfigurationContext->ResourceListHead);
249 
250     ConfigurationContext->Handle = KeyHandle;
251 
252     *ConfigurationHandle = (NDIS_HANDLE)ConfigurationContext;
253     *Status = NDIS_STATUS_SUCCESS;
254 
255     NDIS_DbgPrint(MAX_TRACE,("returning success\n"));
256 }
257 
258 
259 /*
260  * @implemented
261  */
262 VOID
263 EXPORT
264 NdisOpenProtocolConfiguration(
265     OUT PNDIS_STATUS    Status,
266     OUT PNDIS_HANDLE    ConfigurationHandle,
267     IN  PNDIS_STRING    ProtocolSection)
268 /*
269  * FUNCTION: Open the configuration key and set up resource tracking for the protocol
270  * ARGUMENTS:
271  *     Status: caller-allocated buffer where status is returned
272  *     ConfigurationHandle: spot to return the opaque configuration context
273  *     ProtocolSection: configuration string originally passed in to ProtocolBindAdapter
274  * RETURNS:
275  *     NDIS_STATUS_SUCCESS: the operation was a success
276  *     NDIS_STATUS_FAILURE: the operation was not a success
277  * NOTES:
278  *     I think this is the per-device (adapter) parameters\{ProtocolName} key; please verify.
279  */
280 {
281     OBJECT_ATTRIBUTES KeyAttributes;
282     UNICODE_STRING KeyNameU;
283     HANDLE KeyHandle;
284     PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext;
285 
286     KeyNameU.Length = 0;
287     KeyNameU.MaximumLength = ProtocolSection->Length + sizeof(PARAMETERS_KEY) + sizeof(UNICODE_NULL);
288     KeyNameU.Buffer = ExAllocatePool(PagedPool, KeyNameU.MaximumLength);
289     if(!KeyNameU.Buffer)
290     {
291         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
292         *ConfigurationHandle = NULL;
293         *Status = NDIS_STATUS_FAILURE;
294         return;
295     }
296 
297     RtlCopyUnicodeString(&KeyNameU, ProtocolSection);
298     RtlAppendUnicodeToString(&KeyNameU, PARAMETERS_KEY);
299     InitializeObjectAttributes(&KeyAttributes, &KeyNameU, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
300 
301     *Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &KeyAttributes);
302 
303     ExFreePool(KeyNameU.Buffer);
304 
305     if(*Status != NDIS_STATUS_SUCCESS)
306     {
307         NDIS_DbgPrint(MIN_TRACE, ("ZwOpenKey failed (%x)\n", *Status));
308         *ConfigurationHandle = NULL;
309         *Status = NDIS_STATUS_FAILURE;
310         return;
311     }
312 
313     ConfigurationContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_CONFIGURATION_CONTEXT));
314     if(!ConfigurationContext)
315     {
316         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
317         ZwClose(KeyHandle);
318         *ConfigurationHandle = NULL;
319         *Status = NDIS_STATUS_FAILURE;
320         return;
321     }
322 
323     KeInitializeSpinLock(&ConfigurationContext->ResourceLock);
324     InitializeListHead(&ConfigurationContext->ResourceListHead);
325 
326     ConfigurationContext->Handle = KeyHandle;
327 
328     *ConfigurationHandle = (NDIS_HANDLE)ConfigurationContext;
329     *Status = NDIS_STATUS_SUCCESS;
330 }
331 
332 UCHAR UnicodeToHexByte(WCHAR chr)
333 /*
334  * FUNCTION: Converts a unicode hex character to its numerical value
335  * ARGUMENTS:
336  *     chr: Unicode character to convert
337  * RETURNS:
338  *     The numerical value of chr
339  */
340 {
341     switch(chr)
342     {
343         case L'0': return 0;
344         case L'1': return 1;
345         case L'2': return 2;
346         case L'3': return 3;
347         case L'4': return 4;
348         case L'5': return 5;
349         case L'6': return 6;
350         case L'7': return 7;
351         case L'8': return 8;
352         case L'9': return 9;
353         case L'A':
354         case L'a':
355             return 10;
356         case L'B':
357         case L'b':
358             return 11;
359         case L'C':
360         case L'c':
361             return 12;
362         case L'D':
363         case L'd':
364             return 13;
365         case L'E':
366         case L'e':
367             return 14;
368         case L'F':
369         case L'f':
370             return 15;
371     }
372     return 0xFF;
373 }
374 
375 BOOLEAN
376 IsValidNumericString(PNDIS_STRING String, ULONG Base)
377 /*
378  * FUNCTION: Determines if a string is a valid number
379  * ARGUMENTS:
380  *     String: Unicode string to evaluate
381  * RETURNS:
382  *     TRUE if it is valid, FALSE if not
383  */
384 {
385     ULONG i;
386 
387     /* I don't think this will ever happen, but we warn it if it does */
388     if (String->Length == 0)
389     {
390         NDIS_DbgPrint(MIN_TRACE, ("Got an empty string; not sure what to do here\n"));
391         return FALSE;
392     }
393 
394     for (i = 0; i < String->Length / sizeof(WCHAR); i++)
395     {
396         /* Skip any NULL characters we find */
397         if (String->Buffer[i] == UNICODE_NULL)
398             continue;
399 
400         /* Make sure the character is valid for a numeric string of this base */
401         if (UnicodeToHexByte(String->Buffer[i]) >= Base)
402             return FALSE;
403     }
404 
405     /* It's valid */
406     return TRUE;
407 }
408 
409 /*
410  * @implemented
411  */
412 VOID
413 EXPORT
414 NdisReadConfiguration(
415     OUT PNDIS_STATUS                    Status,
416     OUT PNDIS_CONFIGURATION_PARAMETER   * ParameterValue,
417     IN  NDIS_HANDLE                     ConfigurationHandle,
418     IN  PNDIS_STRING                    Keyword,
419     IN  NDIS_PARAMETER_TYPE             ParameterType)
420 /*
421  * FUNCTION: Read a configuration value from the registry, tracking its resources
422  * ARGUMENTS:
423  *     Status: points to a place to write status into
424  *     ParameterValue: Pointer to receive a newly-allocated parameter structure
425  *     ConfigurationHandle: handle originally returned by an open function
426  *     Keyword: Value name to read, or one of the following constants:
427  *       Environment - returns NdisEnvironmentWindowsNt
428  *       ProcessorType - returns NdisProcessorX86 until more architectures are added
429  *       NdisVersion - returns NDIS_VERSION
430  *     ParameterType: the type of the value to be queried
431  * RETURNS:
432  *     - A status in Status
433  *     - A parameter value in ParameterValue
434  */
435 {
436     KEY_VALUE_PARTIAL_INFORMATION *KeyInformation;
437     ULONG KeyDataLength;
438     PMINIPORT_RESOURCE MiniportResource;
439     PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext = (PMINIPORT_CONFIGURATION_CONTEXT)ConfigurationHandle;
440     PVOID Buffer;
441 
442     //*ParameterValue = NULL;
443     *Status = NDIS_STATUS_FAILURE;
444 
445     NDIS_DbgPrint(MAX_TRACE,("requested read of %wZ\n", Keyword));
446     NDIS_DbgPrint(MID_TRACE,("requested parameter type: %d\n", ParameterType));
447 
448     if (ConfigurationContext == NULL)
449     {
450        NDIS_DbgPrint(MIN_TRACE,("invalid parameter ConfigurationContext (0x%x)\n",ConfigurationContext));
451        return;
452     }
453 
454     if(!wcsncmp(Keyword->Buffer, L"Environment", Keyword->Length/sizeof(WCHAR)) &&
455         wcslen(L"Environment") == Keyword->Length/sizeof(WCHAR))
456     {
457         *ParameterValue = ExAllocatePool(PagedPool, sizeof(NDIS_CONFIGURATION_PARAMETER));
458         if(!*ParameterValue)
459         {
460             NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
461             *Status = NDIS_STATUS_RESOURCES;
462             return;
463         }
464 
465         MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
466         if(!MiniportResource)
467         {
468             NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
469             ExFreePool(*ParameterValue);
470             *ParameterValue = NULL;
471             *Status = NDIS_STATUS_RESOURCES;
472             return;
473         }
474 
475         MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_REGISTRY_DATA;
476         MiniportResource->Resource = *ParameterValue;
477 
478         NDIS_DbgPrint(MID_TRACE,("inserting 0x%x into the resource list\n",
479             MiniportResource->Resource));
480 
481         ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead,
482             &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
483 
484         (*ParameterValue)->ParameterType = NdisParameterInteger;
485         (*ParameterValue)->ParameterData.IntegerData = NdisEnvironmentWindowsNt;
486         *Status = NDIS_STATUS_SUCCESS;
487 
488         return;
489     }
490 
491     if(!wcsncmp(Keyword->Buffer, L"ProcessorType", Keyword->Length/sizeof(WCHAR)) &&
492         wcslen(L"ProcessorType") == Keyword->Length/sizeof(WCHAR))
493     {
494         *ParameterValue = ExAllocatePool(PagedPool, sizeof(NDIS_CONFIGURATION_PARAMETER));
495         if(!*ParameterValue)
496         {
497             NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
498             *Status = NDIS_STATUS_RESOURCES;
499             return;
500         }
501 
502         MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
503         if(!MiniportResource)
504         {
505             NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
506             ExFreePool(*ParameterValue);
507             *ParameterValue = NULL;
508             *Status = NDIS_STATUS_RESOURCES;
509             return;
510         }
511 
512         MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_REGISTRY_DATA;
513         MiniportResource->Resource = *ParameterValue;
514         NDIS_DbgPrint(MID_TRACE,("inserting 0x%x into the resource list\n", MiniportResource->Resource));
515         ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead,
516             &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
517 
518         (*ParameterValue)->ParameterType = NdisParameterInteger;
519         (*ParameterValue)->ParameterData.IntegerData = NdisProcessorX86;    /* XXX non-portable */
520         *Status = NDIS_STATUS_SUCCESS;
521 
522         return;
523     }
524 
525     if(!wcsncmp(Keyword->Buffer, L"NdisVersion", Keyword->Length/sizeof(WCHAR)) &&
526         wcslen(L"NdisVersion") == Keyword->Length/sizeof(WCHAR))
527     {
528         *ParameterValue = ExAllocatePool(PagedPool, sizeof(NDIS_CONFIGURATION_PARAMETER));
529         if(!*ParameterValue)
530         {
531             NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
532             *Status = NDIS_STATUS_RESOURCES;
533             return;
534         }
535 
536         MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
537         if(!MiniportResource)
538         {
539             NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
540             ExFreePool(*ParameterValue);
541             *ParameterValue = NULL;
542             *Status = NDIS_STATUS_RESOURCES;
543             return;
544         }
545 
546         MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_REGISTRY_DATA;
547         MiniportResource->Resource = *ParameterValue;
548         NDIS_DbgPrint(MID_TRACE,("inserting 0x%x into the resource list\n", MiniportResource->Resource));
549         ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead,
550             &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
551 
552         (*ParameterValue)->ParameterType = NdisParameterInteger;
553         (*ParameterValue)->ParameterData.IntegerData = NDIS_VERSION;
554         *Status = NDIS_STATUS_SUCCESS;
555 
556         NDIS_DbgPrint(MAX_TRACE,("ParameterType = 0x%x, ParameterValue = 0x%x\n",
557             (*ParameterValue)->ParameterType, (*ParameterValue)->ParameterData.IntegerData));
558         return;
559     }
560 
561     /* figure out how much buffer i should allocate */
562     *Status = ZwQueryValueKey(ConfigurationContext->Handle, Keyword, KeyValuePartialInformation, NULL, 0, &KeyDataLength);
563     if(*Status != STATUS_BUFFER_OVERFLOW && *Status != STATUS_BUFFER_TOO_SMALL && *Status != STATUS_SUCCESS)
564     {
565         NDIS_DbgPrint(MID_TRACE,("ZwQueryValueKey #1 failed for %wZ, status 0x%x\n", Keyword, *Status));
566         *Status = NDIS_STATUS_FAILURE;
567         return;
568     }
569 
570     /* allocate it */
571     KeyInformation = ExAllocatePool(PagedPool, KeyDataLength + sizeof(KEY_VALUE_PARTIAL_INFORMATION));
572     if(!KeyInformation)
573     {
574         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
575         *Status = NDIS_STATUS_RESOURCES;
576         return;
577     }
578 
579     /* grab the value */
580     *Status = ZwQueryValueKey(ConfigurationContext->Handle, Keyword, KeyValuePartialInformation,
581         KeyInformation, KeyDataLength + sizeof(KEY_VALUE_PARTIAL_INFORMATION), &KeyDataLength);
582     if(*Status != STATUS_SUCCESS)
583     {
584         ExFreePool(KeyInformation);
585         NDIS_DbgPrint(MIN_TRACE,("ZwQueryValueKey #2 failed for %wZ, status 0x%x\n", Keyword, *Status));
586         *Status = NDIS_STATUS_FAILURE;
587         return;
588     }
589 
590     MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
591     if(!MiniportResource)
592     {
593        NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
594        ExFreePool(KeyInformation);
595        *Status = NDIS_STATUS_RESOURCES;
596        return;
597     }
598 
599     *ParameterValue = ExAllocatePool(PagedPool, sizeof(NDIS_CONFIGURATION_PARAMETER));
600     if (!*ParameterValue)
601     {
602         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
603         ExFreePool(MiniportResource);
604         ExFreePool(KeyInformation);
605         *Status = NDIS_STATUS_RESOURCES;
606         return;
607     }
608 
609     RtlZeroMemory(*ParameterValue, sizeof(NDIS_CONFIGURATION_PARAMETER));
610 
611     if (KeyInformation->Type == REG_BINARY)
612     {
613         NDIS_DbgPrint(MAX_TRACE, ("NdisParameterBinary\n"));
614 
615         (*ParameterValue)->ParameterType = NdisParameterBinary;
616 
617         Buffer = ExAllocatePool(PagedPool, KeyInformation->DataLength);
618         if (!Buffer)
619         {
620             NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
621             ExFreePool(MiniportResource);
622             ExFreePool(KeyInformation);
623             *Status = NDIS_STATUS_RESOURCES;
624             return;
625         }
626 
627         RtlCopyMemory(Buffer, KeyInformation->Data, KeyInformation->DataLength);
628 
629         (*ParameterValue)->ParameterData.BinaryData.Buffer = Buffer;
630         (*ParameterValue)->ParameterData.BinaryData.Length = KeyInformation->DataLength;
631     }
632     else if (KeyInformation->Type == REG_MULTI_SZ)
633     {
634         NDIS_DbgPrint(MAX_TRACE, ("NdisParameterMultiString\n"));
635 
636         (*ParameterValue)->ParameterType = NdisParameterMultiString;
637 
638         Buffer = ExAllocatePool(PagedPool, KeyInformation->DataLength);
639         if (!Buffer)
640         {
641             NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
642             ExFreePool(MiniportResource);
643             ExFreePool(KeyInformation);
644             *Status = NDIS_STATUS_RESOURCES;
645             return;
646         }
647 
648         RtlCopyMemory(Buffer, KeyInformation->Data, KeyInformation->DataLength);
649 
650         (*ParameterValue)->ParameterData.StringData.Buffer = Buffer;
651         (*ParameterValue)->ParameterData.StringData.Length = KeyInformation->DataLength;
652     }
653     else if (KeyInformation->Type == REG_DWORD)
654     {
655         ASSERT(KeyInformation->DataLength == sizeof(ULONG));
656         NDIS_DbgPrint(MAX_TRACE, ("NdisParameterInteger\n"));
657         (*ParameterValue)->ParameterType = NdisParameterInteger;
658         (*ParameterValue)->ParameterData.IntegerData = * (ULONG *) &KeyInformation->Data[0];
659     }
660     else if (KeyInformation->Type == REG_SZ)
661     {
662          UNICODE_STRING str;
663          ULONG Base;
664 
665          if (ParameterType == NdisParameterInteger)
666              Base = 10;
667          else if (ParameterType == NdisParameterHexInteger)
668              Base = 16;
669          else
670              Base = 0;
671 
672          str.Length = str.MaximumLength = (USHORT)KeyInformation->DataLength;
673          str.Buffer = (PWCHAR)KeyInformation->Data;
674 
675          if (Base != 0 && IsValidNumericString(&str, Base))
676          {
677              *Status = RtlUnicodeStringToInteger(&str, Base, &(*ParameterValue)->ParameterData.IntegerData);
678               ASSERT(*Status == STATUS_SUCCESS);
679 
680              NDIS_DbgPrint(MAX_TRACE, ("NdisParameter(Hex)Integer\n"));
681 
682              /* MSDN documents that this is returned for all integers, regardless of the ParameterType passed in */
683              (*ParameterValue)->ParameterType = NdisParameterInteger;
684          }
685          else
686          {
687              NDIS_DbgPrint(MAX_TRACE, ("NdisParameterString\n"));
688 
689              (*ParameterValue)->ParameterType = NdisParameterString;
690 
691              Buffer = ExAllocatePool(PagedPool, KeyInformation->DataLength);
692              if (!Buffer)
693              {
694                  NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
695                  ExFreePool(MiniportResource);
696                  ExFreePool(KeyInformation);
697                  *Status = NDIS_STATUS_RESOURCES;
698                  return;
699              }
700 
701              RtlCopyMemory(Buffer, KeyInformation->Data, KeyInformation->DataLength);
702 
703              (*ParameterValue)->ParameterData.StringData.Buffer = Buffer;
704              (*ParameterValue)->ParameterData.StringData.Length = KeyInformation->DataLength;
705          }
706     }
707     else
708     {
709         NDIS_DbgPrint(MIN_TRACE, ("Invalid type for NdisReadConfiguration (%d)\n", KeyInformation->Type));
710         NDIS_DbgPrint(MIN_TRACE, ("Requested type: %d\n", ParameterType));
711         NDIS_DbgPrint(MIN_TRACE, ("Registry entry: %wZ\n", Keyword));
712         *Status = NDIS_STATUS_FAILURE;
713         ExFreePool(KeyInformation);
714         return;
715     }
716 
717     if (((*ParameterValue)->ParameterType != ParameterType) &&
718         !((ParameterType == NdisParameterHexInteger) && ((*ParameterValue)->ParameterType == NdisParameterInteger)))
719     {
720         NDIS_DbgPrint(MIN_TRACE, ("Parameter type mismatch! (Requested: %d | Received: %d)\n",
721                                   ParameterType, (*ParameterValue)->ParameterType));
722         NDIS_DbgPrint(MIN_TRACE, ("Registry entry: %wZ\n", Keyword));
723     }
724 
725     MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_REGISTRY_DATA;
726     MiniportResource->Resource = *ParameterValue;
727 
728     ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead, &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
729 
730     ExFreePool(KeyInformation);
731 
732     *Status = NDIS_STATUS_SUCCESS;
733 }
734 
735 /*
736  * @implemented
737  */
738 VOID
739 EXPORT
740 NdisReadNetworkAddress(
741     OUT PNDIS_STATUS    Status,
742     OUT PVOID           * NetworkAddress,
743     OUT PUINT           NetworkAddressLength,
744     IN  NDIS_HANDLE     ConfigurationHandle)
745 /*
746  * FUNCTION: Reads the network address from the registry
747  * ARGUMENTS:
748  *     Status - variable to receive status
749  *     NetworkAddress - pointer to a buffered network address array
750  *     NetworkAddressLength - length of the NetworkAddress array
751  *     ConfigurationHandle: handle passed back from one of the open routines
752  * RETURNS:
753  *     NDIS_STATUS_SUCCESS on success
754  *     NDIS_STATUS_FAILURE on failure
755  *     The network address is placed in the NetworkAddress buffer
756  */
757 {
758     PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext = (PMINIPORT_CONFIGURATION_CONTEXT)ConfigurationHandle;
759     PMINIPORT_RESOURCE MiniportResource = NULL;
760     PNDIS_CONFIGURATION_PARAMETER ParameterValue = NULL;
761     NDIS_STRING Keyword;
762     UINT *IntArray = 0;
763     UINT i,j = 0;
764     WCHAR Buff[11];
765     NDIS_STRING str;
766 
767     NdisInitUnicodeString(&Keyword, L"NetworkAddress");
768     NdisReadConfiguration(Status, &ParameterValue, ConfigurationHandle, &Keyword, NdisParameterString);
769     if(*Status != NDIS_STATUS_SUCCESS)
770     {
771         NDIS_DbgPrint(MID_TRACE, ("NdisReadConfiguration failed (%x)\n", *Status));
772         *Status = NDIS_STATUS_FAILURE;
773         return;
774     }
775 
776     if (ParameterValue->ParameterType == NdisParameterInteger)
777     {
778         NDIS_DbgPrint(MAX_TRACE, ("Read integer data %lx\n",
779                                   ParameterValue->ParameterData.IntegerData));
780 
781         str.Buffer = Buff;
782         str.MaximumLength = (USHORT)sizeof(Buff);
783         str.Length = 0;
784 
785         *Status = RtlIntegerToUnicodeString(ParameterValue->ParameterData.IntegerData,
786                                             10,
787                                             &str);
788 
789         if (*Status != NDIS_STATUS_SUCCESS)
790         {
791             NDIS_DbgPrint(MIN_TRACE, ("RtlIntegerToUnicodeString failed (%x)\n", *Status));
792             *Status = NDIS_STATUS_FAILURE;
793             return;
794         }
795 
796         NDIS_DbgPrint(MAX_TRACE, ("Converted integer data into %wZ\n", &str));
797     }
798     else
799     {
800         ASSERT(ParameterValue->ParameterType == NdisParameterString);
801         str = ParameterValue->ParameterData.StringData;
802     }
803 
804     while (j < str.Length && str.Buffer[j] != '\0') j++;
805 
806     *NetworkAddressLength = (j+1) >> 1;
807 
808     if ((*NetworkAddressLength) == 0)
809     {
810         NDIS_DbgPrint(MIN_TRACE,("Empty NetworkAddress registry entry.\n"));
811         *Status = NDIS_STATUS_FAILURE;
812         return;
813     }
814 
815     IntArray = ExAllocatePool(PagedPool, (*NetworkAddressLength)*sizeof(UINT));
816     if(!IntArray)
817     {
818         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
819         *Status = NDIS_STATUS_RESOURCES;
820         return;
821     }
822 
823     MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
824     if(!MiniportResource)
825     {
826         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
827         ExFreePool(IntArray);
828         *Status = NDIS_STATUS_RESOURCES;
829         return;
830     }
831 
832     MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_MEMORY;
833     MiniportResource->Resource = IntArray;
834     NDIS_DbgPrint(MID_TRACE,("inserting 0x%x into the resource list\n", MiniportResource->Resource));
835     ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead, &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
836 
837     /* convert from string to bytes */
838     for(i=0; i<(*NetworkAddressLength); i++)
839     {
840         IntArray[i] = (UnicodeToHexByte((str.Buffer)[2*i]) << 4) +
841                 UnicodeToHexByte((str.Buffer)[2*i+1]);
842     }
843 
844     *NetworkAddress = IntArray;
845 
846     *Status = NDIS_STATUS_SUCCESS;
847 }
848 
849 
850 /*
851  * @implemented
852  */
853 VOID
854 EXPORT
855 NdisOpenConfigurationKeyByIndex(
856     OUT PNDIS_STATUS    Status,
857     IN  NDIS_HANDLE     ConfigurationHandle,
858     IN  ULONG           Index,
859     OUT PNDIS_STRING    KeyName,
860     OUT PNDIS_HANDLE    KeyHandle)
861 /*
862  * FUNCTION: Opens a configuration subkey by index number
863  * ARGUMENTS:
864  *     Status: pointer to an NDIS_STATUS to receive status info
865  *     ConfigurationHandle: the handle passed back from a previous open function
866  *     Index: the zero-based index of the subkey to open
867  *     KeyName: the name of the key that was opened
868  *     KeyHandle: a handle to the key that was opened
869  * RETURNS:
870  *     NDIS_STATUS_SUCCESS on success
871  *     NDIS_STATUS_FAILURE on failure
872  *     KeyName holds the name of the opened key
873  *     KeyHandle holds a handle to the new key
874  */
875 {
876     KEY_BASIC_INFORMATION *KeyInformation;
877     ULONG KeyInformationLength;
878     OBJECT_ATTRIBUTES KeyAttributes;
879     NDIS_HANDLE RegKeyHandle;
880     PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext;
881 
882     *KeyHandle = NULL;
883 
884     *Status = ZwEnumerateKey(ConfigurationHandle, Index, KeyBasicInformation, NULL, 0, &KeyInformationLength);
885     if(*Status != STATUS_BUFFER_TOO_SMALL && *Status != STATUS_BUFFER_OVERFLOW && *Status != STATUS_SUCCESS)
886     {
887         NDIS_DbgPrint(MIN_TRACE, ("ZwEnumerateKey failed (%x)\n", *Status));
888         *Status = NDIS_STATUS_FAILURE;
889         return;
890     }
891 
892     KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength + sizeof(KEY_BASIC_INFORMATION));
893     if(!KeyInformation)
894     {
895         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
896         *Status = NDIS_STATUS_FAILURE;
897         return;
898     }
899 
900     *Status = ZwEnumerateKey(ConfigurationHandle, Index, KeyBasicInformation, KeyInformation,
901         KeyInformationLength + sizeof(KEY_BASIC_INFORMATION), &KeyInformationLength);
902 
903     if(*Status != STATUS_SUCCESS)
904     {
905         NDIS_DbgPrint(MIN_TRACE, ("ZwEnumerateKey failed (%x)\n", *Status));
906         ExFreePool(KeyInformation);
907         *Status = NDIS_STATUS_FAILURE;
908         return;
909     }
910 
911     /* should i fail instead if the passed-in string isn't long enough? */
912     wcsncpy(KeyName->Buffer, KeyInformation->Name, KeyName->MaximumLength/sizeof(WCHAR));
913     KeyName->Length = (USHORT)min(KeyInformation->NameLength, KeyName->MaximumLength);
914 
915     InitializeObjectAttributes(&KeyAttributes, KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, ConfigurationHandle, NULL);
916 
917     *Status = ZwOpenKey(&RegKeyHandle, KEY_ALL_ACCESS, &KeyAttributes);
918 
919     ExFreePool(KeyInformation);
920 
921     if(*Status != STATUS_SUCCESS)
922     {
923         NDIS_DbgPrint(MIN_TRACE, ("ZwOpenKey failed (%x)\n", *Status));
924         *Status = NDIS_STATUS_FAILURE;
925         return;
926     }
927 
928     ConfigurationContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_CONFIGURATION_CONTEXT));
929     if(!ConfigurationContext)
930     {
931         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
932         ZwClose(RegKeyHandle);
933         *Status = NDIS_STATUS_FAILURE;
934         return;
935     }
936 
937     KeInitializeSpinLock(&ConfigurationContext->ResourceLock);
938     InitializeListHead(&ConfigurationContext->ResourceListHead);
939 
940     ConfigurationContext->Handle = RegKeyHandle;
941 
942     *KeyHandle = (NDIS_HANDLE)ConfigurationContext;
943 
944     *Status = NDIS_STATUS_SUCCESS;
945 }
946 
947 
948 /*
949  * @implemented
950  */
951 VOID
952 EXPORT
953 NdisOpenConfigurationKeyByName(
954     OUT PNDIS_STATUS    Status,
955     IN  NDIS_HANDLE     ConfigurationHandle,
956     IN  PNDIS_STRING    KeyName,
957     OUT PNDIS_HANDLE    KeyHandle)
958 /*
959  * FUNCTION: Opens a configuration subkey by name
960  * ARGUMENTS:
961  *     Status: points to an NDIS_STATUS where status is returned
962  *     ConfigurationHandle: handle returned by a previous open call
963  *     KeyName: the name of the key to open
964  *     KeyHandle: a handle to the opened key
965  * RETURNS:
966  *     NDIS_STATUS_SUCCESS on success
967  *     NDIS_STATUS_FAILURE on failure
968  *     KeyHandle holds a handle to the newly-opened key
969  * NOTES:
970  */
971 {
972     PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext;
973     OBJECT_ATTRIBUTES KeyAttributes;
974     NDIS_HANDLE RegKeyHandle;
975 
976     *KeyHandle = NULL;
977 
978     InitializeObjectAttributes(&KeyAttributes, KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, ConfigurationHandle, 0);
979     *Status = ZwOpenKey(&RegKeyHandle, KEY_ALL_ACCESS, &KeyAttributes);
980 
981     if(*Status != STATUS_SUCCESS)
982     {
983         NDIS_DbgPrint(MIN_TRACE, ("ZwOpenKey failed (%x)\n", *Status));
984         *Status = NDIS_STATUS_FAILURE;
985         return;
986     }
987 
988     ConfigurationContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_CONFIGURATION_CONTEXT));
989     if(!ConfigurationContext)
990     {
991         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
992         ZwClose(RegKeyHandle);
993         *Status = NDIS_STATUS_FAILURE;
994         return;
995     }
996 
997     KeInitializeSpinLock(&ConfigurationContext->ResourceLock);
998     InitializeListHead(&ConfigurationContext->ResourceListHead);
999 
1000     ConfigurationContext->Handle = RegKeyHandle;
1001 
1002     *KeyHandle = (NDIS_HANDLE)ConfigurationContext;
1003 
1004     *Status = NDIS_STATUS_SUCCESS;
1005 }
1006