From 8ca35de7b846af5f36affa5580c97460b07a2ad0 Mon Sep 17 00:00:00 2001 From: Nick Banks Date: Thu, 16 Feb 2017 13:52:44 -0800 Subject: [PATCH] =?UTF-8?q?Persist=C2=A0Settings=20in=20Regsitry=20on=20Wi?= =?UTF-8?q?ndows=20(#1242)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement OpenThread Setting Interface * Update the otPlatSettingDelete comment to indicate it doesn't maintain order. --- examples/drivers/windows/otLwf/filter.h | 5 + examples/drivers/windows/otLwf/settings.c | 479 ++++++++++++++++++++-- examples/drivers/windows/otLwf/thread.c | 8 + include/platform/settings.h | 8 +- 4 files changed, 464 insertions(+), 36 deletions(-) diff --git a/examples/drivers/windows/otLwf/filter.h b/examples/drivers/windows/otLwf/filter.h index f835f2a03..24ce3c2fb 100644 --- a/examples/drivers/windows/otLwf/filter.h +++ b/examples/drivers/windows/otLwf/filter.h @@ -206,6 +206,11 @@ typedef struct _MS_FILTER KEVENT EventWorkerThreadProcessIrp; KEVENT EventWorkerThreadEnergyScanComplete; + // + // OpenThread Settings Management + // + HANDLE otSettingsRegKey; + // // OpenThread state management // diff --git a/examples/drivers/windows/otLwf/settings.c b/examples/drivers/windows/otLwf/settings.c index a3feb99db..09e8c8e8b 100644 --- a/examples/drivers/windows/otLwf/settings.c +++ b/examples/drivers/windows/otLwf/settings.c @@ -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); } diff --git a/examples/drivers/windows/otLwf/thread.c b/examples/drivers/windows/otLwf/thread.c index 093860e33..d0d59f32f 100644 --- a/examples/drivers/windows/otLwf/thread.c +++ b/examples/drivers/windows/otLwf/thread.c @@ -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); diff --git a/include/platform/settings.h b/include/platform/settings.h index f32c6b1c7..8657e9220 100644 --- a/include/platform/settings.h +++ b/include/platform/settings.h @@ -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.