Merge branch 'backport/openthread_feature' into 'release/v5.1'

Backport some Openthread related MR to 5.1(Backport5.1)

See merge request espressif/esp-idf!24285
This commit is contained in:
Shu Chen 2023-07-12 14:25:22 +08:00
commit 65bf500d29
50 changed files with 716 additions and 358 deletions

View File

@ -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

@ -1 +1 @@
Subproject commit dafc8225313a1ce00fb0b497d09f43ec7073857d
Subproject commit 57c29648ff40e2a19a51683717928aaf766a0495

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.
*

@ -1 +1 @@
Subproject commit fed28dde58d5d4a46d3acc4935a23b43fe82b320
Subproject commit 36cb2202e10b5ba7484654962ca9e3ceb51f6d51

View File

@ -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);
}

View File

@ -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.
*

View File

@ -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

View File

@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <esp_err.h>
#include <esp_openthread.h>
#include <esp_openthread_types.h>
#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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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");

View File

@ -0,0 +1,216 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}

View File

@ -0,0 +1,109 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_check.h>
#include <esp_event.h>
#include <esp_log.h>
#include <esp_openthread_dns64.h>
#include <esp_openthread_netif_glue_priv.h>
#include <esp_openthread_state.h>
#include <lwip/dns.h>
#include <openthread/thread.h>
#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;
}

View File

@ -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

View File

@ -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();

View File

@ -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, \
}

View File

@ -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,

1 # Name, Type, SubType, Offset, Size, Flags
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1600K,
ot_storage, data, 0x3a, , 0x2000,

View File

@ -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

View File

@ -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, \
}

View File

@ -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,

1 # Name, Type, SubType, Offset, Size, Flags
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 0x120000,
ot_storage, data, 0x3a, , 0x2000,

View File

@ -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
#

View File

@ -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, \
}

View File

@ -3,4 +3,3 @@
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, , 0x1000,
factory, app, factory, 0x10000, 1M,
ot_storage, data, 0x3a, , 0x2000,

1 # Name, Type, SubType, Offset, Size, Flags
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, , 0x1000,
5 factory, app, factory, 0x10000, 1M,
ot_storage, data, 0x3a, , 0x2000,

View File

@ -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
#