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