/*++ Copyright (c) 1991 Microsoft Corporation Module Name: dlcreg.c Abstract: This module accesses the registry for DLC.SYS Contents: DlcRegistryInitialization LoadDlcConfiguration LoadAdapterConfiguration GetAdapterParameters OpenDlcRegistryHandle OpenDlcAdapterRegistryHandle GetRegistryParameter SetRegistryParameter DlcpGetParameter DlcRegistryTermination Author: Richard L Firth (rfirth) 31-Mar-1993 Environment: kernel mode only Revision History: 30-Mar-1993 rfirth created 04-May-1994 rfirth Exposed GetAdapterParameters --*/ #include #include #include #include #include #include "llcapi.h" #include "dlcdef.h" #include "dlcreg.h" #include "dlctyp.h" #include "llcdef.h" #include "llcmem.h" #include "llctyp.h" #include "llcext.h" // // manifests // #define MAX_ADAPTER_NAME_LENGTH 32 // ? #define MAX_INFORMATION_BUFFER_LENGTH 256 // ? #define PARAMETERS_STRING L"Parameters" // // indicies of parameters within parameter table // #define SWAP_INDEX 0 #define USEDIX_INDEX 1 #define T1_TICK_ONE_INDEX 2 #define T2_TICK_ONE_INDEX 3 #define Ti_TICK_ONE_INDEX 4 #define T1_TICK_TWO_INDEX 5 #define T2_TICK_TWO_INDEX 6 #define Ti_TICK_TWO_INDEX 7 #define FRAME_SIZE_INDEX 8 // // typedefs // // // macros // #define CloseDlcRegistryHandle(handle) ZwClose(handle) #define CloseAdapterRegistryHandle(handle) ZwClose(handle) // // Global data // // // private data // UNICODE_STRING DlcRegistryPath; UNICODE_STRING ParametersPath; // // AdapterParameterTable - used for loading DLC parameters from registry in // data-driven manner. Each adapter that DLC talks to can have a set of all // or part of the following variables // DLC_REGISTRY_PARAMETER AdapterParameterTable[] = { L"Swap", (PVOID)DEFAULT_SWAP_ADDRESS_BITS, { REG_DWORD, PARAMETER_IS_BOOLEAN, NULL, sizeof(ULONG), NULL, 0, 0 }, L"UseDixOverEthernet", (PVOID)DEFAULT_DIX_FORMAT, { REG_DWORD, PARAMETER_IS_BOOLEAN, NULL, sizeof(ULONG), NULL, 0, 0 }, L"T1TickOne", (PVOID)DEFAULT_T1_TICK_ONE, { REG_DWORD, PARAMETER_IS_UCHAR, NULL, sizeof(ULONG), NULL, MIN_TIMER_TICK_VALUE, MAX_TIMER_TICK_VALUE }, L"T2TickOne", (PVOID)DEFAULT_T2_TICK_ONE, { REG_DWORD, PARAMETER_IS_UCHAR, NULL, sizeof(ULONG), NULL, MIN_TIMER_TICK_VALUE, MAX_TIMER_TICK_VALUE }, L"TiTickOne", (PVOID)DEFAULT_Ti_TICK_ONE, { REG_DWORD, PARAMETER_IS_UCHAR, NULL, sizeof(ULONG), NULL, MIN_TIMER_TICK_VALUE, MAX_TIMER_TICK_VALUE }, L"T1TickTwo", (PVOID)DEFAULT_T1_TICK_TWO, { REG_DWORD, PARAMETER_IS_UCHAR, NULL, sizeof(ULONG), NULL, MIN_TIMER_TICK_VALUE, MAX_TIMER_TICK_VALUE }, L"T2TickTwo", (PVOID)DEFAULT_T2_TICK_TWO, { REG_DWORD, PARAMETER_IS_UCHAR, NULL, sizeof(ULONG), NULL, MIN_TIMER_TICK_VALUE, MAX_TIMER_TICK_VALUE }, L"TiTickTwo", (PVOID)DEFAULT_Ti_TICK_TWO, { REG_DWORD, PARAMETER_IS_UCHAR, NULL, sizeof(ULONG), NULL, MIN_TIMER_TICK_VALUE, MAX_TIMER_TICK_VALUE }, L"UseEthernetFrameSize", (PVOID)DEFAULT_USE_ETHERNET_FRAME_SIZE, { REG_DWORD, PARAMETER_IS_BOOLEAN, NULL, sizeof(ULONG), NULL, 0, 0 } }; #define NUMBER_OF_DLC_PARAMETERS (sizeof(AdapterParameterTable)/sizeof(AdapterParameterTable[0])) // // private function prototypes // NTSTATUS OpenDlcRegistryHandle( IN PUNICODE_STRING RegistryPath, OUT PHANDLE DlcRegistryHandle ); NTSTATUS OpenDlcAdapterRegistryHandle( IN HANDLE DlcRegistryHandle, IN PUNICODE_STRING AdapterName, OUT PHANDLE DlcAdapterRegistryHandle, OUT PBOOLEAN Created ); NTSTATUS GetRegistryParameter( IN HANDLE KeyHandle, IN PDLC_REGISTRY_PARAMETER Parameter, IN BOOLEAN SetOnFail ); NTSTATUS SetRegistryParameter( IN HANDLE KeyHandle, IN PDLC_REGISTRY_PARAMETER Parameter ); NTSTATUS DlcpGetParameter( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ); // // debug display options // #if DBG BOOLEAN DebugConfig = TRUE; #endif // // functions // VOID DlcRegistryInitialization( IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: Initializes memory structures for functions in this module Arguments: RegistryPath - pointer to UNICODE_STRING giving base of DLC section in registry Return Value: None. --*/ { ASSUME_IRQL(PASSIVE_LEVEL); LlcInitUnicodeString(&DlcRegistryPath, RegistryPath); RtlInitUnicodeString(&ParametersPath, PARAMETERS_STRING); } VOID DlcRegistryTermination( VOID ) /*++ Routine Description: Undoes anything done in DlcRegistryInitialization Arguments: None. Return Value: None. --*/ { ASSUME_IRQL(PASSIVE_LEVEL); LlcFreeUnicodeString(&DlcRegistryPath); } VOID LoadDlcConfiguration( VOID ) /*++ Routine Description: Initializes the data structures used to access the registry and loads any configuration parameters for the driver Arguments: None. Return Value: None. --*/ { // // nothing else to do at present since we made all currently known // configuration parameters per-adapter // } VOID LoadAdapterConfiguration( IN PUNICODE_STRING AdapterName, OUT PADAPTER_CONFIGURATION_INFO ConfigInfo ) /*++ Routine Description: Loads all of DLC initialization parameters for an adapter from registry: Swap 0 or 1, default 1 UseDixOverEthernet 0 or 1, default 0 T1TickOne 1 - 255, default 5 T1TickTwo 1 - 255, default 25 T2TickOne 1 - 255, default 1 T2TickTwo 1 - 255, default 10 TiTickOne 1 - 255, default 25 TiTickTwo 1 - 255, default 125 UseEthernetFrameSize 0 or 1, default 1 If any of the parameters do not exist in the DLC\Parameters\ section, then they are created Arguments: AdapterName - pointer to UNICODE_STRING structure giving the name of the adapter we are opening. This is the value of a key in the DLC\Parameters section. The string is EXPECTED to be of the form \Device\ ConfigInfo - pointer to the structure that receives the values on output Return Value: None. --*/ { UINT i; PDLC_REGISTRY_PARAMETER parameterTable; ASSUME_IRQL(PASSIVE_LEVEL); // // fill in the adapter configuration structure with default values. These // will be used to update the registry if the value entry doesn't currently // exist // ConfigInfo->SwapAddressBits = (BOOLEAN)DEFAULT_SWAP_ADDRESS_BITS; ConfigInfo->UseDix = (BOOLEAN)DEFAULT_DIX_FORMAT; ConfigInfo->TimerTicks.T1TickOne = (UCHAR)DEFAULT_T1_TICK_ONE; ConfigInfo->TimerTicks.T2TickOne = (UCHAR)DEFAULT_T2_TICK_ONE; ConfigInfo->TimerTicks.TiTickOne = (UCHAR)DEFAULT_Ti_TICK_ONE; ConfigInfo->TimerTicks.T1TickTwo = (UCHAR)DEFAULT_T1_TICK_TWO; ConfigInfo->TimerTicks.T2TickTwo = (UCHAR)DEFAULT_T2_TICK_TWO; ConfigInfo->TimerTicks.TiTickTwo = (UCHAR)DEFAULT_Ti_TICK_TWO; ConfigInfo->UseEthernetFrameSize = (BOOLEAN)DEFAULT_USE_ETHERNET_FRAME_SIZE; // // create and initialize a copy of the DLC adapter parameters template // parameterTable = (PDLC_REGISTRY_PARAMETER)ALLOCATE_MEMORY_DRIVER( sizeof(*parameterTable) * NUMBER_OF_DLC_PARAMETERS); if (parameterTable) { RtlCopyMemory(parameterTable, AdapterParameterTable, sizeof(AdapterParameterTable)); for (i = 0; i < NUMBER_OF_DLC_PARAMETERS; ++i) { parameterTable[i].Descriptor.Value = (PVOID)¶meterTable[i].DefaultValue; switch (i) { case SWAP_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->SwapAddressBits; break; case USEDIX_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->UseDix; break; case T1_TICK_ONE_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->TimerTicks.T1TickOne; break; case T2_TICK_ONE_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->TimerTicks.T2TickOne; break; case Ti_TICK_ONE_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->TimerTicks.TiTickOne; break; case T1_TICK_TWO_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->TimerTicks.T1TickTwo; break; case T2_TICK_TWO_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->TimerTicks.T2TickTwo; break; case Ti_TICK_TWO_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->TimerTicks.TiTickTwo; break; case FRAME_SIZE_INDEX: parameterTable[i].Descriptor.Variable = &ConfigInfo->UseEthernetFrameSize; break; } } GetAdapterParameters(AdapterName, parameterTable, NUMBER_OF_DLC_PARAMETERS, FALSE); FREE_MEMORY_DRIVER(parameterTable); } #if DBG if (DebugConfig) { DbgPrint("DLC.LoadAdapterConfigurationFromRegistry for adapter %ws:\n" "\tSwap . . . . . . . . . : %d\n" "\tUseDixOverEthernet . . : %d\n" "\tT1TickOne. . . . . . . : %d\n" "\tT2TickOne. . . . . . . : %d\n" "\tTiTickOne. . . . . . . : %d\n" "\tT1TickTwo. . . . . . . : %d\n" "\tT2TickTwo. . . . . . . : %d\n" "\tTiTickTwo. . . . . . . : %d\n" "\tUseEthernetFrameSize . : %d\n", AdapterName->Buffer, ConfigInfo->SwapAddressBits, ConfigInfo->UseDix, ConfigInfo->TimerTicks.T1TickOne, ConfigInfo->TimerTicks.T2TickOne, ConfigInfo->TimerTicks.TiTickOne, ConfigInfo->TimerTicks.T1TickTwo, ConfigInfo->TimerTicks.T2TickTwo, ConfigInfo->TimerTicks.TiTickTwo, ConfigInfo->UseEthernetFrameSize ); } #endif } NTSTATUS GetAdapterParameters( IN PUNICODE_STRING AdapterName, IN PDLC_REGISTRY_PARAMETER Parameters, IN ULONG NumberOfParameters, IN BOOLEAN SetOnFail ) /*++ Routine Description: Retrieves a list of parameters from the DLC\Parameters\ section in the registry Arguments: AdapterName - pointer to UNICODE_STRING identifying adapter section in DLC section of registry to open Parameters - pointer to array of DLC_REGISTRY_PARAMETER structures describing variables and default values to retrieve NumberOfParameters - number of structures in Parameters array SetOnFail - TRUE if we should set the registry parameter if we fail to get it Return Value: NTSTATUS Success - STATUS_SUCCESS Failure - --*/ { NTSTATUS status; HANDLE dlcHandle; ASSUME_IRQL(PASSIVE_LEVEL); status = OpenDlcRegistryHandle(&DlcRegistryPath, &dlcHandle); if (NT_SUCCESS(status)) { HANDLE adapterHandle; BOOLEAN created; status = OpenDlcAdapterRegistryHandle(dlcHandle, AdapterName, &adapterHandle, &created ); if (NT_SUCCESS(status)) { while (NumberOfParameters--) { // // if this adapter section was created then create the parameter // value entries and set them to the defaults, else retrieve the // current registry values // if (created) { SetRegistryParameter(adapterHandle, Parameters); } else { GetRegistryParameter(adapterHandle, Parameters, SetOnFail); } ++Parameters; } CloseAdapterRegistryHandle(adapterHandle); } CloseDlcRegistryHandle(dlcHandle); } return status; } NTSTATUS OpenDlcRegistryHandle( IN PUNICODE_STRING RegistryPath, OUT PHANDLE DlcRegistryHandle ) /*++ Routine Description: Opens a handle to the DLC section in the registry Arguments: RegistryPath - pointer to UNICODE_STRING giving full registry path to DLC section DlcRegistryHandle - returned handle Return Value: NTSTATUS Success - STATUS_SUCCESS Failure - --*/ { OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status; ULONG disposition; ASSUME_IRQL(PASSIVE_LEVEL); InitializeObjectAttributes(&objectAttributes, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL ); status = ZwCreateKey(DlcRegistryHandle, KEY_WRITE, // might want to update something in registry &objectAttributes, 0, // title index NULL, // class 0, // create options &disposition ); #if DBG if (DebugConfig) { if (!NT_SUCCESS(status)) { DbgPrint("DLC.OpenDlcRegistryHandle: Error: %08x\n", status); } } #endif return status; } NTSTATUS OpenDlcAdapterRegistryHandle( IN HANDLE DlcRegistryHandle, IN PUNICODE_STRING AdapterName, OUT PHANDLE DlcAdapterRegistryHandle, OUT PBOOLEAN Created ) /*++ Routine Description: Opens a handle to the DLC\Parameters\ section in the registry. If this node does not exist, it is created Arguments: DlcRegistryHandle - open handle to DLC section in registry AdapterName - name of adapter in Parameters section. This MUST be of the form \Device\ DlcAdapterRegistryHandle - returned open handle Created - returned TRUE if the handle was created Return Value: NTSTATUS Success - STATUS_SUCCESS Failure - --*/ { UNICODE_STRING keyName; UNICODE_STRING adapterName; WCHAR keyBuffer[sizeof(PARAMETERS_STRING) + MAX_ADAPTER_NAME_LENGTH]; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status; ULONG disposition; ASSUME_IRQL(PASSIVE_LEVEL); keyName.Buffer = keyBuffer; keyName.Length = 0; keyName.MaximumLength = sizeof(keyBuffer); RtlCopyUnicodeString(&keyName, &ParametersPath); RtlInitUnicodeString(&adapterName, AdapterName->Buffer); adapterName.Buffer += sizeof(L"\\Device") / sizeof(L"") - 1; adapterName.Length -= sizeof(L"\\Device") - sizeof(L""); adapterName.MaximumLength -= sizeof(L"\\Device") - sizeof(L""); RtlAppendUnicodeStringToString(&keyName, &adapterName); InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_CASE_INSENSITIVE, DlcRegistryHandle, NULL ); // // if the DLC\Parameters\ key does not exist, then we will // create it // status = ZwCreateKey(DlcAdapterRegistryHandle, KEY_WRITE, &objectAttributes, 0, NULL, 0, &disposition ); *Created = (disposition == REG_CREATED_NEW_KEY); #if DBG if (DebugConfig) { if (!NT_SUCCESS(status)) { DbgPrint("DLC.OpenDlcAdapterRegistryHandle: Error: %08x\n", status); } } #endif return status; } NTSTATUS GetRegistryParameter( IN HANDLE KeyHandle, IN PDLC_REGISTRY_PARAMETER Parameter, IN BOOLEAN SetOnFail ) /*++ Routine Description: Retrieves a parameter from a section of the registry. If the section cannot be accessed or returns invalid data, then we get the default value from the Parameter structure Arguments: KeyHandle - open handle to the required section in the registry Parameter - pointer to DLC_REGISTRY_PARAMETER structure giving address and type of the parameter to be retrieved, etc. SetOnFail - if we fail to get the value from the registry, we try to set the default value in the registry Return Value: NTSTATUS Success - STATUS_SUCCESS Failure - --*/ { NTSTATUS status; UNICODE_STRING parameterName; UCHAR informationBuffer[MAX_INFORMATION_BUFFER_LENGTH]; PKEY_VALUE_FULL_INFORMATION valueInformation = (PKEY_VALUE_FULL_INFORMATION)informationBuffer; ULONG informationLength; ASSUME_IRQL(PASSIVE_LEVEL); RtlInitUnicodeString(¶meterName, Parameter->ParameterName); status = ZwQueryValueKey(KeyHandle, ¶meterName, KeyValueFullInformation, (PVOID)valueInformation, sizeof(informationBuffer), &informationLength ); if (NT_SUCCESS(status) && valueInformation->DataLength) { // // use the value retrieved from the registry // status = DlcpGetParameter(Parameter->ParameterName, valueInformation->Type, (PVOID)&informationBuffer[valueInformation->DataOffset], valueInformation->DataLength, NULL, (PVOID)&Parameter->Descriptor ); } else { #if DBG if (DebugConfig) { if (!NT_SUCCESS(status)) { DbgPrint("DLC.GetRegistryParameter: Error: %08x\n", status); } else { DbgPrint("DLC.GetRegistryParameter: Error: valueInformation->DataLength is 0\n"); } } #endif if (!NT_SUCCESS(status) && SetOnFail) { SetRegistryParameter(KeyHandle, Parameter); } // // set the default value // status = DlcpGetParameter(Parameter->ParameterName, Parameter->Descriptor.Type, Parameter->Descriptor.Value, Parameter->Descriptor.Length, NULL, (PVOID)&Parameter->Descriptor ); } return status; } NTSTATUS SetRegistryParameter( IN HANDLE KeyHandle, IN PDLC_REGISTRY_PARAMETER Parameter ) /*++ Routine Description: Sets a parameter in the DLC\Parameters\ section Arguments: KeyHandle - open handle to required section in registry Parameter - pointer to DLC_REGISTRY_PARAMETER containing all required parameter information Return Value: NTSTATUS Success - STATUS_SUCCESS Failure - --*/ { NTSTATUS status; UNICODE_STRING name; ASSUME_IRQL(PASSIVE_LEVEL); RtlInitUnicodeString(&name, Parameter->ParameterName); status = ZwSetValueKey(KeyHandle, &name, 0, // TitleIndex Parameter->Descriptor.Type, Parameter->Descriptor.Value, Parameter->Descriptor.Length ); #if DBG if (DebugConfig) { if (!NT_SUCCESS(status)) { DbgPrint("DLC.SetRegistryParameter: Error: %08x\n", status); } } #endif return status; } NTSTATUS DlcpGetParameter( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ) /*++ Routine Description: Call-back function which copies the data retrieved from the registry to a variable Arguments: ValueName - pointer to name of parameter being set (ignored) ValueType - type of parameter being set ValueData - pointer to data retrieved from registry ValueLength - length of data retrieved Context - ignored EntryContext - pointer to REGISTRY_PARAMETER_DESCRIPTOR structure Return Value: NTSTATUS Success - STATUS_SUCCESS Failure - --*/ { #define Descriptor ((PREGISTRY_PARAMETER_DESCRIPTOR)EntryContext) // // if we have a registry entry for the parameter, but it is a different // type from that expected (say REG_SZ instead of REG_DWORD) then we use // the default type, length and value // if (ValueType != Descriptor->Type) { #if DBG DbgPrint("DLC.DlcpGetParameter: Error: type for %ws is %d, expected %d, using default\n", ValueName, ValueType, Descriptor->Type ); #endif ValueType = Descriptor->Type; ValueData = Descriptor->Value; ValueLength = Descriptor->Length; } switch (ValueType) { case REG_DWORD: { ULONG value; if (Descriptor->RealType == PARAMETER_IS_BOOLEAN) { value = (*(PULONG)ValueData != 0); *(PBOOLEAN)(Descriptor->Variable) = (BOOLEAN)value; // // no limit check for BOOLEAN type // break; } else { value = *(PULONG)ValueData; } // // check range. If outside range, use default. Comparison is ULONG // if (value < Descriptor->LowerLimit || value > Descriptor->UpperLimit) { #if DBG DbgPrint("DLC.DlcpGetParameter: Error: Parameter %ws = %d: Out of range (%d..%d). Using default = %d\n", ValueName, value, Descriptor->LowerLimit, Descriptor->UpperLimit, *(PULONG)(Descriptor->Value) ); #endif value = *(PULONG)(Descriptor->Value); } if (Descriptor->RealType == PARAMETER_IS_UCHAR) { *(PUCHAR)(Descriptor->Variable) = (UCHAR)value; } else { *(PULONG)(Descriptor->Variable) = value; } break; } #if DBG default: DbgPrint("DLC.DlcpGetParameter: Error: didn't expect ValueType %d\n", ValueType); #endif } return STATUS_SUCCESS; #undef pDescriptor }