Persist Settings in Regsitry on Windows (#1242)

* Implement OpenThread Setting Interface

* Update the otPlatSettingDelete comment to indicate it doesn't maintain order.
This commit is contained in:
Nick Banks
2017-02-16 13:52:44 -08:00
committed by Jonathan Hui
parent 87bbf4a83a
commit 8ca35de7b8
4 changed files with 464 additions and 36 deletions
+5
View File
@@ -206,6 +206,11 @@ typedef struct _MS_FILTER
KEVENT EventWorkerThreadProcessIrp;
KEVENT EventWorkerThreadEnergyScanComplete;
//
// OpenThread Settings Management
//
HANDLE otSettingsRegKey;
//
// OpenThread state management
//
+448 -31
View File
@@ -39,30 +39,417 @@ void otPlatSettingsInit(otInstance *otCtx)
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
DECLARE_CONST_UNICODE_STRING(SubKeyName, L"OpenThread");
OBJECT_ATTRIBUTES attributes;
ULONG disposition;
InitializeObjectAttributes(
&attributes,
(PUNICODE_STRING)&SubKeyName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
pFilter->InterfaceRegKey,
NULL);
// Create/Open the 'OpenThread' sub key
NTSTATUS status =
ZwCreateKey(
&pFilter->otSettingsRegKey,
KEY_ALL_ACCESS,
&attributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
&disposition);
NT_ASSERT(NT_SUCCESS(status));
if (!NT_SUCCESS(status))
{
LogError(DRIVER_DEFAULT, "ZwCreateKey for 'OpenThread' key failed, %!STATUS!", status);
}
}
uint16_t FilterCountSettings(_In_ PMS_FILTER pFilter, uint16_t aKey)
{
HANDLE regKey = NULL;
OBJECT_ATTRIBUTES attributes;
DECLARE_UNICODE_STRING_SIZE(Name, 8);
UCHAR InfoBuffer[128] = {0};
PKEY_FULL_INFORMATION pInfo = (PKEY_FULL_INFORMATION)InfoBuffer;
ULONG InfoLength = sizeof(InfoBuffer);
// Convert 'aKey' to a string
RtlIntegerToUnicodeString((ULONG)aKey, 16, &Name);
InitializeObjectAttributes(
&attributes,
&Name,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
pFilter->otSettingsRegKey,
NULL);
// Open the registry key
NTSTATUS status =
ZwOpenKey(
&regKey,
KEY_ALL_ACCESS,
&attributes);
if (!NT_SUCCESS(status))
{
// Key doesn't exist, return a count of 0
goto error;
}
// Query the key info from the registry
status =
ZwQueryKey(
regKey,
KeyValueFullInformation,
pInfo,
InfoLength,
&InfoLength);
if (!NT_SUCCESS(status))
{
LogError(DRIVER_DEFAULT, "ZwQueryKey for %S value failed, %!STATUS!", Name.Buffer, status);
goto error;
}
error:
if (regKey) ZwClose(regKey);
return (uint16_t)pInfo->Values;
}
NTSTATUS FilterReadSetting(_In_ PMS_FILTER pFilter, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
{
HANDLE regKey = NULL;
OBJECT_ATTRIBUTES attributes;
DECLARE_UNICODE_STRING_SIZE(Name, 20);
PKEY_VALUE_PARTIAL_INFORMATION pInfo = NULL;
ULONG InfoLength = sizeof(*pInfo) + *aValueLength;
// Convert 'aKey' to a string
RtlIntegerToUnicodeString((ULONG)aKey, 16, &Name);
InitializeObjectAttributes(
&attributes,
&Name,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
pFilter->otSettingsRegKey,
NULL);
// Open the registry key
NTSTATUS status =
ZwOpenKey(
&regKey,
KEY_ALL_ACCESS,
&attributes);
if (!NT_SUCCESS(status))
{
// Key doesn't exist
goto error;
}
// Convert 'aIndex' to a string
RtlIntegerToUnicodeString((ULONG)aIndex, 16, &Name);
// Allocate buffer for query
pInfo = FILTER_ALLOC_MEM(pFilter->FilterHandle, InfoLength);
if (pInfo == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto error;
}
// Query the data
status = ZwQueryValueKey(
regKey,
&Name,
KeyValuePartialInformation,
pInfo,
InfoLength,
&InfoLength);
if (!NT_SUCCESS(status))
{
LogVerbose(DRIVER_DEFAULT, "ZwQueryValueKey for %S value failed, %!STATUS!", Name.Buffer, status);
goto error;
}
NT_ASSERT(*aValueLength >= pInfo->DataLength);
*aValueLength = (uint16_t)pInfo->DataLength;
if (aValue)
{
memcpy(aValue, pInfo->Data, pInfo->DataLength);
}
error:
if (pInfo) FILTER_FREE_MEM(pInfo);
if (regKey) ZwClose(regKey);
return status;
}
NTSTATUS FilterWriteSetting(_In_ PMS_FILTER pFilter, uint16_t aKey, int aIndex, const uint8_t *aValue, uint16_t aValueLength)
{
HANDLE regKey = NULL;
OBJECT_ATTRIBUTES attributes;
DECLARE_UNICODE_STRING_SIZE(Name, 20);
// Convert 'aKey' to a string
RtlIntegerToUnicodeString((ULONG)aKey, 16, &Name);
InitializeObjectAttributes(
&attributes,
&Name,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
pFilter->otSettingsRegKey,
NULL);
// Create/Open the registry key
NTSTATUS status =
ZwCreateKey(
&regKey,
KEY_ALL_ACCESS,
&attributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
NT_ASSERT(NT_SUCCESS(status));
if (!NT_SUCCESS(status))
{
LogError(DRIVER_DEFAULT, "ZwCreateKey for %S key failed, %!STATUS!", Name.Buffer, status);
goto error;
}
// Convert 'aIndex' to a string
RtlIntegerToUnicodeString((ULONG)aIndex, 16, &Name);
// Write the data to the registry
status =
ZwSetValueKey(
regKey,
&Name,
0,
REG_BINARY,
(PVOID)aValue,
aValueLength);
if (!NT_SUCCESS(status))
{
LogError(DRIVER_DEFAULT, "ZwSetValueKey for %S value failed, %!STATUS!", Name.Buffer, status);
goto error;
}
error:
if (regKey) ZwClose(regKey);
return status;
}
NTSTATUS FilterDeleteSetting(_In_ PMS_FILTER pFilter, uint16_t aKey, int aIndex)
{
HANDLE regKey = NULL;
OBJECT_ATTRIBUTES attributes;
DECLARE_UNICODE_STRING_SIZE(Name, 20);
// Convert 'aKey' to a string
RtlIntegerToUnicodeString((ULONG)aKey, 16, &Name);
InitializeObjectAttributes(
&attributes,
&Name,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
pFilter->otSettingsRegKey,
NULL);
// Open the registry key
NTSTATUS status =
ZwOpenKey(
&regKey,
KEY_ALL_ACCESS,
&attributes);
if (!NT_SUCCESS(status))
{
// Key doesn't exist
goto error;
}
// If 'aIndex' is -1 then delete the whole key, otherwise delete the individual value
if (aIndex == -1)
{
// Delete the registry key
status = ZwDeleteKey(regKey);
}
else
{
UCHAR KeyInfoBuffer[128] = { 0 };
PKEY_FULL_INFORMATION pKeyInfo = (PKEY_FULL_INFORMATION)KeyInfoBuffer;
ULONG KeyInfoLength = sizeof(KeyInfoBuffer);
// When deleting an individual value, since order doesn't matter, we will actually
// copy the last value over the one being deleted and then delete the last value; so
// we maintain a contiguous list of numbered values
// Query the number of values
// Note: Can't use helper function because we already have the key open
status =
ZwQueryKey(
regKey,
KeyValueFullInformation,
pKeyInfo,
KeyInfoLength,
&KeyInfoLength);
if (!NT_SUCCESS(status))
{
LogError(DRIVER_DEFAULT, "ZwQueryKey for %S value failed, %!STATUS!", Name.Buffer, status);
goto error;
}
if ((ULONG)aIndex >= pKeyInfo->Values)
{
// Attempt to delete beyond the end of the list
status = STATUS_OBJECT_NAME_NOT_FOUND;
goto error;
}
else if (pKeyInfo->Values == 1)
{
// Deleting the only value on the key, go ahead and delete the entire key
status = ZwDeleteKey(regKey);
}
else if (pKeyInfo->Values - 1 != (ULONG)aIndex)
{
// We aren't deleting the last value so we need to copy the last value
// over this one, and then delete the last one.
PKEY_VALUE_PARTIAL_INFORMATION pValueInfo = NULL;
ULONG ValueInfoLength = 0;
// Convert pKeyInfo->Values-1 to a string
RtlIntegerToUnicodeString(pKeyInfo->Values - 1, 16, &Name);
// Query the key data buffer size
status = ZwQueryValueKey(
regKey,
&Name,
KeyValuePartialInformation,
pValueInfo,
0,
&ValueInfoLength);
NT_ASSERT(status != STATUS_SUCCESS);
if (status != STATUS_BUFFER_TOO_SMALL)
{
LogVerbose(DRIVER_DEFAULT, "ZwQueryValueKey for %S value failed, %!STATUS!", Name.Buffer, status);
goto error;
}
pValueInfo = FILTER_ALLOC_MEM(pFilter->FilterHandle, ValueInfoLength);
if (pValueInfo == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto error;
}
// Query the data buffer
status = ZwQueryValueKey(
regKey,
&Name,
KeyValuePartialInformation,
pValueInfo,
ValueInfoLength,
&ValueInfoLength);
if (!NT_SUCCESS(status))
{
LogError(DRIVER_DEFAULT, "ZwQueryValueKey for %S value failed, %!STATUS!", Name.Buffer, status);
goto cleanup;
}
// Delete the registry value
status =
ZwDeleteValueKey(
regKey,
&Name);
if (!NT_SUCCESS(status))
{
LogError(DRIVER_DEFAULT, "ZwDeleteValueKey for %S value failed, %!STATUS!", Name.Buffer, status);
goto cleanup;
}
// Convert 'aIndex' to a string
RtlIntegerToUnicodeString((ULONG)aIndex, 16, &Name);
// Write the data to the registry key we are deleting
status =
ZwSetValueKey(
regKey,
&Name,
0,
REG_BINARY,
(PVOID)pValueInfo->Data,
pValueInfo->DataLength);
if (!NT_SUCCESS(status))
{
LogError(DRIVER_DEFAULT, "ZwSetValueKey for %S value failed, %!STATUS!", Name.Buffer, status);
goto cleanup;
}
cleanup:
if (pValueInfo) FILTER_FREE_MEM(pValueInfo);
}
else
{
// Deleting the last value in the list (but not the only value)
// Just delete the value directly. No need to copy any others.
// Convert 'aIndex' to a string
RtlIntegerToUnicodeString((ULONG)aIndex, 16, &Name);
// Delete the registry value
status =
ZwDeleteValueKey(
regKey,
&Name);
}
}
error:
if (regKey) ZwClose(regKey);
return status;
}
ThreadError otPlatSettingsBeginChange(otInstance *otCtx)
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
UNREFERENCED_PARAMETER(otCtx);
return kThreadError_NotImplemented;
}
ThreadError otPlatSettingsCommitChange(otInstance *otCtx)
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
UNREFERENCED_PARAMETER(otCtx);
return kThreadError_NotImplemented;
}
ThreadError otPlatSettingsAbandonChange(otInstance *otCtx)
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
UNREFERENCED_PARAMETER(otCtx);
return kThreadError_NotImplemented;
}
@@ -70,49 +457,79 @@ ThreadError otPlatSettingsGet(otInstance *otCtx, uint16_t aKey, int aIndex, uint
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
UNREFERENCED_PARAMETER(aKey);
UNREFERENCED_PARAMETER(aIndex);
UNREFERENCED_PARAMETER(aValue);
UNREFERENCED_PARAMETER(aValueLength);
return kThreadError_NotImplemented;
NTSTATUS status =
FilterReadSetting(
pFilter,
aKey,
aIndex,
aValue,
aValueLength);
return NT_SUCCESS(status) ? kThreadError_None : kThreadError_NotFound;
}
ThreadError otPlatSettingsSet(otInstance *otCtx, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
UNREFERENCED_PARAMETER(aKey);
UNREFERENCED_PARAMETER(aValue);
UNREFERENCED_PARAMETER(aValueLength);
return kThreadError_NotImplemented;
NTSTATUS status =
FilterWriteSetting(
pFilter,
aKey,
0,
aValue,
aValueLength);
return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed;
}
ThreadError otPlatSettingsAdd(otInstance *otCtx, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
UNREFERENCED_PARAMETER(aKey);
UNREFERENCED_PARAMETER(aValue);
UNREFERENCED_PARAMETER(aValueLength);
return kThreadError_NotImplemented;
uint16_t count = FilterCountSettings(pFilter, aKey);
NTSTATUS status =
FilterWriteSetting(
pFilter,
aKey,
count,
aValue,
aValueLength);
return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed;
}
ThreadError otPlatSettingsDelete(otInstance *otCtx, uint16_t aKey, int aIndex)
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
UNREFERENCED_PARAMETER(aKey);
UNREFERENCED_PARAMETER(aIndex);
return kThreadError_NotImplemented;
NTSTATUS status =
FilterDeleteSetting(
pFilter,
aKey,
aIndex);
return NT_SUCCESS(status) ? kThreadError_None : kThreadError_Failed;
}
void otPlatSettingsWipe(otInstance *otCtx)
{
NT_ASSERT(otCtx);
PMS_FILTER pFilter = otCtxToFilter(otCtx);
UNREFERENCED_PARAMETER(pFilter);
// Delete the entire 'OpenThread' sub key
if (pFilter->otSettingsRegKey)
{
ZwDeleteKey(pFilter->otSettingsRegKey);
ZwClose(pFilter->otSettingsRegKey);
pFilter->otSettingsRegKey = NULL;
}
// Recreate and open the 'OpenThread' sub key
otPlatSettingsInit(otCtx);
}
+8
View File
@@ -168,6 +168,14 @@ otLwfUninitializeThreadMode(
if (pFilter->EventHighPrecisionTimer)
{
ExDeleteTimer(pFilter->EventHighPrecisionTimer, TRUE, FALSE, NULL);
pFilter->EventHighPrecisionTimer = NULL;
}
// Close handle to settings registry key
if (pFilter->otSettingsRegKey)
{
ZwClose(pFilter->otSettingsRegKey);
pFilter->otSettingsRegKey = NULL;
}
LogFuncExit(DRIVER_DEFAULT);
+3 -5
View File
@@ -230,11 +230,9 @@ ThreadError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_
/** This function deletes a specific value from the
* setting identified by aKey from the settings store.
*
* This is the only function which mutates the settings store
* that is required to maintain the relative order of the
* values associated with aKey. For example, if you have three
* items ordered (A, B, C) and you delete B, the resulting order
* is guaranteed to be (A, C).
* Note that the underlying implementation is not required
* to maintain the order of the items associated with a
* specific key.
*
* @param[in] aInstance
* The OpenThread instance structure.