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