diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 95c1c72f39..843cb90289 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -1024,6 +1024,26 @@ menu "LWIP" endchoice + choice LWIP_HOOK_IP6_SELECT_SRC_ADDR + prompt "IPv6 source address selection Hook" + depends on LWIP_IPV6 + default LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE + help + Enables custom IPv6 source address selection. + Setting this to "default" provides weak implementation + stub that could be overwritten in application code. + Setting this to "custom" provides hook's declaration + only and expects the application to implement it. + + config LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE + bool "No hook declared" + config LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT + bool "Default (weak) implementation" + config LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM + bool "Custom implementation" + + endchoice + choice LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE prompt "Netconn external resolve Hook" default LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT if OPENTHREAD_DNS64_CLIENT diff --git a/components/lwip/lwip b/components/lwip/lwip index dafc822531..57c29648ff 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit dafc8225313a1ce00fb0b497d09f43ec7073857d +Subproject commit 57c29648ff40e2a19a51683717928aaf766a0495 diff --git a/components/lwip/port/hooks/lwip_default_hooks.c b/components/lwip/port/hooks/lwip_default_hooks.c index 2e92d36458..251aae0f48 100644 --- a/components/lwip/port/hooks/lwip_default_hooks.c +++ b/components/lwip/port/hooks/lwip_default_hooks.c @@ -41,7 +41,17 @@ const ip6_addr_t *__weak lwip_hook_nd6_get_gw(struct netif *netif, const ip6_add LWIP_UNUSED_ARG(netif); LWIP_UNUSED_ARG(dest); - return 0; + return NULL; +} +#endif + +#ifdef CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT +const ip_addr_t *__weak lwip_hook_ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest) +{ + LWIP_UNUSED_ARG(netif); + LWIP_UNUSED_ARG(dest); + + return NULL; } #endif diff --git a/components/lwip/port/include/lwip_default_hooks.h b/components/lwip/port/include/lwip_default_hooks.h index 6c273bd3ab..bdc54064a9 100644 --- a/components/lwip/port/include/lwip_default_hooks.h +++ b/components/lwip/port/include/lwip_default_hooks.h @@ -43,6 +43,12 @@ const ip6_addr_t *lwip_hook_nd6_get_gw(struct netif *netif, const ip6_addr_t *de #define LWIP_HOOK_ND6_GET_GW lwip_hook_nd6_get_gw #endif /* CONFIG_LWIP_HOOK_ND6_GET_GATEWAY... */ +#if defined(CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM) || defined(CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_DEFAULT) +const ip_addr_t *lwip_hook_ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest); + +#define LWIP_HOOK_IP6_SELECT_SRC_ADDR lwip_hook_ip6_select_source_address +#endif /* CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR... */ + #if defined(CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM) || defined(CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT) int lwip_hook_netconn_external_resolve(const char *name, ip_addr_t *addr, u8_t addrtype, err_t *err); diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index 7a40455ca5..26c3d5706a 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -16,7 +16,8 @@ if(CONFIG_OPENTHREAD_ENABLED) "private_include") set(src_dirs - "port" + "src" + "src/port" "openthread/examples/platforms/utils" "openthread/src/core/api" "openthread/src/core/common" @@ -57,6 +58,7 @@ if(CONFIG_OPENTHREAD_ENABLED) "openthread/examples/apps/ncp") list(APPEND exclude_srcs + "src/port/esp_openthread_state.c" "openthread/examples/apps/ncp/main.c" "openthread/src/core/api/backbone_router_api.cpp" "openthread/src/core/api/child_supervision_api.cpp" @@ -113,13 +115,13 @@ if(CONFIG_OPENTHREAD_ENABLED) if(CONFIG_OPENTHREAD_RADIO_NATIVE) list(APPEND exclude_srcs - "port/esp_openthread_radio_spinel.cpp" - "port/esp_spi_spinel_interface.cpp" - "port/esp_uart_spinel_interface.cpp" + "src/port/esp_openthread_radio_spinel.cpp" + "src/port/esp_spi_spinel_interface.cpp" + "src/port/esp_uart_spinel_interface.cpp" ) elseif(CONFIG_OPENTHREAD_RADIO_SPINEL_UART OR CONFIG_OPENTHREAD_RADIO_SPINEL_SPI) list(APPEND exclude_srcs - "port/esp_openthread_radio.c") + "src/port/esp_openthread_radio.c") endif() if(CONFIG_OPENTHREAD_BORDER_ROUTER) @@ -135,7 +137,7 @@ if(CONFIG_OPENTHREAD_ENABLED) if(NOT CONFIG_OPENTHREAD_DNS64_CLIENT) list(APPEND exclude_srcs - "port/esp_openthread_dns64.c") + "src/esp_openthread_dns64.c") endif() if(CONFIG_OPENTHREAD_FTD) @@ -173,7 +175,7 @@ idf_component_register(SRC_DIRS "${src_dirs}" REQUIRES esp_netif lwip driver LDFRAGMENTS linker.lf PRIV_REQUIRES console esp_event esp_partition esp_timer - ieee802154 mbedtls spi_flash) + ieee802154 mbedtls nvs_flash) if(CONFIG_OPENTHREAD_ENABLED) if(CONFIG_OPENTHREAD_RADIO) diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 03f154d11c..ff4ca35bb5 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -34,6 +34,40 @@ menu "OpenThread" bool "Debug logs" endchoice #OPENTHREAD_LOG_LEVEL + menu "Thread Operational Dataset" + config OPENTHREAD_NETWORK_NAME + string "OpenThread network name" + default "OpenThread-ESP" + + config OPENTHREAD_NETWORK_CHANNEL + int "OpenThread network channel" + range 11 26 + default 15 + + config OPENTHREAD_NETWORK_PANID + hex "OpenThread network pan id" + range 0 0xFFFE + default 0x1234 + + config OPENTHREAD_NETWORK_EXTPANID + string "OpenThread extended pan id" + default "dead00beef00cafe" + help + The OpenThread network extended pan id in hex string format + + config OPENTHREAD_NETWORK_MASTERKEY + string "OpenThread network key" + default "00112233445566778899aabbccddeeff" + help + The OpenThread network network key in hex string format + + config OPENTHREAD_NETWORK_PSKC + string "OpenThread pre-shared commissioner key" + default "104810e2315100afd6bc9215a6bfac53" + help + The OpenThread pre-shared commissioner key in hex string format + endmenu + config OPENTHREAD_LOG_LEVEL int depends on OPENTHREAD_ENABLED && !OPENTHREAD_LOG_LEVEL_DYNAMIC diff --git a/components/openthread/include/esp_openthread.h b/components/openthread/include/esp_openthread.h index f98f193d5c..9e5f39a59b 100644 --- a/components/openthread/include/esp_openthread.h +++ b/components/openthread/include/esp_openthread.h @@ -8,6 +8,7 @@ #include "esp_err.h" #include "esp_openthread_types.h" +#include "openthread/dataset.h" #include "openthread/error.h" #include "openthread/instance.h" #include "lwip/ip_addr.h" @@ -32,10 +33,23 @@ extern "C" { */ esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *init_config); +/** + * @brief Starts the Thread protocol operation and attaches to a Thread network. + * + * @param[in] datasetTlvs The operational dataset (TLV encoded), if it's NULL, the function will generate the dataset + * based on the configurations from kconfig. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on failures + * + */ +esp_err_t esp_openthread_auto_start(otOperationalDatasetTlvs *datasetTlvs); + /** * @brief Launches the OpenThread main loop. * - * @note Thie function will not return unless error happens when running the OpenThread stack. + * @note This function will not return unless error happens when running the OpenThread stack. * * @return * - ESP_OK on success diff --git a/components/openthread/include/esp_openthread_dns64.h b/components/openthread/include/esp_openthread_dns64.h index 8c8bb15795..22809b8560 100644 --- a/components/openthread/include/esp_openthread_dns64.h +++ b/components/openthread/include/esp_openthread_dns64.h @@ -12,6 +12,8 @@ #ifdef __cplusplus extern "C" { #endif +// The network data change callback sets the dns server address of index 0, while the CLI sets the dns server address of index 1. +#define OPENTHREAD_DNS_SERVER_INDEX 0 /** * @brief This function initiizes the dns64 client. diff --git a/components/openthread/include/esp_openthread_types.h b/components/openthread/include/esp_openthread_types.h index 5923814fb4..936dd6d542 100644 --- a/components/openthread/include/esp_openthread_types.h +++ b/components/openthread/include/esp_openthread_types.h @@ -14,8 +14,10 @@ #include "driver/gpio.h" #include "driver/spi_master.h" #include "driver/spi_slave.h" +#include "driver/uart.h" #include "hal/gpio_types.h" #include "hal/uart_types.h" +#include "openthread/thread.h" #ifdef __cplusplus extern "C" { @@ -28,6 +30,9 @@ extern "C" { typedef enum { OPENTHREAD_EVENT_START, /*!< OpenThread stack start */ OPENTHREAD_EVENT_STOP, /*!< OpenThread stack stop */ + OPENTHREAD_EVENT_DETACHED, /*!< OpenThread detached */ + OPENTHREAD_EVENT_ATTACHED, /*!< OpenThread attached */ + OPENTHREAD_EVENT_ROLE_CHANGED, /*!< OpenThread role changed */ OPENTHREAD_EVENT_IF_UP, /*!< OpenThread network interface up */ OPENTHREAD_EVENT_IF_DOWN, /*!< OpenThread network interface down */ OPENTHREAD_EVENT_GOT_IP6, /*!< OpenThread stack added IPv6 address */ @@ -46,6 +51,15 @@ typedef enum { */ ESP_EVENT_DECLARE_BASE(OPENTHREAD_EVENT); +/** + * @brief OpenThread role changed event data + * + */ +typedef struct { + otDeviceRole previous_role; /*!< Previous Thread role */ + otDeviceRole current_role; /*!< Current Thread role */ +} esp_openthread_role_changed_event_t; + /** * This structure represents a context for a select() based mainloop. * diff --git a/components/openthread/lib b/components/openthread/lib index fed28dde58..36cb2202e1 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit fed28dde58d5d4a46d3acc4935a23b43fe82b320 +Subproject commit 36cb2202e10b5ba7484654962ca9e3ceb51f6d51 diff --git a/components/openthread/port/esp_openthread.cpp b/components/openthread/port/esp_openthread.cpp deleted file mode 100644 index 5c0b34c4a8..0000000000 --- a/components/openthread/port/esp_openthread.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "esp_openthread.h" -#include "esp_check.h" -#include "esp_openthread_border_router.h" -#include "esp_openthread_common_macro.h" -#include "esp_openthread_dns64.h" -#include "esp_openthread_lock.h" -#include "esp_openthread_platform.h" -#include "esp_openthread_task_queue.h" -#include "esp_openthread_types.h" -#include "freertos/FreeRTOS.h" -#include "lwip/dns.h" -#include "openthread/instance.h" -#include "openthread/netdata.h" -#include "openthread/tasklet.h" - -esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *config) -{ - ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG, - "Failed to initialize OpenThread platform driver"); - esp_openthread_lock_acquire(portMAX_DELAY); - ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG, - "Failed to initialize OpenThread instance"); -#if CONFIG_OPENTHREAD_DNS64_CLIENT - ESP_RETURN_ON_ERROR(esp_openthread_dns64_client_init(), OT_PLAT_LOG_TAG, - "Failed to initialize OpenThread dns64 client"); -#endif - esp_openthread_lock_release(); - - return ESP_OK; -} - -esp_err_t esp_openthread_launch_mainloop(void) -{ - esp_openthread_mainloop_context_t mainloop; - otInstance *instance = esp_openthread_get_instance(); - esp_err_t error = ESP_OK; - - while (true) { - FD_ZERO(&mainloop.read_fds); - FD_ZERO(&mainloop.write_fds); - FD_ZERO(&mainloop.error_fds); - - mainloop.max_fd = -1; - mainloop.timeout.tv_sec = 10; - mainloop.timeout.tv_usec = 0; - - esp_openthread_lock_acquire(portMAX_DELAY); - esp_openthread_platform_update(&mainloop); - if (otTaskletsArePending(instance)) { - mainloop.timeout.tv_sec = 0; - mainloop.timeout.tv_usec = 0; - } - esp_openthread_lock_release(); - - if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds, - &mainloop.timeout) >= 0) { - esp_openthread_lock_acquire(portMAX_DELAY); - error = esp_openthread_platform_process(instance, &mainloop); - while (otTaskletsArePending(instance)) { - otTaskletsProcess(instance); - } - esp_openthread_lock_release(); - if (error != ESP_OK) { - ESP_LOGE(OT_PLAT_LOG_TAG, "esp_openthread_platform_process failed"); - break; - } - } else { - error = ESP_FAIL; - ESP_LOGE(OT_PLAT_LOG_TAG, "OpenThread system polling failed"); - break; - } - } - return error; -} - -esp_err_t esp_openthread_deinit(void) -{ - otInstanceFinalize(esp_openthread_get_instance()); - return esp_openthread_platform_deinit(); -} - -static void stub_task(void *context) -{ - // this is a empty function used for ot-task signal pending -} - -void otTaskletsSignalPending(otInstance *aInstance) -{ - esp_openthread_task_queue_post(stub_task, NULL); -} diff --git a/components/openthread/private_include/esp_openthread_netif_glue_priv.h b/components/openthread/private_include/esp_openthread_netif_glue_priv.h index 47e5134638..d5a9d1c072 100644 --- a/components/openthread/private_include/esp_openthread_netif_glue_priv.h +++ b/components/openthread/private_include/esp_openthread_netif_glue_priv.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,15 +14,6 @@ extern "C" { #endif -/** - * @brief The state handler to be called when OpenThread state changes - * - * @param[in] changed_flags The changed Openthread states - * @param[in] ctx A pointer to application-specific context - * - */ -void esp_openthread_netif_glue_state_callback(otChangedFlags changed_flags, void *ctx); - /** * @brief This function updates the netif fds and timeouts to the main loop. * diff --git a/components/openthread/private_include/esp_openthread_platform.h b/components/openthread/private_include/esp_openthread_platform.h index 4c7f4ddcb4..6919e914be 100644 --- a/components/openthread/private_include/esp_openthread_platform.h +++ b/components/openthread/private_include/esp_openthread_platform.h @@ -139,6 +139,13 @@ void esp_openthread_platform_update(esp_openthread_mainloop_context_t *mainloop) */ esp_err_t esp_openthread_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop); +/** + * @brief This function set the OpenThread storage name + * + * @param[in] name The OpenThread storage name. + * + */ +void esp_openthread_set_storage_name(const char *name); #ifdef __cplusplus } // end of extern "C" #endif diff --git a/components/openthread/private_include/esp_openthread_state.h b/components/openthread/private_include/esp_openthread_state.h new file mode 100644 index 0000000000..e2ee350805 --- /dev/null +++ b/components/openthread/private_include/esp_openthread_state.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief This function initiizes OpenThread state event post. + * + * @pram[in] instance The OpenThread instance + * + * @return + * - ESP_OK on success + * - ESP_FAIL if OpenThread state changed callback fails to be registered + * + */ +esp_err_t esp_openthread_state_event_init(otInstance *instance); + +#ifdef __cplusplus +} +#endif diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index 2cb8ede33c..f3ad6f268f 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -32,7 +32,7 @@ * When defined to 1, the platform MUST implement the otPlatFlash* APIs instead of the otPlatSettings* APIs. * */ -#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1 +#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 0 /** * @def OPENTHREAD_CONFIG_LOG_OUTPUT diff --git a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h index 7ecfbca1c1..f84a6f80eb 100644 --- a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h @@ -32,7 +32,7 @@ * When defined to 1, the platform MUST implement the otPlatFlash* APIs instead of the otPlatSettings* APIs. * */ -#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1 +#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 0 /** * @def OPENTHREAD_CONFIG_LOG_OUTPUT diff --git a/components/openthread/private_include/openthread-core-esp32x-radio-config.h b/components/openthread/private_include/openthread-core-esp32x-radio-config.h index f58432903b..8bb97355de 100644 --- a/components/openthread/private_include/openthread-core-esp32x-radio-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-radio-config.h @@ -31,7 +31,7 @@ * When defined to 1, the platform MUST implement the otPlatFlash* APIs instead of the otPlatSettings* APIs. * */ -#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 1 +#define OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE 0 /** * @def OPENTHREAD_CONFIG_LOG_OUTPUT diff --git a/components/openthread/src/esp_openthread.cpp b/components/openthread/src/esp_openthread.cpp new file mode 100644 index 0000000000..38f3511528 --- /dev/null +++ b/components/openthread/src/esp_openthread.cpp @@ -0,0 +1,199 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_openthread.h" +#include "esp_check.h" +#include "esp_openthread_border_router.h" +#include "esp_openthread_common_macro.h" +#include "esp_openthread_dns64.h" +#include "esp_openthread_lock.h" +#include "esp_openthread_platform.h" +#include "esp_openthread_state.h" +#include "esp_openthread_task_queue.h" +#include "esp_openthread_types.h" +#include "freertos/FreeRTOS.h" +#include "lwip/dns.h" +#include "openthread/instance.h" +#include "openthread/netdata.h" +#include "openthread/tasklet.h" +#include "openthread/thread.h" + +static int hex_digit_to_int(char hex) +{ + if ('A' <= hex && hex <= 'F') { + return 10 + hex - 'A'; + } + if ('a' <= hex && hex <= 'f') { + return 10 + hex - 'a'; + } + if ('0' <= hex && hex <= '9') { + return hex - '0'; + } + return -1; +} + +static size_t hex_string_to_binary(const char *hex_string, uint8_t *buf, size_t buf_size) +{ + int num_char = strlen(hex_string); + + if (num_char != buf_size * 2) { + return 0; + } + for (size_t i = 0; i < num_char; i += 2) { + int digit0 = hex_digit_to_int(hex_string[i]); + int digit1 = hex_digit_to_int(hex_string[i + 1]); + + if (digit0 < 0 || digit1 < 0) { + return 0; + } + buf[i / 2] = (digit0 << 4) + digit1; + } + + return buf_size; +} + +esp_err_t esp_openthread_init(const esp_openthread_platform_config_t *config) +{ + ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG, + "Failed to initialize OpenThread platform driver"); + esp_openthread_lock_acquire(portMAX_DELAY); + ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG, + "Failed to initialize OpenThread instance"); +#if CONFIG_OPENTHREAD_DNS64_CLIENT + ESP_RETURN_ON_ERROR(esp_openthread_dns64_client_init(), OT_PLAT_LOG_TAG, + "Failed to initialize OpenThread dns64 client"); +#endif +#if !CONFIG_OPENTHREAD_RADIO + ESP_RETURN_ON_ERROR(esp_openthread_state_event_init(esp_openthread_get_instance()), OT_PLAT_LOG_TAG, + "Failed to initialize OpenThread state event"); +#endif + esp_openthread_lock_release(); + + return ESP_OK; +} + +esp_err_t esp_openthread_auto_start(otOperationalDatasetTlvs *datasetTlvs) +{ + otInstance *instance = esp_openthread_get_instance(); + + if (datasetTlvs) { + ESP_RETURN_ON_FALSE(otDatasetSetActiveTlvs(instance, datasetTlvs) == OT_ERROR_NONE, ESP_FAIL, OT_PLAT_LOG_TAG, + "Failed to set OpenThread active dataset"); + } + else { + otOperationalDataset dataset; + size_t len = 0; + + memset(&dataset, 0, sizeof(otOperationalDataset)); + + // Active timestamp + dataset.mActiveTimestamp.mSeconds = 1; + dataset.mActiveTimestamp.mTicks = 0; + dataset.mActiveTimestamp.mAuthoritative = false; + dataset.mComponents.mIsActiveTimestampPresent = true; + + // Channel, Pan ID, Network Name + dataset.mChannel = CONFIG_OPENTHREAD_NETWORK_CHANNEL; + dataset.mComponents.mIsChannelPresent = true; + dataset.mPanId = CONFIG_OPENTHREAD_NETWORK_PANID; + dataset.mComponents.mIsPanIdPresent = true; + len = strlen(CONFIG_OPENTHREAD_NETWORK_NAME); + assert(len <= OT_NETWORK_NAME_MAX_SIZE); + memcpy(dataset.mNetworkName.m8, CONFIG_OPENTHREAD_NETWORK_NAME, len); + dataset.mComponents.mIsNetworkNamePresent = true; + + // Extended Pan ID + len = hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_EXTPANID, dataset.mExtendedPanId.m8, + sizeof(dataset.mExtendedPanId.m8)); + ESP_RETURN_ON_FALSE(len == sizeof(dataset.mExtendedPanId.m8), ESP_FAIL, OT_PLAT_LOG_TAG, + "Cannot convert OpenThread extended pan id"); + dataset.mComponents.mIsExtendedPanIdPresent = true; + + // Network Key + len = hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_MASTERKEY, dataset.mNetworkKey.m8, + sizeof(dataset.mNetworkKey.m8)); + ESP_RETURN_ON_FALSE(len == sizeof(dataset.mNetworkKey.m8), ESP_FAIL, OT_PLAT_LOG_TAG, + "Cannot convert OpenThread master key"); + dataset.mComponents.mIsNetworkKeyPresent = true; + + // PSKc + len = hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_PSKC, dataset.mPskc.m8, sizeof(dataset.mPskc.m8)); + ESP_RETURN_ON_FALSE(len == sizeof(dataset.mPskc.m8), ESP_FAIL, OT_PLAT_LOG_TAG, + "Cannot convert OpenThread pre-shared commissioner key"); + dataset.mComponents.mIsPskcPresent = true; + + ESP_RETURN_ON_FALSE(otDatasetSetActive(instance, &dataset) == OT_ERROR_NONE, ESP_FAIL, OT_PLAT_LOG_TAG, + "Failed to set OpenThread active dataset"); + } + + ESP_RETURN_ON_FALSE(otIp6SetEnabled(instance, true) == OT_ERROR_NONE, ESP_FAIL, OT_PLAT_LOG_TAG, + "Failed to enable OpenThread IPv6 interface"); + + ESP_RETURN_ON_FALSE(otThreadSetEnabled(instance, true) == OT_ERROR_NONE, ESP_FAIL, OT_PLAT_LOG_TAG, + "Failed to enable OpenThread"); + + return ESP_OK; +} + +esp_err_t esp_openthread_launch_mainloop(void) +{ + esp_openthread_mainloop_context_t mainloop; + otInstance *instance = esp_openthread_get_instance(); + esp_err_t error = ESP_OK; + + while (true) { + FD_ZERO(&mainloop.read_fds); + FD_ZERO(&mainloop.write_fds); + FD_ZERO(&mainloop.error_fds); + + mainloop.max_fd = -1; + mainloop.timeout.tv_sec = 10; + mainloop.timeout.tv_usec = 0; + + esp_openthread_lock_acquire(portMAX_DELAY); + esp_openthread_platform_update(&mainloop); + if (otTaskletsArePending(instance)) { + mainloop.timeout.tv_sec = 0; + mainloop.timeout.tv_usec = 0; + } + esp_openthread_lock_release(); + + if (select(mainloop.max_fd + 1, &mainloop.read_fds, &mainloop.write_fds, &mainloop.error_fds, + &mainloop.timeout) >= 0) { + esp_openthread_lock_acquire(portMAX_DELAY); + error = esp_openthread_platform_process(instance, &mainloop); + while (otTaskletsArePending(instance)) { + otTaskletsProcess(instance); + } + esp_openthread_lock_release(); + if (error != ESP_OK) { + ESP_LOGE(OT_PLAT_LOG_TAG, "esp_openthread_platform_process failed"); + break; + } + } else { + error = ESP_FAIL; + ESP_LOGE(OT_PLAT_LOG_TAG, "OpenThread system polling failed"); + break; + } + } + return error; +} + +esp_err_t esp_openthread_deinit(void) +{ + otInstanceFinalize(esp_openthread_get_instance()); + return esp_openthread_platform_deinit(); +} + +static void stub_task(void *context) +{ + // this is a empty function used for ot-task signal pending +} + +void otTaskletsSignalPending(otInstance *aInstance) +{ + esp_openthread_task_queue_post(stub_task, NULL); +} diff --git a/components/openthread/port/esp_openthread_cli.c b/components/openthread/src/esp_openthread_cli.c similarity index 100% rename from components/openthread/port/esp_openthread_cli.c rename to components/openthread/src/esp_openthread_cli.c diff --git a/components/openthread/port/esp_openthread_dns64.c b/components/openthread/src/esp_openthread_dns64.c similarity index 62% rename from components/openthread/port/esp_openthread_dns64.c rename to components/openthread/src/esp_openthread_dns64.c index cdece8334a..77be398886 100644 --- a/components/openthread/port/esp_openthread_dns64.c +++ b/components/openthread/src/esp_openthread_dns64.c @@ -5,6 +5,7 @@ */ #include "esp_openthread_dns64.h" +#include "esp_openthread_state.h" #include "esp_check.h" #include "esp_event.h" @@ -16,34 +17,9 @@ #include "lwip/dns.h" #define TAG "OT_DNS64" -// The network data change callback sets the dns server address of index 0, while the CLI sets the dns server address of index 1. -#define OPENTHREAD_DNS_SERVER_INDEX 0 - -static void esp_openthread_netdata_change_callback(otChangedFlags changed_flags, void *ctx) -{ - if (OT_CHANGED_THREAD_NETDATA & changed_flags) { - ip_addr_t dns_server_addr = *IP_ADDR_ANY; - if (esp_openthread_get_nat64_prefix(&dns_server_addr.u_addr.ip6) == ESP_OK) { - dns_server_addr.type = IPADDR_TYPE_V6; - dns_server_addr.u_addr.ip6.addr[3] = ipaddr_addr(CONFIG_OPENTHREAD_DNS_SERVER_ADDR); - const ip_addr_t *dnsserver = dns_getserver(OPENTHREAD_DNS_SERVER_INDEX); - if (memcmp(dnsserver, &dns_server_addr, sizeof(ip_addr_t)) != 0) { - ESP_LOGI(TAG, "Set dns server address: %s", ipaddr_ntoa(&dns_server_addr)); - dns_setserver(OPENTHREAD_DNS_SERVER_INDEX, &dns_server_addr); - if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_SET_DNS_SERVER, NULL, 0, 0) != ESP_OK) { - ESP_LOGE(TAG, "Failed to post OpenThread set DNS server event"); - } - } - } - } -} esp_err_t esp_openthread_dns64_client_init(void) { - otInstance *instance = esp_openthread_get_instance(); - ESP_RETURN_ON_FALSE(otSetStateChangedCallback(instance, esp_openthread_netdata_change_callback, NULL) == - OT_ERROR_NONE, - ESP_FAIL, TAG, "Failed to install network data change callback"); dns_setserver(OPENTHREAD_DNS_SERVER_INDEX, NULL); return ESP_OK; } diff --git a/components/openthread/port/esp_openthread_lock.c b/components/openthread/src/esp_openthread_lock.c similarity index 100% rename from components/openthread/port/esp_openthread_lock.c rename to components/openthread/src/esp_openthread_lock.c diff --git a/components/openthread/port/esp_openthread_lwip_netif.c b/components/openthread/src/esp_openthread_lwip_netif.c similarity index 84% rename from components/openthread/port/esp_openthread_lwip_netif.c rename to components/openthread/src/esp_openthread_lwip_netif.c index b05eb2912f..29be440ae0 100644 --- a/components/openthread/port/esp_openthread_lwip_netif.c +++ b/components/openthread/src/esp_openthread_lwip_netif.c @@ -15,6 +15,7 @@ #include "lwip/esp_netif_net_stack.h" #include "lwip/netif.h" #include "lwip/pbuf.h" +#include "lwip_default_hooks.h" #include "openthread/error.h" #include "openthread/ip6.h" #include "openthread/link.h" @@ -143,3 +144,25 @@ static err_t openthread_netif_init(struct netif *netif) return ERR_OK; } + +const ip_addr_t *lwip_hook_ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest) +{ + const ip6_addr_t *cur_addr; + uint8_t idx = 0; + // Only process with ot netif. + if (!(netif->name[0] == 'o' && netif->name[1] == 't')) { + return NULL; + } + // Currently, prefer the address with the same prefix of the destination address. + // If no address found, return NULL for selection source address using the default algorithm. + for (idx = 0; idx < LWIP_IPV6_NUM_ADDRESSES; idx++) { + if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, idx))) { + continue; + } + cur_addr = netif_ip6_addr(netif, idx); + if (ip6_addr_netcmp_zoneless(cur_addr, dest)) { + return netif_ip_addr6(netif, idx); + } + } + return NULL; +} diff --git a/components/openthread/port/esp_openthread_netif_glue.c b/components/openthread/src/esp_openthread_netif_glue.c similarity index 91% rename from components/openthread/port/esp_openthread_netif_glue.c rename to components/openthread/src/esp_openthread_netif_glue.c index 9be2b6b947..608a3218fa 100644 --- a/components/openthread/port/esp_openthread_netif_glue.c +++ b/components/openthread/src/esp_openthread_netif_glue.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,7 @@ #include "esp_openthread_lock.h" #include "esp_openthread_netif_glue_priv.h" #include "esp_openthread_platform.h" +#include "esp_openthread_state.h" #include "esp_openthread_types.h" #include "esp_vfs_eventfd.h" #include "sdkconfig.h" @@ -170,30 +171,6 @@ static esp_err_t process_thread_transmit(otInstance *instance) return error; } -void esp_openthread_netif_glue_state_callback(otChangedFlags changed_flags, void *ctx) -{ - otInstance *instance = esp_openthread_get_instance(); - esp_err_t err = ESP_OK; - - if (s_packet_queue != NULL && (OT_CHANGED_THREAD_NETIF_STATE & changed_flags)) { - if (otLinkIsEnabled(instance)) { - ESP_LOGI(OT_PLAT_LOG_TAG, "netif up"); - if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_UP, NULL, 0, 0) != ESP_OK) { - ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to post OpenThread if up event"); - } - } else { - ESP_LOGI(OT_PLAT_LOG_TAG, "netif down"); - if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_DOWN, NULL, 0, 0) != ESP_OK) { - ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to post OpenThread if down event"); - } - } - } - - if (err != ESP_OK) { - ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to configure netif state"); - } -} - static esp_err_t openthread_netif_transmit(void *handle, void *buffer, size_t len) { esp_err_t error = ESP_OK; @@ -298,9 +275,6 @@ void *esp_openthread_netif_glue_init(const esp_openthread_platform_config_t *con if (instance == NULL || s_packet_queue || s_openthread_netif_glue.event_fd >= 0) { return NULL; } - ESP_RETURN_ON_FALSE(otSetStateChangedCallback(instance, esp_openthread_netif_glue_state_callback, NULL) == - OT_ERROR_NONE, - NULL, OT_PLAT_LOG_TAG, "Failed to install netif glue state callback"); s_packet_queue = xQueueCreate(config->port_config.netif_queue_size, sizeof(otMessage *)); if (s_packet_queue == NULL) { diff --git a/components/openthread/port/esp_openthread_platform.cpp b/components/openthread/src/esp_openthread_platform.cpp similarity index 93% rename from components/openthread/port/esp_openthread_platform.cpp rename to components/openthread/src/esp_openthread_platform.cpp index 2197807aee..24b39b6531 100644 --- a/components/openthread/port/esp_openthread_platform.cpp +++ b/components/openthread/src/esp_openthread_platform.cpp @@ -102,18 +102,12 @@ esp_err_t esp_openthread_platform_init(const esp_openthread_platform_config_t *c s_openthread_platform_initialized = true; esp_err_t ret = ESP_OK; -/* Avoid to compile flash in RADIO type device */ -#if !CONFIG_OPENTHREAD_RADIO - const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, - config->port_config.storage_partition_name); - ESP_RETURN_ON_FALSE(partition, ESP_ERR_INVALID_ARG, OT_PLAT_LOG_TAG, "OpenThread storage partition not found"); - esp_openthread_flash_set_partition(partition); -#endif - s_platform_config = *config; ESP_GOTO_ON_ERROR(esp_openthread_lock_init(), exit, OT_PLAT_LOG_TAG, "esp_openthread_lock_init failed"); ESP_GOTO_ON_ERROR(esp_openthread_alarm_init(), exit, OT_PLAT_LOG_TAG, "esp_openthread_alarm_init failed"); + esp_openthread_set_storage_name(config->port_config.storage_partition_name); + if (config->host_config.host_connection_mode == HOST_CONNECTION_MODE_RCP_SPI) { ESP_GOTO_ON_ERROR(esp_openthread_spi_slave_init(config), exit, OT_PLAT_LOG_TAG, "esp_openthread_spi_slave_init failed"); diff --git a/components/openthread/port/esp_openthread_task_queue.c b/components/openthread/src/esp_openthread_task_queue.c similarity index 100% rename from components/openthread/port/esp_openthread_task_queue.c rename to components/openthread/src/esp_openthread_task_queue.c diff --git a/components/openthread/port/esp_openthread_alarm.c b/components/openthread/src/port/esp_openthread_alarm.c similarity index 100% rename from components/openthread/port/esp_openthread_alarm.c rename to components/openthread/src/port/esp_openthread_alarm.c diff --git a/components/openthread/port/esp_openthread_flash.c b/components/openthread/src/port/esp_openthread_flash.c similarity index 100% rename from components/openthread/port/esp_openthread_flash.c rename to components/openthread/src/port/esp_openthread_flash.c diff --git a/components/openthread/port/esp_openthread_logging.c b/components/openthread/src/port/esp_openthread_logging.c similarity index 100% rename from components/openthread/port/esp_openthread_logging.c rename to components/openthread/src/port/esp_openthread_logging.c diff --git a/components/openthread/port/esp_openthread_memory.c b/components/openthread/src/port/esp_openthread_memory.c similarity index 100% rename from components/openthread/port/esp_openthread_memory.c rename to components/openthread/src/port/esp_openthread_memory.c diff --git a/components/openthread/port/esp_openthread_misc.c b/components/openthread/src/port/esp_openthread_misc.c similarity index 100% rename from components/openthread/port/esp_openthread_misc.c rename to components/openthread/src/port/esp_openthread_misc.c diff --git a/components/openthread/port/esp_openthread_radio.c b/components/openthread/src/port/esp_openthread_radio.c similarity index 100% rename from components/openthread/port/esp_openthread_radio.c rename to components/openthread/src/port/esp_openthread_radio.c diff --git a/components/openthread/port/esp_openthread_radio_spinel.cpp b/components/openthread/src/port/esp_openthread_radio_spinel.cpp similarity index 100% rename from components/openthread/port/esp_openthread_radio_spinel.cpp rename to components/openthread/src/port/esp_openthread_radio_spinel.cpp diff --git a/components/openthread/src/port/esp_openthread_settings.c b/components/openthread/src/port/esp_openthread_settings.c new file mode 100644 index 0000000000..8bc08be482 --- /dev/null +++ b/components/openthread/src/port/esp_openthread_settings.c @@ -0,0 +1,216 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "nvs.h" +#include "esp_check.h" +#include "esp_openthread_common_macro.h" +#include "openthread/instance.h" +#include "openthread/platform/settings.h" + +#define OT_NAMESPACE "openthread" +#define OT_PART_NAME s_storage_name +#define OT_KEY_PATTERN "OT%02x" +#define OT_KEY_INDEX_PATTERN "OT%02x%02x" +#define OT_KEY_PATTERN_LEN 5 +#define OT_KEY_INDEX_PATTERN_LEN 7 +static nvs_handle_t s_ot_nvs_handle; +static const char *s_storage_name; + +void esp_openthread_set_storage_name(const char *name) +{ + s_storage_name = name; +} + +static esp_err_t get_next_empty_index(uint16_t aKey, uint8_t *index) +{ + ESP_RETURN_ON_FALSE((s_ot_nvs_handle != 0), ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "OT NVS handle is invalid."); + esp_err_t ret = ESP_OK; + static volatile uint8_t s_unused_pos = 0; + char ot_nvs_key[OT_KEY_INDEX_PATTERN_LEN] = { 0 }; + nvs_iterator_t nvs_it = NULL; + bool found = false; + + for (uint8_t i = 0; i != UINT8_MAX; i++) { + s_unused_pos++; + snprintf(ot_nvs_key, sizeof(ot_nvs_key), OT_KEY_INDEX_PATTERN, (uint8_t)aKey, s_unused_pos); + ret = nvs_entry_find(OT_PART_NAME, OT_NAMESPACE, NVS_TYPE_BLOB, &nvs_it); + while (ret == ESP_OK) { + nvs_entry_info_t info; + nvs_entry_info(nvs_it, &info); + if (memcmp(ot_nvs_key, info.key, OT_KEY_INDEX_PATTERN_LEN - 1) == 0) { + found = true; + break; + } + ret = nvs_entry_next(&nvs_it); + } + nvs_release_iterator(nvs_it); + if (!found) { + // find an empty position, return ESP_OK + *index = s_unused_pos; + return ESP_OK; + } + } + // all index was used, no memory for current data, return ESP_ERR_NOT_FOUND. + return ESP_ERR_NOT_FOUND; +} + +static esp_err_t find_target_key_using_index(uint16_t aKey, int aIndex, char *key, size_t key_len) +{ + ESP_RETURN_ON_FALSE((s_ot_nvs_handle != 0), ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "OT NVS handle is invalid."); + esp_err_t ret = ESP_OK; + nvs_iterator_t nvs_it = NULL; + int cur_index = 0; + char ot_nvs_key[OT_KEY_PATTERN_LEN] = { 0 }; + + ret = nvs_entry_find(OT_PART_NAME, OT_NAMESPACE, NVS_TYPE_BLOB, &nvs_it); + if (ret != ESP_OK) { + return ret; + } + snprintf(ot_nvs_key, sizeof(ot_nvs_key), OT_KEY_PATTERN, (uint8_t)aKey); + while (ret == ESP_OK) { + nvs_entry_info_t info; + nvs_entry_info(nvs_it, &info); + if (memcmp(ot_nvs_key, info.key, OT_KEY_PATTERN_LEN - 1) == 0) { + if (cur_index == aIndex) { + memcpy(key, info.key, key_len); + break; + } else { + cur_index++; + } + } + ret = nvs_entry_next(&nvs_it); + } + nvs_release_iterator(nvs_it); + + if ((cur_index != aIndex) || (ret != ESP_OK)) { + return ESP_FAIL; + } + return ESP_OK; +} + +static esp_err_t erase_all_key(uint16_t aKey) +{ + ESP_RETURN_ON_FALSE((s_ot_nvs_handle != 0), ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, "OT NVS handle is invalid."); + esp_err_t ret = ESP_OK; + nvs_iterator_t nvs_it = NULL; + char ot_nvs_key[OT_KEY_PATTERN_LEN] = { 0 }; + + ret = nvs_entry_find(OT_PART_NAME, OT_NAMESPACE, NVS_TYPE_BLOB, &nvs_it); + if (ret == ESP_ERR_NVS_NOT_FOUND) { + return ESP_OK; + } + ESP_RETURN_ON_FALSE((ret == ESP_OK && nvs_it != NULL), ESP_FAIL, OT_PLAT_LOG_TAG, "Can not find any data in nvs flash, err: %d", ret); + while (ret == ESP_OK) { + snprintf(ot_nvs_key, sizeof(ot_nvs_key), OT_KEY_PATTERN, (uint8_t)aKey); + nvs_entry_info_t info; + nvs_entry_info(nvs_it, &info); + if (memcmp(ot_nvs_key, info.key, OT_KEY_PATTERN_LEN - 1) == 0) { + ret = nvs_erase_key(s_ot_nvs_handle, info.key); + if (ret != ESP_OK) { + break; + } + } + ret = nvs_entry_next(&nvs_it); + } + nvs_release_iterator(nvs_it); + ret = nvs_commit(s_ot_nvs_handle); + if (ret != ESP_OK) { + return ESP_FAIL; + } + return ESP_OK; +} + +void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, uint16_t aSensitiveKeysLength) +{ + esp_err_t err = nvs_open(OT_NAMESPACE, NVS_READWRITE, &s_ot_nvs_handle); + if (err != ESP_OK) { + ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to open NVS namespace (0x%x)", err); + assert(0); + } +} + +void otPlatSettingsDeinit(otInstance *aInstance) +{ + if (s_ot_nvs_handle != 0) { + nvs_close(s_ot_nvs_handle); + } +} + +otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) +{ + ESP_RETURN_ON_FALSE((s_ot_nvs_handle != 0), OT_ERROR_NOT_FOUND, OT_PLAT_LOG_TAG, "OT NVS handle is invalid."); + esp_err_t ret = ESP_OK; + char ot_nvs_key[OT_KEY_INDEX_PATTERN_LEN] = { 0 }; + + ret = find_target_key_using_index(aKey, aIndex, ot_nvs_key, OT_KEY_INDEX_PATTERN_LEN); + if (ret != ESP_OK) { + return OT_ERROR_NOT_FOUND; + } + size_t length = *aValueLength; + ret = nvs_get_blob(s_ot_nvs_handle, ot_nvs_key, aValue, &length); + *aValueLength = (uint16_t) length; + ESP_RETURN_ON_FALSE((ret == ESP_OK), OT_ERROR_NOT_FOUND, OT_PLAT_LOG_TAG, "Data not found, err: %d", ret); + return OT_ERROR_NONE; +} + +otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength) +{ + ESP_RETURN_ON_FALSE((s_ot_nvs_handle != 0), OT_ERROR_NOT_FOUND, OT_PLAT_LOG_TAG, "OT NVS handle is invalid."); + esp_err_t ret = ESP_OK; + char ot_nvs_key[OT_KEY_INDEX_PATTERN_LEN]= { 0 }; + + snprintf(ot_nvs_key, sizeof(ot_nvs_key), OT_KEY_INDEX_PATTERN, (uint8_t)aKey, 0); + ret = nvs_set_blob(s_ot_nvs_handle, ot_nvs_key, aValue, aValueLength); + ESP_RETURN_ON_FALSE((ret == ESP_OK), OT_ERROR_NO_BUFS, OT_PLAT_LOG_TAG, "No buffers, err: %d", ret); + ret = nvs_commit(s_ot_nvs_handle); + ESP_RETURN_ON_FALSE((ret == ESP_OK), OT_ERROR_NO_BUFS, OT_PLAT_LOG_TAG, "OT NVS handle shut down, err: %d", ret); + return OT_ERROR_NONE; +} + +otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength) +{ + ESP_RETURN_ON_FALSE((s_ot_nvs_handle != 0), OT_ERROR_NOT_FOUND, OT_PLAT_LOG_TAG, "OT NVS handle is invalid."); + esp_err_t ret = ESP_OK; + uint8_t unused_pos; + char ot_nvs_key[OT_KEY_INDEX_PATTERN_LEN] = { 0 }; + + ret = get_next_empty_index(aKey, &unused_pos); + ESP_RETURN_ON_FALSE((ret == ESP_OK), OT_ERROR_NO_BUFS, OT_PLAT_LOG_TAG, "No buffers, err: %d", ret); + snprintf(ot_nvs_key, sizeof(ot_nvs_key), OT_KEY_INDEX_PATTERN, (uint8_t)aKey, unused_pos); + ret = nvs_set_blob(s_ot_nvs_handle, ot_nvs_key, aValue, aValueLength); + ESP_RETURN_ON_FALSE((ret == ESP_OK), OT_ERROR_NO_BUFS, OT_PLAT_LOG_TAG, "No buffers, err: %d", ret); + ret = nvs_commit(s_ot_nvs_handle); + ESP_RETURN_ON_FALSE((ret == ESP_OK), OT_ERROR_NO_BUFS, OT_PLAT_LOG_TAG, "OT NVS handle shut down, err: %d", ret); + return OT_ERROR_NONE; +} + +otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex) +{ + ESP_RETURN_ON_FALSE((s_ot_nvs_handle != 0), OT_ERROR_NOT_FOUND, OT_PLAT_LOG_TAG, "OT NVS handle is invalid."); + esp_err_t ret = ESP_OK; + + if (aIndex == -1) { + ret = erase_all_key(aKey); + } else { + char ot_nvs_key[OT_KEY_INDEX_PATTERN_LEN] = { 0 }; + ret = find_target_key_using_index(aKey, aIndex, ot_nvs_key, OT_KEY_INDEX_PATTERN_LEN); + if (ret != ESP_OK) { + return OT_ERROR_NOT_FOUND; + } + ret = nvs_erase_key(s_ot_nvs_handle, ot_nvs_key); + nvs_commit(s_ot_nvs_handle); + } + return OT_ERROR_NONE; +} + +void otPlatSettingsWipe(otInstance *aInstance) +{ + nvs_erase_all(s_ot_nvs_handle); +} diff --git a/components/openthread/port/esp_openthread_spi_slave.c b/components/openthread/src/port/esp_openthread_spi_slave.c similarity index 100% rename from components/openthread/port/esp_openthread_spi_slave.c rename to components/openthread/src/port/esp_openthread_spi_slave.c diff --git a/components/openthread/src/port/esp_openthread_state.c b/components/openthread/src/port/esp_openthread_state.c new file mode 100644 index 0000000000..6dbe101670 --- /dev/null +++ b/components/openthread/src/port/esp_openthread_state.c @@ -0,0 +1,109 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TAG "OT_STATE" + +static void handle_ot_netif_state_change(otInstance* instance) +{ + if (otLinkIsEnabled(instance)) { + ESP_LOGI(TAG, "netif up"); + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_UP, NULL, 0, 0) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post OpenThread if up event"); + } + } else { + ESP_LOGI(TAG, "netif down"); + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_DOWN, NULL, 0, 0) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post OpenThread if down event"); + } + } +} + +static void handle_ot_netdata_change(void) +{ +#if CONFIG_OPENTHREAD_DNS64_CLIENT + ip_addr_t dns_server_addr = *IP_ADDR_ANY; + if (esp_openthread_get_nat64_prefix(&dns_server_addr.u_addr.ip6) == ESP_OK) { + dns_server_addr.type = IPADDR_TYPE_V6; + dns_server_addr.u_addr.ip6.addr[3] = ipaddr_addr(CONFIG_OPENTHREAD_DNS_SERVER_ADDR); + const ip_addr_t* dnsserver = dns_getserver(OPENTHREAD_DNS_SERVER_INDEX); + if (memcmp(dnsserver, &dns_server_addr, sizeof(ip_addr_t)) != 0) { + ESP_LOGI(TAG, "Set dns server address: %s", ipaddr_ntoa(&dns_server_addr)); + dns_setserver(OPENTHREAD_DNS_SERVER_INDEX, &dns_server_addr); + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_SET_DNS_SERVER, NULL, 0, 0) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post OpenThread set DNS server event"); + } + } + } +#endif +} + +static void handle_ot_role_change(otInstance* instance) +{ + static otDeviceRole s_previous_role = OT_DEVICE_ROLE_DISABLED; + otDeviceRole role = otThreadGetDeviceRole(instance); + esp_err_t ret = ESP_OK; + esp_openthread_role_changed_event_t event_data; + event_data.current_role = role; + event_data.previous_role = s_previous_role; + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_ROLE_CHANGED, &event_data, sizeof(event_data), 0) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post OPENTHREAD_EVENT_ROLE_CHANGED"); + } + if (role == OT_DEVICE_ROLE_CHILD || role == OT_DEVICE_ROLE_ROUTER || role == OT_DEVICE_ROLE_LEADER) { + if (s_previous_role == OT_DEVICE_ROLE_DETACHED || s_previous_role == OT_DEVICE_ROLE_DISABLED) { + otOperationalDataset dataset; + ESP_GOTO_ON_FALSE(otDatasetGetActive(instance, &dataset) == OT_ERROR_NONE, ESP_FAIL, exit, TAG, + "Failed to get the active dataset"); + ESP_GOTO_ON_ERROR(esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_ATTACHED, &dataset, sizeof(dataset), 0), + exit, TAG, "Failed to post OPENTHREAD_EVENT_ATTACHED. Err: %s", esp_err_to_name(ret)); + } + } else if (role == OT_DEVICE_ROLE_DETACHED) { + if (s_previous_role != OT_DEVICE_ROLE_DISABLED) { + ESP_GOTO_ON_ERROR( + esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_DETACHED, &s_previous_role, sizeof(s_previous_role), 0), + exit, TAG, "Failed to post OPENTHREAD_EVENT_DETACHED. Err: %s", esp_err_to_name(ret)); + } + } +exit: + s_previous_role = role; +} + +static void ot_state_change_callback(otChangedFlags changed_flags, void* ctx) +{ + OT_UNUSED_VARIABLE(ctx); + otInstance* instance = esp_openthread_get_instance(); + if (!instance) { + return; + } + + if (changed_flags & OT_CHANGED_THREAD_ROLE) { + handle_ot_role_change(instance); + } + + if (changed_flags & OT_CHANGED_THREAD_NETDATA) { + handle_ot_netdata_change(); + } + + if (changed_flags & OT_CHANGED_THREAD_NETIF_STATE) { + handle_ot_netif_state_change(instance); + } +} + +esp_err_t esp_openthread_state_event_init(otInstance* instance) +{ + ESP_RETURN_ON_FALSE(otSetStateChangedCallback(instance, ot_state_change_callback, NULL) == OT_ERROR_NONE, + ESP_FAIL, TAG, "Failed to install state change callback"); + return ESP_OK; +} diff --git a/components/openthread/port/esp_openthread_uart.c b/components/openthread/src/port/esp_openthread_uart.c similarity index 100% rename from components/openthread/port/esp_openthread_uart.c rename to components/openthread/src/port/esp_openthread_uart.c diff --git a/components/openthread/port/esp_openthread_udp.c b/components/openthread/src/port/esp_openthread_udp.c similarity index 100% rename from components/openthread/port/esp_openthread_udp.c rename to components/openthread/src/port/esp_openthread_udp.c diff --git a/components/openthread/port/esp_spi_spinel_interface.cpp b/components/openthread/src/port/esp_spi_spinel_interface.cpp similarity index 100% rename from components/openthread/port/esp_spi_spinel_interface.cpp rename to components/openthread/src/port/esp_spi_spinel_interface.cpp diff --git a/components/openthread/port/esp_uart_spinel_interface.cpp b/components/openthread/src/port/esp_uart_spinel_interface.cpp similarity index 100% rename from components/openthread/port/esp_uart_spinel_interface.cpp rename to components/openthread/src/port/esp_uart_spinel_interface.cpp diff --git a/examples/openthread/ot_br/main/Kconfig.projbuild b/examples/openthread/ot_br/main/Kconfig.projbuild index fa8a651201..996d5e2abb 100644 --- a/examples/openthread/ot_br/main/Kconfig.projbuild +++ b/examples/openthread/ot_br/main/Kconfig.projbuild @@ -1,43 +1,5 @@ menu "OpenThread Border Router Example" - config OPENTHREAD_NETWORK_NAME - string "OpenThread network name" - default "OpenThread" - help - The OpenThread network name for example to use - - config OPENTHREAD_NETWORK_CHANNEL - int "OpenThread network channel" - range 11 26 - default 15 - help - The OpenThread network channel to use - - config OPENTHREAD_NETWORK_PANID - hex "OpenThread network pan id" - range 0 0xFFFE - default 0x1234 - help - The OpenThread network pan id to use - - config OPENTHREAD_NETWORK_EXTPANID - string "OpenThread extended pan id" - default "dead00beef00cafe" - help - The OpenThread network extended pan id in hex string format - - config OPENTHREAD_NETWORK_MASTERKEY - string "OpenThread master key" - default "00112233445566778899aabbccddeeff" - help - The OpenThread network master key in hex string format - - config OPENTHREAD_NETWORK_PSKC - string "OpenThread pre-shared commissioner key" - default "104810e2315100afd6bc9215a6bfac53" - help - The OpenThread pre-shared commissioner key in hex string format - config OPENTHREAD_BR_AUTO_START bool 'Enable the automatic start mode in Thread Border Router.' default False diff --git a/examples/openthread/ot_br/main/esp_ot_br.c b/examples/openthread/ot_br/main/esp_ot_br.c index 38d8e43dd6..249ea27654 100644 --- a/examples/openthread/ot_br/main/esp_ot_br.c +++ b/examples/openthread/ot_br/main/esp_ot_br.c @@ -20,8 +20,6 @@ #include "esp_event.h" #include "esp_log.h" #include "esp_netif.h" -#include "esp_netif_ip_addr.h" -#include "esp_netif_net_stack.h" #include "esp_openthread.h" #include "esp_openthread_border_router.h" #include "esp_openthread_cli.h" @@ -43,122 +41,12 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "hal/uart_types.h" -#include "openthread/backbone_router_ftd.h" -#include "openthread/border_router.h" -#include "openthread/cli.h" -#include "openthread/dataset.h" -#include "openthread/dataset_ftd.h" -#include "openthread/dataset_updater.h" #include "openthread/error.h" -#include "openthread/instance.h" -#include "openthread/ip6.h" #include "openthread/logging.h" #include "openthread/tasklet.h" -#include "openthread/thread_ftd.h" #define TAG "esp_ot_br" -#if CONFIG_OPENTHREAD_BR_AUTO_START -static int hex_digit_to_int(char hex) -{ - if ('A' <= hex && hex <= 'F') { - return 10 + hex - 'A'; - } - if ('a' <= hex && hex <= 'f') { - return 10 + hex - 'a'; - } - if ('0' <= hex && hex <= '9') { - return hex - '0'; - } - return -1; -} - -static size_t hex_string_to_binary(const char *hex_string, uint8_t *buf, size_t buf_size) -{ - int num_char = strlen(hex_string); - - if (num_char != buf_size * 2) { - return 0; - } - for (size_t i = 0; i < num_char; i += 2) { - int digit0 = hex_digit_to_int(hex_string[i]); - int digit1 = hex_digit_to_int(hex_string[i + 1]); - - if (digit0 < 0 || digit1 < 0) { - return 0; - } - buf[i / 2] = (digit0 << 4) + digit1; - } - - return buf_size; -} - -static void create_config_network(otInstance *instance) -{ - otOperationalDataset dataset; - - if (otDatasetGetActive(instance, &dataset) == OT_ERROR_NONE) { - ESP_LOGI(TAG, "Already has network, skip configuring OpenThread network."); - return; - } - - uint16_t network_name_len = strlen(CONFIG_OPENTHREAD_NETWORK_NAME); - - assert(network_name_len <= OT_NETWORK_NAME_MAX_SIZE); - - if (otDatasetCreateNewNetwork(instance, &dataset) != OT_ERROR_NONE) { - ESP_LOGE(TAG, "Failed to create OpenThread network dataset."); - abort(); - } - dataset.mChannel = CONFIG_OPENTHREAD_NETWORK_CHANNEL; - dataset.mComponents.mIsChannelPresent = true; - dataset.mPanId = CONFIG_OPENTHREAD_NETWORK_PANID; - dataset.mComponents.mIsPanIdPresent = true; - memcpy(dataset.mNetworkName.m8, CONFIG_OPENTHREAD_NETWORK_NAME, network_name_len); - dataset.mComponents.mIsNetworkNamePresent = true; - if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_EXTPANID, dataset.mExtendedPanId.m8, - sizeof(dataset.mExtendedPanId.m8)) != sizeof(dataset.mExtendedPanId.m8)) { - ESP_LOGE(TAG, "Cannot convert OpenThread extended pan id. Please double-check your config."); - abort(); - } - dataset.mComponents.mIsExtendedPanIdPresent = true; - if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_MASTERKEY, dataset.mNetworkKey.m8, - sizeof(dataset.mNetworkKey.m8)) != sizeof(dataset.mNetworkKey.m8)) { - ESP_LOGE(TAG, "Cannot convert OpenThread master key. Please double-check your config."); - abort(); - } - dataset.mComponents.mIsNetworkKeyPresent = true; - if (hex_string_to_binary(CONFIG_OPENTHREAD_NETWORK_PSKC, dataset.mPskc.m8, sizeof(dataset.mPskc.m8)) != - sizeof(dataset.mPskc.m8)) { - ESP_LOGE(TAG, "Cannot convert OpenThread pre-shared commissioner key. Please double-check your config."); - abort(); - } - dataset.mComponents.mIsPskcPresent = true; - if (otDatasetSetActive(instance, &dataset) != OT_ERROR_NONE) { - ESP_LOGE(TAG, "Failed to set OpenThread active dataset."); - abort(); - } - return; -} - -static void launch_openthread_network(otInstance *instance) -{ - if (otIp6SetEnabled(instance, true) != OT_ERROR_NONE) { - ESP_LOGE(TAG, "Failed to enable OpenThread IP6 link"); - abort(); - } - if (otThreadSetEnabled(instance, true) != OT_ERROR_NONE) { - ESP_LOGE(TAG, "Failed to enable OpenThread"); - abort(); - } - if (otBorderRouterRegister(instance) != OT_ERROR_NONE) { - ESP_LOGE(TAG, "Failed to register border router."); - abort(); - } - otBackboneRouterSetEnabled(instance, true); -} -#endif // CONFIG_OPENTHREAD_BR_AUTO_START - static void ot_task_worker(void *aContext) { esp_openthread_platform_config_t config = { @@ -170,8 +58,8 @@ static void ot_task_worker(void *aContext) esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD(); esp_netif_t *openthread_netif = esp_netif_new(&cfg); assert(openthread_netif != NULL); - // Initialize the OpenThread stack + // Initialize the OpenThread stack ESP_ERROR_CHECK(esp_openthread_init(&config)); // Initialize border routing features @@ -180,11 +68,12 @@ static void ot_task_worker(void *aContext) (void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL); esp_openthread_cli_init(); + #if CONFIG_OPENTHREAD_BR_AUTO_START ESP_ERROR_CHECK(esp_openthread_border_router_init()); - create_config_network(esp_openthread_get_instance()); - launch_openthread_network(esp_openthread_get_instance()); + ESP_ERROR_CHECK(esp_openthread_auto_start(NULL)); #endif // CONFIG_OPENTHREAD_BR_AUTO_START + esp_cli_custom_command_init(); esp_openthread_lock_release(); diff --git a/examples/openthread/ot_br/main/esp_ot_config.h b/examples/openthread/ot_br/main/esp_ot_config.h index 9e9953966a..d8c4265cba 100644 --- a/examples/openthread/ot_br/main/esp_ot_config.h +++ b/examples/openthread/ot_br/main/esp_ot_config.h @@ -96,7 +96,7 @@ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ { \ - .storage_partition_name = "ot_storage", \ + .storage_partition_name = "nvs", \ .netif_queue_size = 10, \ .task_queue_size = 10, \ } diff --git a/examples/openthread/ot_br/partitions.csv b/examples/openthread/ot_br/partitions.csv index a484b99010..4305c74725 100644 --- a/examples/openthread/ot_br/partitions.csv +++ b/examples/openthread/ot_br/partitions.csv @@ -3,4 +3,3 @@ nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1600K, -ot_storage, data, 0x3a, , 0x2000, diff --git a/examples/openthread/ot_br/sdkconfig.defaults b/examples/openthread/ot_br/sdkconfig.defaults index 369bdb00f6..d2ee6928f0 100644 --- a/examples/openthread/ot_br/sdkconfig.defaults +++ b/examples/openthread/ot_br/sdkconfig.defaults @@ -43,6 +43,7 @@ CONFIG_LWIP_NETIF_STATUS_CALLBACK=y CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM=y +CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM=y CONFIG_LWIP_IPV6_AUTOCONFIG=y # end of lwIP diff --git a/examples/openthread/ot_cli/main/esp_ot_config.h b/examples/openthread/ot_cli/main/esp_ot_config.h index c1defedae5..a0a1a37a9e 100644 --- a/examples/openthread/ot_cli/main/esp_ot_config.h +++ b/examples/openthread/ot_cli/main/esp_ot_config.h @@ -66,7 +66,7 @@ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ { \ - .storage_partition_name = "ot_storage", \ + .storage_partition_name = "nvs", \ .netif_queue_size = 10, \ .task_queue_size = 10, \ } diff --git a/examples/openthread/ot_cli/partitions.csv b/examples/openthread/ot_cli/partitions.csv index 1874ddc89f..6c0e048dba 100644 --- a/examples/openthread/ot_cli/partitions.csv +++ b/examples/openthread/ot_cli/partitions.csv @@ -3,4 +3,3 @@ nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 0x120000, -ot_storage, data, 0x3a, , 0x2000, diff --git a/examples/openthread/ot_cli/sdkconfig.defaults b/examples/openthread/ot_cli/sdkconfig.defaults index 9ea24974eb..b998de8176 100644 --- a/examples/openthread/ot_cli/sdkconfig.defaults +++ b/examples/openthread/ot_cli/sdkconfig.defaults @@ -4,8 +4,6 @@ CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y # end of libsodium -CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=2048 - # # Partition Table # @@ -19,10 +17,6 @@ CONFIG_PARTITION_TABLE_MD5=y # # mbedTLS # -# ESP32H2-TODO: enable HW acceleration -CONFIG_MBEDTLS_HARDWARE_AES=n -CONFIG_MBEDTLS_HARDWARE_MPI=n -CONFIG_MBEDTLS_HARDWARE_SHA=n CONFIG_MBEDTLS_CMAC_C=y CONFIG_MBEDTLS_SSL_PROTO_DTLS=y CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y @@ -43,6 +37,7 @@ CONFIG_OPENTHREAD_DNS64_CLIENT=y CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096 CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 CONFIG_LWIP_MULTICAST_PING=y +CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM=y # end of lwIP # diff --git a/examples/openthread/ot_rcp/main/esp_ot_config.h b/examples/openthread/ot_rcp/main/esp_ot_config.h index 24c434c12d..42e91bbb18 100644 --- a/examples/openthread/ot_rcp/main/esp_ot_config.h +++ b/examples/openthread/ot_rcp/main/esp_ot_config.h @@ -75,7 +75,7 @@ #define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \ { \ - .storage_partition_name = "ot_storage", \ + .storage_partition_name = "nvs", \ .netif_queue_size = 10, \ .task_queue_size = 10, \ } diff --git a/examples/openthread/ot_rcp/partitions.csv b/examples/openthread/ot_rcp/partitions.csv index 738122467a..88795c6b03 100644 --- a/examples/openthread/ot_rcp/partitions.csv +++ b/examples/openthread/ot_rcp/partitions.csv @@ -3,4 +3,3 @@ nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, , 0x1000, factory, app, factory, 0x10000, 1M, -ot_storage, data, 0x3a, , 0x2000, diff --git a/examples/openthread/ot_rcp/sdkconfig.defaults b/examples/openthread/ot_rcp/sdkconfig.defaults index f1ab6da317..3b8c9d13e4 100644 --- a/examples/openthread/ot_rcp/sdkconfig.defaults +++ b/examples/openthread/ot_rcp/sdkconfig.defaults @@ -14,18 +14,6 @@ CONFIG_PARTITION_TABLE_OFFSET=0x8000 CONFIG_PARTITION_TABLE_MD5=y # end of Partition Table -# -# mbedTLS -# - -CONFIG_MBEDTLS_CMAC_C=y -CONFIG_MBEDTLS_SSL_PROTO_DTLS=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y -# end of TLS Key Exchange Methods - -CONFIG_MBEDTLS_ECJPAKE_C=y -# end of mbedTLS - # # OpenThread #