You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
931 lines
24 KiB
931 lines
24 KiB
/*++
|
|
|
|
Copyright (C) 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
registry.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines that port drivers export to miniports to allow
|
|
them to read and write registry data. The Keys are relative to the miniport's
|
|
<ServiceName>\Parameters key.
|
|
|
|
Author:
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define MAX_REGISTRY_BUFFER_SIZE 0x10000
|
|
#define PORT_TAG_REGISTRY_BUFFER 'BRlP'
|
|
|
|
|
|
#define PORT_REGISTRY_INFO_INITIALIZED 0x00000001
|
|
#define PORT_REGISTRY_BUFFER_ALLOCATED 0x00000002
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PortMiniportRegistryInitialize(
|
|
IN OUT PPORT_REGISTRY_INFO PortContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the port driver to init the registry routine's internal
|
|
data.
|
|
|
|
Arguments:
|
|
|
|
PortContext - Used to identify the caller and instatiation of the caller.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS for now. If this is extended, it might require allocations, etc.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT(PortContext->Size == sizeof(PORT_REGISTRY_INFO));
|
|
|
|
//
|
|
// Initialize the spinlock and list entry.
|
|
//
|
|
KeInitializeSpinLock(&PortContext->SpinLock);
|
|
InitializeListHead(&PortContext->ListEntry);
|
|
|
|
//
|
|
// Ensure that buffer is NULL at this time. It's only valid after we allocate it.
|
|
//
|
|
PortContext->Buffer = NULL;
|
|
|
|
//
|
|
// Indiacate that this is ready to go.
|
|
//
|
|
PortContext->Flags = PORT_REGISTRY_INFO_INITIALIZED;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
PortMiniportRegistryDestroy(
|
|
IN PPORT_REGISTRY_INFO PortContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the port driver when it unloads a miniport.
|
|
It will free the resources and cleanup whatever else.
|
|
|
|
Arguments:
|
|
|
|
PortContext - Used to identify the caller and instatiation of the caller.
|
|
|
|
Return Value:
|
|
|
|
NOTHING
|
|
|
|
--*/
|
|
{
|
|
KIRQL irql;
|
|
|
|
KeAcquireSpinLock(&PortContext->SpinLock, &irql);
|
|
|
|
//
|
|
// See whether there is still a buffer hanging around.
|
|
//
|
|
if (PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED) {
|
|
ASSERT(PortContext->Buffer);
|
|
|
|
//
|
|
// Free it.
|
|
//
|
|
ExFreePool(PortContext->Buffer);
|
|
} else {
|
|
|
|
//
|
|
// This should be NULL if it's not allocated.
|
|
//
|
|
ASSERT(PortContext->Buffer == NULL);
|
|
}
|
|
|
|
//
|
|
// Clean up.
|
|
//
|
|
PortContext->Flags = 0;
|
|
PortContext->Buffer = NULL;
|
|
|
|
KeReleaseSpinLock(&PortContext->SpinLock, irql);
|
|
return;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PortAllocateRegistryBuffer(
|
|
IN PPORT_REGISTRY_INFO PortContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the port driver to allocate a registry buffer of Length for the
|
|
miniport.
|
|
The caller should initialize Length before calling this routine.
|
|
|
|
Length is checked against a max. and alignment requirements and updated accordingly, if
|
|
necessary.
|
|
|
|
Arguments:
|
|
|
|
PortContext - Value used to identify the caller and instatiation of the caller.
|
|
|
|
Return Value:
|
|
|
|
The buffer field is updated or NULL if some error prevents the allocation.
|
|
Length is updated to reflect the actual size.
|
|
SUCCESS, INSUFFICIENT_RESOURCES, or BUSY if the miniport already has a buffer.
|
|
|
|
--*/
|
|
{
|
|
PUCHAR buffer = NULL;
|
|
ULONG length;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// The size must be correct.
|
|
//
|
|
ASSERT(PortContext->Size == sizeof(PORT_REGISTRY_INFO));
|
|
|
|
//
|
|
// Must be initialized via the init routine.
|
|
//
|
|
ASSERT(PortContext->Flags & PORT_REGISTRY_INFO_INITIALIZED );
|
|
|
|
//
|
|
// Can't be here twice.
|
|
//
|
|
ASSERT((PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED) == 0);
|
|
|
|
//
|
|
// Capture the length.
|
|
//
|
|
length = PortContext->LengthNeeded;
|
|
|
|
//
|
|
// See if the miniport is attempted a double allocate.
|
|
//
|
|
if (PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED) {
|
|
|
|
//
|
|
// This would say that there better be a buffer.
|
|
//
|
|
ASSERT(PortContext->Buffer);
|
|
|
|
//
|
|
// Buffer already outstanding, so don't allow this.
|
|
//
|
|
status = STATUS_DEVICE_BUSY;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Check the upper bound.
|
|
//
|
|
if (length > MAX_REGISTRY_BUFFER_SIZE) {
|
|
|
|
//
|
|
// The request is too large, reset it. The port driver or miniport will have
|
|
// to deal with the change.
|
|
//
|
|
length = MAX_REGISTRY_BUFFER_SIZE;
|
|
}
|
|
|
|
//
|
|
// Allocate the buffer.
|
|
//
|
|
buffer = ExAllocatePoolWithTag(NonPagedPool,
|
|
length,
|
|
PORT_TAG_REGISTRY_BUFFER);
|
|
if (buffer == NULL) {
|
|
|
|
//
|
|
// Set the caller's length to 0 as the allocation failed.
|
|
//
|
|
PortContext->AllocatedLength = 0;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Indicate that the allocation of Length was successful, and
|
|
// that the miniport has a registry buffer.
|
|
//
|
|
PortContext->Flags |= PORT_REGISTRY_BUFFER_ALLOCATED;
|
|
PortContext->Buffer = buffer;
|
|
PortContext->AllocatedLength = length;
|
|
|
|
//
|
|
// Zero it for them to be nice.
|
|
//
|
|
RtlZeroMemory(buffer, length);
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PortFreeRegistryBuffer(
|
|
IN PPORT_REGISTRY_INFO PortContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees the buffer allocated via PortAllocateRegistryBuffer.
|
|
|
|
Arguments:
|
|
|
|
PortContext - Value used to identify the caller and instatiation of the caller.
|
|
|
|
Return Value:
|
|
|
|
INVALID_PARAMETER if the buffer isn't already allocated.
|
|
SUCCESS
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// The size must be correct.
|
|
//
|
|
ASSERT(PortContext->Size == sizeof(PORT_REGISTRY_INFO));
|
|
|
|
//
|
|
// Must be initialized via the init routine.
|
|
//
|
|
ASSERT(PortContext->Flags & PORT_REGISTRY_INFO_INITIALIZED );
|
|
|
|
//
|
|
// Can't be here, unless a buffer has been allocated.
|
|
//
|
|
ASSERT(PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED);
|
|
|
|
//
|
|
// If it's not allocated, return an error.
|
|
//
|
|
if ((PortContext->Flags & PORT_REGISTRY_BUFFER_ALLOCATED) == 0) {
|
|
|
|
ASSERT(PortContext->Buffer == NULL);
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Poison the buffer to catch poorly-written miniports.
|
|
//
|
|
RtlZeroMemory(PortContext->Buffer, PortContext->AllocatedLength);
|
|
|
|
//
|
|
// Free the buffer.
|
|
//
|
|
ExFreePool(PortContext->Buffer);
|
|
|
|
//
|
|
// Indicate that it's gone.
|
|
//
|
|
PortContext->Flags &= ~PORT_REGISTRY_BUFFER_ALLOCATED;
|
|
PortContext->AllocatedLength = 0;
|
|
PortContext->Buffer = NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
ULONG
|
|
WCharToAscii(
|
|
OUT PUCHAR Destination,
|
|
IN PWCHAR Source,
|
|
IN ULONG BufferSize
|
|
)
|
|
/*+++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to convert the Source buffer into ASCII.
|
|
|
|
NOTE: BufferSize should include the NULL-Terminator, while the return value does not.
|
|
|
|
Arguements:
|
|
|
|
Destination - ASCII buffer to place the converted values.
|
|
Source - WCHAR buffer containing the string to convert.
|
|
BufferSize - Size, in bytes, of Destination.
|
|
|
|
Return Value:
|
|
|
|
The converted buffer and the count of converted chars. The NULL-termination
|
|
isn't included.
|
|
|
|
--*/
|
|
{
|
|
ULONG convertedCount = 0;
|
|
ULONG i;
|
|
|
|
RtlZeroMemory(Destination, BufferSize);
|
|
|
|
if (Source) {
|
|
|
|
//
|
|
// Run through the Source buffer and convert the WCHAR to ASCII, placing
|
|
// the converted value in Destination. Ensure that the destination buffer
|
|
// isn't overflowed.
|
|
//
|
|
for (i = 0; (i < (BufferSize - 1)) && (*Source); i++, convertedCount++) {
|
|
*Destination = (UCHAR)*Source;
|
|
Destination++;
|
|
Source++;
|
|
}
|
|
}
|
|
|
|
return convertedCount;
|
|
}
|
|
|
|
|
|
ULONG
|
|
AsciiToWChar(
|
|
IN PWCHAR Destination,
|
|
IN PUCHAR Source,
|
|
IN ULONG BufferSize
|
|
)
|
|
/*+++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to convert the Source buffer into WCHAR.
|
|
|
|
NOTE: BufferSize should include the NULL-Terminator, while the return value does not.
|
|
|
|
Arguements:
|
|
|
|
Destination - WCHAR buffer to place the converted values.
|
|
Source - ASCII buffer containing the string to convert.
|
|
BufferSize - Size, in bytes, of Destination.
|
|
|
|
Return Value:
|
|
|
|
The converted buffer and the count of converted chars. The NULL-termination
|
|
isn't included.
|
|
|
|
--*/
|
|
{
|
|
ULONG convertedCount = 0;
|
|
ULONG i;
|
|
|
|
RtlZeroMemory(Destination, BufferSize);
|
|
|
|
if (Source) {
|
|
|
|
//
|
|
// Run through source buffer and convert the ascii values to WCHAR and put
|
|
// the convert into Destination. Ensure that neither source nor dest are
|
|
// overflowed.
|
|
//
|
|
for (i = 0; (i < (BufferSize - 1)) && (*Source); i++, convertedCount++) {
|
|
*Destination = (WCHAR)*Source;
|
|
Destination++;
|
|
Source++;
|
|
}
|
|
}
|
|
return convertedCount;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PortAsciiToUnicode(
|
|
IN PUCHAR AsciiString,
|
|
OUT PUNICODE_STRING UnicodeString
|
|
)
|
|
{
|
|
ANSI_STRING ansiString;
|
|
|
|
//
|
|
// Convert ValueName to Unicode.
|
|
//
|
|
RtlInitAnsiString(&ansiString, AsciiString);
|
|
return RtlAnsiStringToUnicodeString(UnicodeString, &ansiString, TRUE);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PortpBinaryReadCallBack(
|
|
IN PWSTR ValueName,
|
|
IN ULONG Type,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the callback function for handling REG_BINARY reads. It will determine
|
|
whether the buffer in the PORT_REGISTRY_INFO is of sufficient size to handle the data,
|
|
and copy it over, if necessary. Otherwise the data length needed is updated.
|
|
|
|
Arguments:
|
|
|
|
ValueName - The name of the data to be returned.
|
|
Type - The reg. data type for this request.
|
|
ValueLength - Size, in bytes, of ValueData
|
|
Context - Not used.
|
|
PortContext - Blob containing the miniports buffer and it's size.
|
|
|
|
Return Value:
|
|
|
|
SUCCESS or BUFFER_TOO_SMALL (which unfortunately gets updated by the RTL function to
|
|
SUCCESS. InternalStatus is updated to the real status and the length field within
|
|
the REGISTRY_INFO struct. is updated.
|
|
|
|
--*/
|
|
{
|
|
PPORT_REGISTRY_INFO portContext = EntryContext;
|
|
PUCHAR currentBuffer;
|
|
NTSTATUS status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
//
|
|
// Determine whether the supplied buffer is big enough to hold the data.
|
|
//
|
|
if (portContext->CurrentLength >= BufferLength) {
|
|
|
|
//
|
|
// Determine the correct offset into the buffer.
|
|
//
|
|
currentBuffer = portContext->Buffer + portContext->Offset;
|
|
|
|
//
|
|
// The Rtl routine will free it's buffer, so get the data now.
|
|
//
|
|
RtlCopyMemory(currentBuffer, Buffer, BufferLength);
|
|
|
|
//
|
|
// Update the status to show the data in the buffer is valid.
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Update the length. This will either tell them how big the buffer
|
|
// should be, or how large the returned data actually is.
|
|
// The Read routine will handle the rest.
|
|
//
|
|
portContext->CurrentLength = BufferLength;
|
|
portContext->InternalStatus = status;
|
|
|
|
//
|
|
// Return the status to the Read routine.
|
|
//
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PortRegistryRead(
|
|
IN PUNICODE_STRING RegistryKeyName,
|
|
IN PUNICODE_STRING ValueName,
|
|
IN ULONG Type,
|
|
IN PPORT_REGISTRY_INFO PortContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used by the portdriver to read the info. at ValueName from the regkey
|
|
|
|
This assumes that the data is a REG_SZ, REG_DWORD, or REG_BINARY only.
|
|
REG_SZ data is converted into a NULL-terminiated ASCII string from the UNICODE.
|
|
DWORD and BINARY data are directly copied into the caller's buffer if it's of
|
|
correct size.
|
|
|
|
Arguments:
|
|
|
|
RegistryKeyName - The absolute key name where ValueName lives.
|
|
ValueName - The name of the data to be returned.
|
|
Type - The reg. data type for this request.
|
|
PortContext - Blob containing the miniports buffer and it's size.
|
|
|
|
Return Value:
|
|
|
|
STATUS of the registry routines, INSUFFICIENT_RESOURCES, or BUFFER_TOO_SMALL.
|
|
If TOO_SMALL, LengthNeeded within the PortContext is updated to reflect the size needed.
|
|
|
|
--*/
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE queryTable[2];
|
|
WCHAR defaultData[] = { L"\0" };
|
|
ULONG defaultUlong = (ULONG)-1;
|
|
UNICODE_STRING unicodeString;
|
|
NTSTATUS status;
|
|
ULONG length;
|
|
PUCHAR currentBuffer;
|
|
|
|
RtlZeroMemory(queryTable, sizeof(queryTable));
|
|
|
|
//
|
|
// Calculate the actual buffer location where this data should go.
|
|
// This presupposes that the port-driver has done all the validation, otherwise
|
|
// this will be blindly copying into who-knows-where.
|
|
//
|
|
currentBuffer = PortContext->Buffer + PortContext->Offset;
|
|
|
|
//
|
|
// Looking for what lives at ValueName.
|
|
//
|
|
queryTable[0].Name = ValueName->Buffer;
|
|
|
|
//
|
|
// Indicate that there is no call-back routine and to return everything as one big
|
|
// blob.
|
|
//
|
|
queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
|
|
|
|
//
|
|
// Handle setting up for the various types that are supported.
|
|
//
|
|
if (Type == REG_SZ) {
|
|
|
|
RtlZeroMemory(&unicodeString, sizeof(UNICODE_STRING));
|
|
|
|
//
|
|
// Local storage for the returned data. The routine will allocate the buffer
|
|
// and set Length.
|
|
//
|
|
queryTable[0].EntryContext = &unicodeString;
|
|
queryTable[0].DefaultData = defaultData;
|
|
queryTable[0].DefaultLength = sizeof(defaultData);
|
|
|
|
} else if (Type == REG_DWORD) {
|
|
|
|
//
|
|
// The data will be placed in the first ulong of the caller's
|
|
// buffer.
|
|
//
|
|
queryTable[0].EntryContext = currentBuffer;
|
|
queryTable[0].DefaultData = &defaultUlong;
|
|
queryTable[0].DefaultLength = sizeof(ULONG);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Clear the flags because we need a callback to determine
|
|
// the real size of the binary data.
|
|
//
|
|
queryTable[0].Flags = 0;
|
|
queryTable[0].QueryRoutine = PortpBinaryReadCallBack;
|
|
queryTable[0].EntryContext = PortContext;
|
|
queryTable[0].DefaultData = &defaultUlong;
|
|
queryTable[0].DefaultLength = sizeof(ULONG);
|
|
}
|
|
|
|
//
|
|
// Set the type.
|
|
//
|
|
queryTable[0].DefaultType = Type;
|
|
|
|
//
|
|
// Call the query routine. This will either be direct, or result in the callback
|
|
// function getting invoked.
|
|
//
|
|
status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryKeyName->Buffer,
|
|
queryTable,
|
|
NULL,
|
|
NULL);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if (Type == REG_SZ) {
|
|
|
|
//
|
|
// Have their data. Now figure out whether it fits. The Query function allocates
|
|
// the unicode string buffer.
|
|
//
|
|
if ((unicodeString.Length) &&
|
|
((unicodeString.Length / sizeof(WCHAR)) <= PortContext->CurrentLength)) {
|
|
|
|
//
|
|
// Magically convert.
|
|
//
|
|
length = WCharToAscii(currentBuffer,
|
|
unicodeString.Buffer,
|
|
PortContext->CurrentLength);
|
|
|
|
//
|
|
// Set the length of the buffer.
|
|
//
|
|
PortContext->CurrentLength = length;
|
|
|
|
} else {
|
|
ASSERT(unicodeString.Length);
|
|
|
|
//
|
|
// Update the Length to indicate how big it should actually be.
|
|
//
|
|
PortContext->LengthNeeded = (unicodeString.Length + 1) / sizeof(WCHAR);
|
|
PortContext->CurrentLength = 0;
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
//
|
|
// Free our string, as the data has already been copied, or won't be copied
|
|
// into the caller's buffer.
|
|
//
|
|
ExFreePool(unicodeString.Buffer);
|
|
|
|
} else if (Type == REG_DWORD) {
|
|
|
|
//
|
|
// The data should already be there.
|
|
//
|
|
PortContext->CurrentLength = sizeof(ULONG);
|
|
|
|
} else {
|
|
|
|
//
|
|
// The Rtl routine has this annoying effect of fixing up BUFFER_TOO_SMALL
|
|
// into SUCCESS. Check for this case.
|
|
//
|
|
if (PortContext->InternalStatus == STATUS_BUFFER_TOO_SMALL) {
|
|
|
|
//
|
|
// Reset the status correctly for the caller.
|
|
//
|
|
status = PortContext->InternalStatus;
|
|
|
|
//
|
|
// Update length needed, so that the miniport can realloc.
|
|
//
|
|
PortContext->LengthNeeded = PortContext->CurrentLength;
|
|
PortContext->CurrentLength = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// The callback did all the necessary work.
|
|
//
|
|
NOTHING;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Indicate to the caller that the error is NOT due to a length mismatch or
|
|
// that the Buffer is too small. The difference is that if too small, the callback
|
|
// routine adjusted CurrentLength.
|
|
//
|
|
PortContext->LengthNeeded = PortContext->CurrentLength;
|
|
PortContext->CurrentLength = 0;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PortRegistryWrite(
|
|
IN PUNICODE_STRING RegistryKeyName,
|
|
IN PUNICODE_STRING ValueName,
|
|
IN ULONG Type,
|
|
IN PPORT_REGISTRY_INFO PortContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used by the port-driver to write the contents of Buffer to ValueName
|
|
which is located at the reg. key RegistryKeyName.
|
|
|
|
Buffer is first converted to UNICODE then the write takes place.
|
|
|
|
Arguments:
|
|
|
|
RegistryKeyName - The absolute path to the key name.
|
|
ValueName - The name of the data to be written.
|
|
Type - The reg. data type for this operation.
|
|
PortContext - Blob containing the miniports buffer and it's size.
|
|
|
|
Return Value:
|
|
|
|
STATUS from the registry routines, or INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeString;
|
|
ULONG bufferLength;
|
|
PUCHAR currentBuffer;
|
|
LONG offset;
|
|
ULONG length;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Determine whether the field exists.
|
|
//
|
|
status = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryKeyName->Buffer);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// The key doesn't exist. Create it.
|
|
//
|
|
status = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryKeyName->Buffer);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Can't go on. Return the error to the port-driver and it can figure
|
|
// out what best to do.
|
|
//
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Calculate the actual buffer location where this data lives.
|
|
// This presupposes that the port-driver has done all the validation.
|
|
//
|
|
currentBuffer = PortContext->Buffer + PortContext->Offset;
|
|
|
|
if (Type == REG_SZ) {
|
|
|
|
//
|
|
// Determine the size needed for the WCHAR.
|
|
//
|
|
bufferLength = PortContext->CurrentLength * sizeof(WCHAR);
|
|
|
|
//
|
|
// Allocate a buffer to build the converted data in.
|
|
//
|
|
unicodeString.Buffer = ExAllocatePool(NonPagedPool, bufferLength + sizeof(UNICODE_NULL));
|
|
if (unicodeString.Buffer == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(unicodeString.Buffer, bufferLength + sizeof(UNICODE_NULL));
|
|
|
|
//
|
|
// Set the lengths.
|
|
//
|
|
unicodeString.MaximumLength = (USHORT)(bufferLength + sizeof(UNICODE_NULL));
|
|
unicodeString.Length = (USHORT)bufferLength;
|
|
|
|
|
|
//
|
|
// Convert it.
|
|
//
|
|
length = AsciiToWChar(unicodeString.Buffer,
|
|
currentBuffer,
|
|
unicodeString.Length);
|
|
|
|
//
|
|
// Length is now set for the call below. Get the buffer by resetting
|
|
// currentbuffer to that of the unicode string's.
|
|
//
|
|
currentBuffer = (PUCHAR)unicodeString.Buffer;
|
|
|
|
} else if (Type == REG_DWORD){
|
|
|
|
//
|
|
// always this size.
|
|
//
|
|
length = sizeof(ULONG);
|
|
|
|
} else {
|
|
|
|
//
|
|
// For BINARY use the passed in buffer (currentBuffer) and length.
|
|
//
|
|
length = PortContext->CurrentLength;
|
|
}
|
|
|
|
//
|
|
// Write the data to the specified key/Value
|
|
//
|
|
status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
|
|
RegistryKeyName->Buffer,
|
|
ValueName->Buffer,
|
|
Type,
|
|
currentBuffer,
|
|
length);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PortBuildRegKeyName(
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN OUT PUNICODE_STRING KeyName,
|
|
IN ULONG PortNumber,
|
|
IN ULONG Global
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will build the registry keyname to the miniport's
|
|
Device(N) key based on RegistryPath and whether the key is for global miniport
|
|
data, or specific to one scsiN.
|
|
|
|
Arguments:
|
|
|
|
RegistryPath - The path to the miniport's service key.
|
|
KeyName - Storage for the whole path.
|
|
PortNumber - The adapter ordinal. Valid only if Global is FALSE.
|
|
Global - Indicates whether the Device or Device(N) path should be built.
|
|
|
|
Return Value:
|
|
|
|
SUCCESS - KeyName is valid.
|
|
INSUFFICIENT_RESOURCES
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeValue;
|
|
UNICODE_STRING tempKeyName;
|
|
ANSI_STRING ansiKeyName;
|
|
ULONG maxLength;
|
|
NTSTATUS status;
|
|
UCHAR paramsBuffer[24];
|
|
|
|
//
|
|
// If this is global, it represents ALL adapters being controlled by
|
|
// the miniport. Otherwise, it's the scsiN key only.
|
|
//
|
|
if (Global) {
|
|
|
|
RtlInitAnsiString(&ansiKeyName, "\\Parameters\\Device");
|
|
RtlAnsiStringToUnicodeString(&tempKeyName, &ansiKeyName, TRUE);
|
|
} else {
|
|
|
|
//
|
|
// Get the scsiport'N'.
|
|
//
|
|
sprintf(paramsBuffer, "\\Parameters\\Device%d", PortNumber);
|
|
RtlInitAnsiString(&ansiKeyName, paramsBuffer);
|
|
RtlAnsiStringToUnicodeString(&tempKeyName, &ansiKeyName, TRUE);
|
|
}
|
|
|
|
//
|
|
// The total length will be the size of the path to <services> plus the parameters\device
|
|
// string. Add enough for a NULL at the end.
|
|
//
|
|
maxLength = RegistryPath->MaximumLength + tempKeyName.MaximumLength + 2;
|
|
KeyName->Buffer = ExAllocatePool(NonPagedPool, maxLength);
|
|
if (KeyName->Buffer == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(KeyName->Buffer, maxLength);
|
|
|
|
//
|
|
// Clone the Reg.Path.
|
|
//
|
|
KeyName->MaximumLength = (USHORT)maxLength;
|
|
RtlCopyUnicodeString(KeyName,
|
|
RegistryPath);
|
|
|
|
//
|
|
// Have a copy of the path to the services name. Add the rest of the keyname
|
|
// to it.
|
|
//
|
|
status = RtlAppendUnicodeStringToString(KeyName, &tempKeyName);
|
|
|
|
//
|
|
// Free the buffer allocated above.
|
|
//
|
|
RtlFreeUnicodeString(&tempKeyName);
|
|
|
|
return status;
|
|
}
|
|
|