mirror of
https://github.com/espressif/openthread.git
synced 2026-09-09 10:40:09 +00:00
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:
@@ -206,6 +206,11 @@ typedef struct _MS_FILTER
|
||||
KEVENT EventWorkerThreadProcessIrp;
|
||||
KEVENT EventWorkerThreadEnergyScanComplete;
|
||||
|
||||
//
|
||||
// OpenThread Settings Management
|
||||
//
|
||||
HANDLE otSettingsRegKey;
|
||||
|
||||
//
|
||||
// OpenThread state management
|
||||
//
|
||||
|
||||
@@ -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(
|
||||
®Key,
|
||||
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(
|
||||
®Key,
|
||||
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(
|
||||
®Key,
|
||||
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(
|
||||
®Key,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user