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