/*++
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 <ntddk.h>
#include <windef.h>
#include <dlcapi.h>
#include <dlcio.h>
#include <ndis.h>
#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\<AdapterName>
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\<adapter>
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\<AdapterName> 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\<AdapterName> 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\<adapter_name>
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\<adapter_name> 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\<AdapterName> 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
}