[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, NDIS_PARAMETER_TYPE *ParameterType)
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, Base;
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 /* Set the default parameter type */
388 *ParameterType = NdisParameterInteger;
389 Base = 10;
390
391 for (i = 0; i < String->Length / sizeof(WCHAR); i++)
392 {
393 /* Look at the second character for the base */
394 if (i == 1)
395 {
396 if (String->Buffer[i] == L'X' ||
397 String->Buffer[i] == L'x')
398 {
399 NDIS_DbgPrint(MID_TRACE, ("Identified hex string\n"));
400 *ParameterType = NdisParameterHexInteger;
401 Base = 0x10;
402 continue;
403 }
404 }
405
406 /* Skip any NULL characters we find */
407 if (String->Buffer[i] == UNICODE_NULL)
408 continue;
409
410 /* Make sure the character is valid for a numeric string of this base */
411 if (UnicodeToHexByte(String->Buffer[i]) >= Base)
412 return FALSE;
413 }
414
415 /* It's valid */
416 return TRUE;
417 }
418
419 /*
420 * @implemented
421 */
422 VOID
423 EXPORT
424 NdisReadConfiguration(
425 OUT PNDIS_STATUS Status,
426 OUT PNDIS_CONFIGURATION_PARAMETER * ParameterValue,
427 IN NDIS_HANDLE ConfigurationHandle,
428 IN PNDIS_STRING Keyword,
429 IN NDIS_PARAMETER_TYPE ParameterType)
430 /*
431 * FUNCTION: Read a configuration value from the registry, tracking its resources
432 * ARGUMENTS:
433 * Status: points to a place to write status into
434 * ParameterValue: Pointer to receive a newly-allocated parameter structure
435 * ConfigurationHandle: handle originally returned by an open function
436 * Keyword: Value name to read, or one of the following constants:
437 * Environment - returns NdisEnvironmentWindowsNt
438 * ProcessorType - returns NdisProcessorX86 until more architectures are added
439 * NdisVersion - returns NDIS_VERSION
440 * ParameterType: the type of the value to be queried
441 * RETURNS:
442 * - A status in Status
443 * - A parameter value in ParameterValue
444 */
445 {
446 KEY_VALUE_PARTIAL_INFORMATION *KeyInformation;
447 ULONG KeyDataLength;
448 PMINIPORT_RESOURCE MiniportResource;
449 PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext = (PMINIPORT_CONFIGURATION_CONTEXT)ConfigurationHandle;
450 PVOID Buffer;
451
452 *ParameterValue = NULL;
453 *Status = NDIS_STATUS_FAILURE;
454
455 NDIS_DbgPrint(MAX_TRACE,("requested read of %wZ\n", Keyword));
456 NDIS_DbgPrint(MID_TRACE,("requested parameter type: %d\n", ParameterType));
457
458 if (ConfigurationContext == NULL)
459 {
460 NDIS_DbgPrint(MIN_TRACE,("invalid parameter ConfigurationContext (0x%x)\n",ConfigurationContext));
461 return;
462 }
463
464 if(
465 !wcsncmp(Keyword->Buffer, L"Environment", Keyword->Length/sizeof(WCHAR)) &&
466 wcslen(L"Environment") == Keyword->Length/sizeof(WCHAR)
467 )
468 {
469 *ParameterValue = ExAllocatePool(PagedPool, sizeof(NDIS_CONFIGURATION_PARAMETER));
470 if(!*ParameterValue)
471 {
472 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
473 *Status = NDIS_STATUS_RESOURCES;
474 return;
475 }
476
477 MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
478 if(!MiniportResource)
479 {
480 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
481 ExFreePool(*ParameterValue);
482 *ParameterValue = NULL;
483 *Status = NDIS_STATUS_RESOURCES;
484 return;
485 }
486
487 MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_REGISTRY_DATA;
488 MiniportResource->Resource = *ParameterValue;
489
490 NDIS_DbgPrint(MID_TRACE,("inserting 0x%x into the resource list\n",
491 MiniportResource->Resource));
492
493 ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead,
494 &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
495
496 (*ParameterValue)->ParameterType = NdisParameterInteger;
497 (*ParameterValue)->ParameterData.IntegerData = NdisEnvironmentWindowsNt;
498 *Status = NDIS_STATUS_SUCCESS;
499
500 return;
501 }
502
503 if(
504 !wcsncmp(Keyword->Buffer, L"ProcessorType", Keyword->Length/sizeof(WCHAR)) &&
505 wcslen(L"ProcessorType") == Keyword->Length/sizeof(WCHAR)
506 )
507 {
508 *ParameterValue = ExAllocatePool(PagedPool, sizeof(NDIS_CONFIGURATION_PARAMETER));
509 if(!*ParameterValue)
510 {
511 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
512 *Status = NDIS_STATUS_RESOURCES;
513 return;
514 }
515
516 MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
517 if(!MiniportResource)
518 {
519 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
520 ExFreePool(*ParameterValue);
521 *ParameterValue = NULL;
522 *Status = NDIS_STATUS_RESOURCES;
523 return;
524 }
525
526 MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_REGISTRY_DATA;
527 MiniportResource->Resource = *ParameterValue;
528 NDIS_DbgPrint(MID_TRACE,("inserting 0x%x into the resource list\n", MiniportResource->Resource));
529 ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead,
530 &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
531
532 (*ParameterValue)->ParameterType = NdisParameterInteger;
533 (*ParameterValue)->ParameterData.IntegerData = NdisProcessorX86; /* XXX non-portable */
534 *Status = NDIS_STATUS_SUCCESS;
535
536 return;
537 }
538
539 if(
540 !wcsncmp(Keyword->Buffer, L"NdisVersion", Keyword->Length/sizeof(WCHAR)) &&
541 wcslen(L"NdisVersion") == Keyword->Length/sizeof(WCHAR)
542 )
543 {
544 *ParameterValue = ExAllocatePool(PagedPool, sizeof(NDIS_CONFIGURATION_PARAMETER));
545 if(!*ParameterValue)
546 {
547 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
548 *Status = NDIS_STATUS_RESOURCES;
549 return;
550 }
551
552 MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
553 if(!MiniportResource)
554 {
555 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
556 ExFreePool(*ParameterValue);
557 *ParameterValue = NULL;
558 *Status = NDIS_STATUS_RESOURCES;
559 return;
560 }
561
562 MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_REGISTRY_DATA;
563 MiniportResource->Resource = *ParameterValue;
564 NDIS_DbgPrint(MID_TRACE,("inserting 0x%x into the resource list\n", MiniportResource->Resource));
565 ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead,
566 &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
567
568 (*ParameterValue)->ParameterType = NdisParameterInteger;
569 (*ParameterValue)->ParameterData.IntegerData = NDIS_VERSION;
570 *Status = NDIS_STATUS_SUCCESS;
571
572 NDIS_DbgPrint(MAX_TRACE,("ParameterType = %0x%x, ParameterValue = 0x%x\n",
573 (*ParameterValue)->ParameterType, (*ParameterValue)->ParameterData.IntegerData));
574 return;
575 }
576
577 /* figure out how much buffer i should allocate */
578 *Status = ZwQueryValueKey(ConfigurationContext->Handle, Keyword, KeyValuePartialInformation, NULL, 0, &KeyDataLength);
579 if(*Status != STATUS_BUFFER_OVERFLOW && *Status != STATUS_BUFFER_TOO_SMALL && *Status != STATUS_SUCCESS)
580 {
581 NDIS_DbgPrint(MID_TRACE,("ZwQueryValueKey #1 failed for %wZ, status 0x%x\n", Keyword, *Status));
582 *Status = NDIS_STATUS_FAILURE;
583 return;
584 }
585
586 /* allocate it */
587 KeyInformation = ExAllocatePool(PagedPool, KeyDataLength + sizeof(KEY_VALUE_PARTIAL_INFORMATION));
588 if(!KeyInformation)
589 {
590 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
591 *Status = NDIS_STATUS_RESOURCES;
592 return;
593 }
594
595 /* grab the value */
596 *Status = ZwQueryValueKey(ConfigurationContext->Handle, Keyword, KeyValuePartialInformation,
597 KeyInformation, KeyDataLength + sizeof(KEY_VALUE_PARTIAL_INFORMATION), &KeyDataLength);
598 if(*Status != STATUS_SUCCESS)
599 {
600 ExFreePool(KeyInformation);
601 NDIS_DbgPrint(MIN_TRACE,("ZwQueryValueKey #2 failed for %wZ, status 0x%x\n", Keyword, *Status));
602 *Status = NDIS_STATUS_FAILURE;
603 return;
604 }
605
606 MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
607 if(!MiniportResource)
608 {
609 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
610 ExFreePool(KeyInformation);
611 *Status = NDIS_STATUS_RESOURCES;
612 return;
613 }
614
615 *ParameterValue = ExAllocatePool(PagedPool, sizeof(NDIS_CONFIGURATION_PARAMETER));
616 if (!*ParameterValue)
617 {
618 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
619 ExFreePool(MiniportResource);
620 ExFreePool(KeyInformation);
621 *Status = NDIS_STATUS_RESOURCES;
622 return;
623 }
624
625 RtlZeroMemory(*ParameterValue, sizeof(NDIS_CONFIGURATION_PARAMETER));
626
627 if (KeyInformation->Type == REG_BINARY)
628 {
629 NDIS_DbgPrint(MAX_TRACE, ("NdisParameterBinary\n"));
630
631 (*ParameterValue)->ParameterType = NdisParameterBinary;
632
633 Buffer = ExAllocatePool(NonPagedPool, 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.BinaryData.Buffer = Buffer;
646 (*ParameterValue)->ParameterData.BinaryData.Length = KeyInformation->DataLength;
647 }
648 else if (KeyInformation->Type == REG_MULTI_SZ)
649 {
650 NDIS_DbgPrint(MAX_TRACE, ("NdisParameterMultiString\n"));
651
652 (*ParameterValue)->ParameterType = NdisParameterMultiString;
653
654 Buffer = ExAllocatePool(NonPagedPool, KeyInformation->DataLength);
655 if (!Buffer)
656 {
657 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
658 ExFreePool(MiniportResource);
659 ExFreePool(KeyInformation);
660 *Status = NDIS_STATUS_RESOURCES;
661 return;
662 }
663
664 RtlCopyMemory(Buffer, KeyInformation->Data, KeyInformation->DataLength);
665
666 (*ParameterValue)->ParameterData.StringData.Buffer = Buffer;
667 (*ParameterValue)->ParameterData.StringData.Length = KeyInformation->DataLength;
668 }
669 else if (KeyInformation->Type == REG_SZ)
670 {
671 UNICODE_STRING str;
672
673 str.Length = str.MaximumLength = (USHORT)KeyInformation->DataLength;
674 str.Buffer = (PWCHAR)KeyInformation->Data;
675
676 if (IsValidNumericString(&str, &(*ParameterValue)->ParameterType) &&
677 ((*Status = RtlUnicodeStringToInteger(&str, 0,
678 &(*ParameterValue)->ParameterData.IntegerData)) == STATUS_SUCCESS))
679 {
680 NDIS_DbgPrint(MAX_TRACE, ("NdisParameter(Hex)Integer\n"));
681
682 /* IsValidNumericString sets the parameter type when parsing the string */
683 }
684 else
685 {
686 NDIS_DbgPrint(MAX_TRACE, ("NdisParameterString\n"));
687
688 (*ParameterValue)->ParameterType = NdisParameterString;
689
690 Buffer = ExAllocatePool(NonPagedPool, KeyInformation->DataLength);
691 if (!Buffer)
692 {
693 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
694 ExFreePool(MiniportResource);
695 ExFreePool(KeyInformation);
696 *Status = NDIS_STATUS_RESOURCES;
697 return;
698 }
699
700 RtlCopyMemory(Buffer, KeyInformation->Data, KeyInformation->DataLength);
701
702 (*ParameterValue)->ParameterData.StringData.Buffer = Buffer;
703 (*ParameterValue)->ParameterData.StringData.Length = KeyInformation->DataLength;
704 }
705 }
706 else
707 {
708 NDIS_DbgPrint(MIN_TRACE, ("Invalid type for NdisReadConfiguration (%d)\n", KeyInformation->Type));
709 NDIS_DbgPrint(MIN_TRACE, ("Requested type: %d\n", ParameterType));
710 NDIS_DbgPrint(MIN_TRACE, ("Registry entry: %wZ\n", Keyword));
711 *Status = NDIS_STATUS_FAILURE;
712 ExFreePool(KeyInformation);
713 return;
714 }
715
716 if ((*ParameterValue)->ParameterType != ParameterType)
717 {
718 NDIS_DbgPrint(MIN_TRACE, ("Parameter type mismatch! (Requested: %d | Received: %d)\n",
719 ParameterType, (*ParameterValue)->ParameterType));
720 NDIS_DbgPrint(MIN_TRACE, ("Registry entry: %wZ\n", Keyword));
721 }
722
723 MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_REGISTRY_DATA;
724 MiniportResource->Resource = *ParameterValue;
725
726 ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead, &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
727
728 ExFreePool(KeyInformation);
729
730 *Status = NDIS_STATUS_SUCCESS;
731 }
732
733 /*
734 * @implemented
735 */
736 VOID
737 EXPORT
738 NdisReadNetworkAddress(
739 OUT PNDIS_STATUS Status,
740 OUT PVOID * NetworkAddress,
741 OUT PUINT NetworkAddressLength,
742 IN NDIS_HANDLE ConfigurationHandle)
743 /*
744 * FUNCTION: Reads the network address from the registry
745 * ARGUMENTS:
746 * Status - variable to receive status
747 * NetworkAddress - pointer to a buffered network address array
748 * NetworkAddressLength - length of the NetworkAddress array
749 * ConfigurationHandle: handle passed back from one of the open routines
750 * RETURNS:
751 * NDIS_STATUS_SUCCESS on success
752 * NDIS_STATUS_FAILURE on failure
753 * The network address is placed in the NetworkAddress buffer
754 */
755 {
756 PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext = (PMINIPORT_CONFIGURATION_CONTEXT)ConfigurationHandle;
757 PMINIPORT_RESOURCE MiniportResource = NULL;
758 PNDIS_CONFIGURATION_PARAMETER ParameterValue = NULL;
759 NDIS_STRING Keyword;
760 UINT *IntArray = 0;
761 UINT i,j = 0;
762 NDIS_STRING str;
763
764 NdisInitUnicodeString(&Keyword, L"NetworkAddress");
765 NdisReadConfiguration(Status, &ParameterValue, ConfigurationHandle, &Keyword, NdisParameterString);
766 if(*Status != NDIS_STATUS_SUCCESS)
767 {
768 NDIS_DbgPrint(MID_TRACE, ("NdisReadConfiguration failed (%x)\n", *Status));
769 *Status = NDIS_STATUS_FAILURE;
770 return;
771 }
772
773 if (ParameterValue->ParameterType == NdisParameterInteger)
774 {
775 WCHAR Buff[11];
776
777 NDIS_DbgPrint(MAX_TRACE, ("Read integer data %lx\n",
778 ParameterValue->ParameterData.IntegerData));
779
780 str.Buffer = Buff;
781 str.MaximumLength = (USHORT)sizeof(Buff);
782 str.Length = 0;
783
784 *Status = RtlIntegerToUnicodeString(ParameterValue->ParameterData.IntegerData,
785 10,
786 &str);
787
788 if (*Status != NDIS_STATUS_SUCCESS)
789 {
790 NDIS_DbgPrint(MIN_TRACE, ("RtlIntegerToUnicodeString failed (%x)\n", *Status));
791 *Status = NDIS_STATUS_FAILURE;
792 return;
793 }
794
795 NDIS_DbgPrint(MAX_TRACE, ("Converted integer data into %wZ\n", &str));
796 }
797 else
798 {
799 ASSERT(ParameterValue->ParameterType == NdisParameterString);
800 str = ParameterValue->ParameterData.StringData;
801 }
802
803 while (j < str.Length && str.Buffer[j] != '\0') j++;
804
805 *NetworkAddressLength = (j+1) >> 1;
806
807 if ((*NetworkAddressLength) == 0)
808 {
809 NDIS_DbgPrint(MIN_TRACE,("Empty NetworkAddress registry entry.\n"));
810 *Status = NDIS_STATUS_FAILURE;
811 return;
812 }
813
814 IntArray = ExAllocatePool(PagedPool, (*NetworkAddressLength)*sizeof(UINT));
815 if(!IntArray)
816 {
817 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
818 *Status = NDIS_STATUS_RESOURCES;
819 return;
820 }
821
822 MiniportResource = ExAllocatePool(PagedPool, sizeof(MINIPORT_RESOURCE));
823 if(!MiniportResource)
824 {
825 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
826 ExFreePool(IntArray);
827 *Status = NDIS_STATUS_RESOURCES;
828 return;
829 }
830
831 MiniportResource->ResourceType = MINIPORT_RESOURCE_TYPE_MEMORY;
832 MiniportResource->Resource = IntArray;
833 NDIS_DbgPrint(MID_TRACE,("inserting 0x%x into the resource list\n", MiniportResource->Resource));
834 ExInterlockedInsertTailList(&ConfigurationContext->ResourceListHead, &MiniportResource->ListEntry, &ConfigurationContext->ResourceLock);
835
836 /* convert from string to bytes */
837 for(i=0; i<(*NetworkAddressLength); i++)
838 {
839 IntArray[i] = (UnicodeToHexByte((str.Buffer)[2*i]) << 4) +
840 UnicodeToHexByte((str.Buffer)[2*i+1]);
841 }
842
843 *NetworkAddress = IntArray;
844
845 *Status = NDIS_STATUS_SUCCESS;
846 }
847
848
849 /*
850 * @implemented
851 */
852 VOID
853 EXPORT
854 NdisOpenConfigurationKeyByIndex(
855 OUT PNDIS_STATUS Status,
856 IN NDIS_HANDLE ConfigurationHandle,
857 IN ULONG Index,
858 OUT PNDIS_STRING KeyName,
859 OUT PNDIS_HANDLE KeyHandle)
860 /*
861 * FUNCTION: Opens a configuration subkey by index number
862 * ARGUMENTS:
863 * Status: pointer to an NDIS_STATUS to receive status info
864 * ConfigurationHandle: the handle passed back from a previous open function
865 * Index: the zero-based index of the subkey to open
866 * KeyName: the name of the key that was opened
867 * KeyHandle: a handle to the key that was opened
868 * RETURNS:
869 * NDIS_STATUS_SUCCESS on success
870 * NDIS_STATUS_FAILURE on failure
871 * KeyName holds the name of the opened key
872 * KeyHandle holds a handle to the new key
873 */
874 {
875 KEY_BASIC_INFORMATION *KeyInformation;
876 ULONG KeyInformationLength;
877 OBJECT_ATTRIBUTES KeyAttributes;
878 NDIS_HANDLE RegKeyHandle;
879 PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext;
880
881 *KeyHandle = NULL;
882
883 *Status = ZwEnumerateKey(ConfigurationHandle, Index, KeyBasicInformation, NULL, 0, &KeyInformationLength);
884 if(*Status != STATUS_BUFFER_TOO_SMALL && *Status != STATUS_BUFFER_OVERFLOW && *Status != STATUS_SUCCESS)
885 {
886 NDIS_DbgPrint(MIN_TRACE, ("ZwEnumerateKey failed (%x)\n", *Status));
887 *Status = NDIS_STATUS_FAILURE;
888 return;
889 }
890
891 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength + sizeof(KEY_BASIC_INFORMATION));
892 if(!KeyInformation)
893 {
894 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
895 *Status = NDIS_STATUS_FAILURE;
896 return;
897 }
898
899 *Status = ZwEnumerateKey(ConfigurationHandle, Index, KeyBasicInformation, KeyInformation,
900 KeyInformationLength + sizeof(KEY_BASIC_INFORMATION), &KeyInformationLength);
901
902 if(*Status != STATUS_SUCCESS)
903 {
904 NDIS_DbgPrint(MIN_TRACE, ("ZwEnumerateKey failed (%x)\n", *Status));
905 ExFreePool(KeyInformation);
906 *Status = NDIS_STATUS_FAILURE;
907 return;
908 }
909
910 /* should i fail instead if the passed-in string isn't long enough? */
911 wcsncpy(KeyName->Buffer, KeyInformation->Name, KeyName->MaximumLength/sizeof(WCHAR));
912 KeyName->Length = (USHORT)min(KeyInformation->NameLength, KeyName->MaximumLength);
913
914 InitializeObjectAttributes(&KeyAttributes, KeyName, OBJ_CASE_INSENSITIVE, ConfigurationHandle, NULL);
915
916 *Status = ZwOpenKey(&RegKeyHandle, KEY_ALL_ACCESS, &KeyAttributes);
917
918 ExFreePool(KeyInformation);
919
920 if(*Status != STATUS_SUCCESS)
921 {
922 NDIS_DbgPrint(MIN_TRACE, ("ZwOpenKey failed (%x)\n", *Status));
923 *Status = NDIS_STATUS_FAILURE;
924 return;
925 }
926
927 ConfigurationContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_CONFIGURATION_CONTEXT));
928 if(!ConfigurationContext)
929 {
930 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
931 ZwClose(RegKeyHandle);
932 *Status = NDIS_STATUS_FAILURE;
933 return;
934 }
935
936 KeInitializeSpinLock(&ConfigurationContext->ResourceLock);
937 InitializeListHead(&ConfigurationContext->ResourceListHead);
938
939 ConfigurationContext->Handle = RegKeyHandle;
940
941 *KeyHandle = (NDIS_HANDLE)ConfigurationContext;
942
943 *Status = NDIS_STATUS_SUCCESS;
944 }
945
946
947 /*
948 * @implemented
949 */
950 VOID
951 EXPORT
952 NdisOpenConfigurationKeyByName(
953 OUT PNDIS_STATUS Status,
954 IN NDIS_HANDLE ConfigurationHandle,
955 IN PNDIS_STRING KeyName,
956 OUT PNDIS_HANDLE KeyHandle)
957 /*
958 * FUNCTION: Opens a configuration subkey by name
959 * ARGUMENTS:
960 * Status: points to an NDIS_STATUS where status is returned
961 * ConfigurationHandle: handle returned by a previous open call
962 * KeyName: the name of the key to open
963 * KeyHandle: a handle to the opened key
964 * RETURNS:
965 * NDIS_STATUS_SUCCESS on success
966 * NDIS_STATUS_FAILURE on failure
967 * KeyHandle holds a handle to the newly-opened key
968 * NOTES:
969 */
970 {
971 PMINIPORT_CONFIGURATION_CONTEXT ConfigurationContext;
972 OBJECT_ATTRIBUTES KeyAttributes;
973 NDIS_HANDLE RegKeyHandle;
974
975 *KeyHandle = NULL;
976
977 InitializeObjectAttributes(&KeyAttributes, KeyName, OBJ_CASE_INSENSITIVE, ConfigurationHandle, 0);
978 *Status = ZwOpenKey(&RegKeyHandle, KEY_ALL_ACCESS, &KeyAttributes);
979
980 if(*Status != STATUS_SUCCESS)
981 {
982 NDIS_DbgPrint(MIN_TRACE, ("ZwOpenKey failed (%x)\n", *Status));
983 *Status = NDIS_STATUS_FAILURE;
984 return;
985 }
986
987 ConfigurationContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_CONFIGURATION_CONTEXT));
988 if(!ConfigurationContext)
989 {
990 NDIS_DbgPrint(MIN_TRACE,("Insufficient resources.\n"));
991 ZwClose(RegKeyHandle);
992 *Status = NDIS_STATUS_FAILURE;
993 return;
994 }
995
996 KeInitializeSpinLock(&ConfigurationContext->ResourceLock);
997 InitializeListHead(&ConfigurationContext->ResourceListHead);
998
999 ConfigurationContext->Handle = RegKeyHandle;
1000
1001 *KeyHandle = (NDIS_HANDLE)ConfigurationContext;
1002
1003 *Status = NDIS_STATUS_SUCCESS;
1004 }