Merge branch 'review_ot_code_using_cursor' into 'master'

fix(openthread): make the code more robust

See merge request espressif/esp-idf!47092
This commit is contained in:
Shu Chen
2026-04-17 08:40:44 +00:00
15 changed files with 120 additions and 53 deletions
+11 -10
View File
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -80,19 +80,20 @@ 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, ESP_RETURN_ON_ERROR(esp_openthread_platform_init(config), OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread platform driver"); "Failed to initialize OpenThread platform driver");
esp_openthread_lock_acquire(portMAX_DELAY); esp_openthread_lock_acquire(portMAX_DELAY);
ESP_RETURN_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, OT_PLAT_LOG_TAG, esp_err_t ret = ESP_OK;
"Failed to initialize OpenThread instance"); ESP_GOTO_ON_FALSE(otInstanceInitSingle() != NULL, ESP_FAIL, exit, OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread instance");
#if CONFIG_OPENTHREAD_DNS64_CLIENT #if CONFIG_OPENTHREAD_DNS64_CLIENT
ESP_RETURN_ON_ERROR(esp_openthread_dns64_client_init(), OT_PLAT_LOG_TAG, ESP_GOTO_ON_ERROR(esp_openthread_dns64_client_init(), exit, OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread dns64 client"); "Failed to initialize OpenThread dns64 client");
#endif #endif
#if !CONFIG_OPENTHREAD_RADIO #if !CONFIG_OPENTHREAD_RADIO
ESP_RETURN_ON_ERROR(esp_openthread_state_event_init(esp_openthread_get_instance()), OT_PLAT_LOG_TAG, ESP_GOTO_ON_ERROR(esp_openthread_state_event_init(esp_openthread_get_instance()), exit, OT_PLAT_LOG_TAG,
"Failed to initialize OpenThread state event"); "Failed to initialize OpenThread state event");
#endif #endif
exit:
esp_openthread_lock_release(); esp_openthread_lock_release();
return ret;
return ESP_OK;
} }
esp_err_t esp_openthread_auto_start(otOperationalDatasetTlvs *datasetTlvs) esp_err_t esp_openthread_auto_start(otOperationalDatasetTlvs *datasetTlvs)
@@ -140,7 +141,7 @@ esp_err_t esp_openthread_auto_start(otOperationalDatasetTlvs *datasetTlvs)
memcpy(dataset.mMeshLocalPrefix.m8, prefix.mPrefix.mFields.m8, sizeof(dataset.mMeshLocalPrefix.m8)); memcpy(dataset.mMeshLocalPrefix.m8, prefix.mPrefix.mFields.m8, sizeof(dataset.mMeshLocalPrefix.m8));
dataset.mComponents.mIsMeshLocalPrefixPresent = true; dataset.mComponents.mIsMeshLocalPrefixPresent = true;
} else { } else {
ESP_LOGE("Failed to parse mesh local prefix", CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX); ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to parse mesh local prefix: %s", CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX);
} }
// Network Key // Network Key
+18 -6
View File
@@ -64,8 +64,12 @@ static int cli_output_callback(void *context, const char *format, va_list args)
{ {
char prompt_check[3]; char prompt_check[3];
int ret = 0; int ret = 0;
va_list args_copy;
va_copy(args_copy, args);
vsnprintf(prompt_check, sizeof(prompt_check), format, args_copy);
va_end(args_copy);
vsnprintf(prompt_check, sizeof(prompt_check), format, args);
if (!strncmp(prompt_check, "> ", sizeof(prompt_check)) && s_cli_task) { if (!strncmp(prompt_check, "> ", sizeof(prompt_check)) && s_cli_task) {
xTaskNotifyGive(s_cli_task); xTaskNotifyGive(s_cli_task);
} else { } else {
@@ -93,7 +97,11 @@ esp_err_t esp_openthread_cli_input(const char *line)
ESP_RETURN_ON_FALSE(line_copy != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to copy OpenThread CLI line input"); ESP_RETURN_ON_FALSE(line_copy != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to copy OpenThread CLI line input");
return esp_openthread_task_queue_post(line_handle_task, line_copy); esp_err_t ret = esp_openthread_task_queue_post(line_handle_task, line_copy);
if (ret != ESP_OK) {
free(line_copy);
}
return ret;
} }
static int ot_cli_console_callback(int argc, char **argv) static int ot_cli_console_callback(int argc, char **argv)
@@ -140,6 +148,11 @@ static void ot_cli_loop(void *context)
console_config.hint_color = -1; console_config.hint_color = -1;
ret = esp_console_init(&console_config); ret = esp_console_init(&console_config);
if (ret != ESP_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to initialize console: %s", esp_err_to_name(ret));
vTaskDelete(NULL);
return;
}
linenoiseSetMultiLine(true); linenoiseSetMultiLine(true);
linenoiseHistorySetMaxLen(100); linenoiseHistorySetMaxLen(100);
@@ -183,9 +196,8 @@ static void ot_cli_loop(void *context)
} }
} }
void esp_openthread_cli_create_task() void esp_openthread_cli_create_task(void)
{ {
xTaskCreate(ot_cli_loop, "ot_cli", 4096, xTaskGetCurrentTaskHandle(), 4, &s_cli_task); BaseType_t ret = xTaskCreate(ot_cli_loop, "ot_cli", 4096, xTaskGetCurrentTaskHandle(), 4, &s_cli_task);
ESP_RETURN_ON_FALSE(ret == pdPASS, , OT_PLAT_LOG_TAG, "Failed to create OpenThread CLI task");
return;
} }
@@ -107,6 +107,7 @@ static void dns_found_handler(const char *name, const ip_addr_t *ipaddr, void *c
if (resolve_entry && resolve_entry->found) { if (resolve_entry && resolve_entry->found) {
if (!ipaddr) { if (!ipaddr) {
resolve_entry->found(name, NULL, resolve_entry->callback_arg); resolve_entry->found(name, NULL, resolve_entry->callback_arg);
resolve_entry->is_using = false;
} else if (lwip_strnicmp(name, resolve_entry->name, sizeof(resolve_entry->name)) == 0) { } else if (lwip_strnicmp(name, resolve_entry->name, sizeof(resolve_entry->name)) == 0) {
ip_addr_t ipaddr_copy = *ipaddr; ip_addr_t ipaddr_copy = *ipaddr;
ip6_addr_t nat64_prefix; ip6_addr_t nat64_prefix;
@@ -117,8 +118,8 @@ static void dns_found_handler(const char *name, const ip_addr_t *ipaddr, void *c
ipaddr_copy.u_addr.ip6.zone = IP6_NO_ZONE; ipaddr_copy.u_addr.ip6.zone = IP6_NO_ZONE;
} }
resolve_entry->found(name, &ipaddr_copy, resolve_entry->callback_arg); resolve_entry->found(name, &ipaddr_copy, resolve_entry->callback_arg);
resolve_entry->is_using = false;
} }
resolve_entry->is_using = false;
} }
} }
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -20,9 +20,14 @@ bool esp_openthread_lock_acquire(TickType_t block_ticks)
{ {
ESP_RETURN_ON_FALSE(s_openthread_mutex && s_openthread_task_mutex, false, OT_PLAT_LOG_TAG, ESP_RETURN_ON_FALSE(s_openthread_mutex && s_openthread_task_mutex, false, OT_PLAT_LOG_TAG,
"Failed to acquire the lock because the mutex is not ready"); "Failed to acquire the lock because the mutex is not ready");
BaseType_t ret = xSemaphoreTakeRecursive(s_openthread_mutex, block_ticks) && if (xSemaphoreTakeRecursive(s_openthread_mutex, block_ticks) != pdTRUE) {
xSemaphoreTakeRecursive(s_openthread_task_mutex, block_ticks); return false;
return (ret == pdTRUE); }
if (xSemaphoreTakeRecursive(s_openthread_task_mutex, block_ticks) != pdTRUE) {
xSemaphoreGiveRecursive(s_openthread_mutex);
return false;
}
return true;
} }
void esp_openthread_lock_release(void) void esp_openthread_lock_release(void)
@@ -61,6 +66,7 @@ esp_err_t esp_openthread_lock_init(void)
s_openthread_mutex = xSemaphoreCreateRecursiveMutex(); s_openthread_mutex = xSemaphoreCreateRecursiveMutex();
s_openthread_task_mutex = xSemaphoreCreateRecursiveMutex(); s_openthread_task_mutex = xSemaphoreCreateRecursiveMutex();
if (s_openthread_mutex == NULL || s_openthread_task_mutex == NULL) { if (s_openthread_mutex == NULL || s_openthread_task_mutex == NULL) {
esp_openthread_lock_deinit();
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
return ESP_OK; return ESP_OK;
@@ -243,10 +243,8 @@ void esp_openthread_register_meshcop_e_handler(esp_event_handler_t handler, bool
{ {
if (for_publish) { if (for_publish) {
meshcop_e_publish_handler = handler; meshcop_e_publish_handler = handler;
} else if (!for_publish) {
meshcop_e_remove_handler = handler;
} else { } else {
ESP_ERROR_CHECK(ESP_FAIL); meshcop_e_remove_handler = handler;
} }
} }
@@ -345,6 +343,8 @@ void *esp_openthread_netif_glue_init(const esp_openthread_platform_config_t *con
s_openthread_netif_glue.event_fd = eventfd(0, 0); s_openthread_netif_glue.event_fd = eventfd(0, 0);
if (s_openthread_netif_glue.event_fd < 0) { if (s_openthread_netif_glue.event_fd < 0) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to create event fd for Thread netif"); ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to create event fd for Thread netif");
vQueueDelete(s_packet_queue);
s_packet_queue = NULL;
ExitNow(error = ESP_FAIL); ExitNow(error = ESP_FAIL);
} }
s_openthread_netif_glue.base.post_attach = openthread_netif_post_attach; s_openthread_netif_glue.base.post_attach = openthread_netif_post_attach;
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -34,8 +34,12 @@ esp_err_t esp_openthread_task_queue_init(const esp_openthread_platform_config_t
ESP_RETURN_ON_FALSE(s_task_queue_event_fd >= 0, ESP_FAIL, OT_PLAT_LOG_TAG, ESP_RETURN_ON_FALSE(s_task_queue_event_fd >= 0, ESP_FAIL, OT_PLAT_LOG_TAG,
"Failed to create OpenThread task queue event fd"); "Failed to create OpenThread task queue event fd");
s_task_queue = xQueueCreate(config->port_config.task_queue_size, sizeof(task_storage_t)); s_task_queue = xQueueCreate(config->port_config.task_queue_size, sizeof(task_storage_t));
ESP_RETURN_ON_FALSE(s_task_queue != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, if (s_task_queue == NULL) {
"Failed to create OpenThread task queue"); close(s_task_queue_event_fd);
s_task_queue_event_fd = -1;
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to create OpenThread task queue");
return ESP_ERR_NO_MEM;
}
return esp_openthread_platform_workflow_register(&esp_openthread_task_queue_update, return esp_openthread_platform_workflow_register(&esp_openthread_task_queue_update,
&esp_openthread_task_queue_process, task_queue_workflow); &esp_openthread_task_queue_process, task_queue_workflow);
} }
@@ -18,11 +18,14 @@
#define OT_MSGPOOL_NUM_BUFFERS_NO_PSRAM 65 #define OT_MSGPOOL_NUM_BUFFERS_NO_PSRAM 65
static int s_buffer_pool_head = -1; static int s_buffer_pool_head = -1;
static uint16_t s_buffer_pool_size = 0;
static otMessageBuffer **s_buffer_pool_pointer = NULL; static otMessageBuffer **s_buffer_pool_pointer = NULL;
static otMessageBuffer *s_buffer_pool = NULL; static otMessageBuffer *s_buffer_pool = NULL;
void otPlatMessagePoolInit(otInstance *aInstance, uint16_t aMinNumFreeBuffers, size_t aBufferSize) void otPlatMessagePoolInit(otInstance *aInstance, uint16_t aMinNumFreeBuffers, size_t aBufferSize)
{ {
assert(aBufferSize % sizeof(otMessageBuffer) == 0);
uint16_t num_buffers = aMinNumFreeBuffers; uint16_t num_buffers = aMinNumFreeBuffers;
if (!esp_psram_is_initialized() && num_buffers > OT_MSGPOOL_NUM_BUFFERS_NO_PSRAM) { if (!esp_psram_is_initialized() && num_buffers > OT_MSGPOOL_NUM_BUFFERS_NO_PSRAM) {
@@ -41,6 +44,7 @@ void otPlatMessagePoolInit(otInstance *aInstance, uint16_t aMinNumFreeBuffers, s
s_buffer_pool_pointer[i] = buffer_pool + i * aBufferSize / sizeof(otMessageBuffer); s_buffer_pool_pointer[i] = buffer_pool + i * aBufferSize / sizeof(otMessageBuffer);
} }
s_buffer_pool_head = num_buffers - 1; s_buffer_pool_head = num_buffers - 1;
s_buffer_pool_size = num_buffers;
s_buffer_pool = buffer_pool; s_buffer_pool = buffer_pool;
ESP_LOGI(OT_PLAT_LOG_TAG, "Create message buffer pool successfully, size %d", num_buffers * aBufferSize); ESP_LOGI(OT_PLAT_LOG_TAG, "Create message buffer pool successfully, size %d", num_buffers * aBufferSize);
} }
@@ -57,6 +61,7 @@ otMessageBuffer *otPlatMessagePoolNew(otInstance *aInstance)
void otPlatMessagePoolFree(otInstance *aInstance, otMessageBuffer *aBuffer) void otPlatMessagePoolFree(otInstance *aInstance, otMessageBuffer *aBuffer)
{ {
assert(s_buffer_pool_head + 1 < s_buffer_pool_size);
s_buffer_pool_head++; s_buffer_pool_head++;
s_buffer_pool_pointer[s_buffer_pool_head] = aBuffer; s_buffer_pool_pointer[s_buffer_pool_head] = aBuffer;
} }
@@ -77,4 +82,5 @@ void otPlatMessagePoolDeinit(otInstance *aInstance)
s_buffer_pool = NULL; s_buffer_pool = NULL;
} }
s_buffer_pool_head = -1; s_buffer_pool_head = -1;
s_buffer_pool_size = 0;
} }
@@ -81,7 +81,7 @@ static uint32_t s_csl_sample_time;
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
static uint32_t s_mac_frame_counter; static uint32_t s_mac_frame_counter;
static uint8_t s_key_id; static uint8_t s_key_id;
static struct otMacKeyMaterial s_pervious_key; static struct otMacKeyMaterial s_previous_key;
static struct otMacKeyMaterial s_current_key; static struct otMacKeyMaterial s_current_key;
static struct otMacKeyMaterial s_next_key; static struct otMacKeyMaterial s_next_key;
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
@@ -101,7 +101,7 @@ static void ot_set_security_key_from_key_material(struct otMacKeyMaterial a_key_
/* Key bytes are pre-exported in task context (otPlatRadioSetMacKey). /* Key bytes are pre-exported in task context (otPlatRadioSetMacKey).
* Identify which cached buffer to use by comparing the key reference. * Identify which cached buffer to use by comparing the key reference.
* Jira TZ-2472 */ * Jira TZ-2472 */
if (a_key_material.mKeyMaterial.mKeyRef == s_pervious_key.mKeyMaterial.mKeyRef) { if (a_key_material.mKeyMaterial.mKeyRef == s_previous_key.mKeyMaterial.mKeyRef) {
memcpy(s_security_key, s_pervious_key_bytes, 16); memcpy(s_security_key, s_pervious_key_bytes, 16);
} else if (a_key_material.mKeyMaterial.mKeyRef == s_next_key.mKeyMaterial.mKeyRef) { } else if (a_key_material.mKeyMaterial.mKeyRef == s_next_key.mKeyMaterial.mKeyRef) {
memcpy(s_security_key, s_next_key_bytes, 16); memcpy(s_security_key, s_next_key_bytes, 16);
@@ -165,7 +165,7 @@ esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *conf
void esp_openthread_radio_deinit(void) void esp_openthread_radio_deinit(void)
{ {
if (s_radio_event_fd > 0) { if (s_radio_event_fd != -1) {
close(s_radio_event_fd); close(s_radio_event_fd);
s_radio_event_fd = -1; s_radio_event_fd = -1;
} }
@@ -521,7 +521,7 @@ void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKe
assert(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL); assert(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL);
s_key_id = aKeyId; s_key_id = aKeyId;
s_pervious_key = *aPrevKey; s_previous_key = *aPrevKey;
s_current_key = *aCurrKey; s_current_key = *aCurrKey;
s_next_key = *aNextKey; s_next_key = *aNextKey;
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
@@ -656,7 +656,7 @@ static esp_err_t IRAM_ATTR enh_ack_set_security_addr_and_key(otRadioFrame *ack_f
if (key_id == s_key_id) { if (key_id == s_key_id) {
key = &s_current_key; key = &s_current_key;
} else if (key_id == s_key_id - 1) { } else if (key_id == s_key_id - 1) {
key = &s_pervious_key; key = &s_previous_key;
} else if (key_id == s_key_id + 1) { } else if (key_id == s_key_id + 1) {
key = &s_next_key; key = &s_next_key;
} else { } else {
@@ -729,6 +729,7 @@ void IRAM_ATTR esp_ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_i
if (atomic_load(&s_recv_queue.used) == CONFIG_IEEE802154_RX_BUFFER_SIZE) { if (atomic_load(&s_recv_queue.used) == CONFIG_IEEE802154_RX_BUFFER_SIZE) {
ESP_EARLY_LOGE(OT_PLAT_LOG_TAG, "radio receive buffer full!"); ESP_EARLY_LOGE(OT_PLAT_LOG_TAG, "radio receive buffer full!");
esp_ieee802154_receive_handle_done(data);
return; return;
} }
@@ -414,7 +414,11 @@ otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArg
char *end = cmd + sizeof(cmd); char *end = cmd + sizeof(cmd);
for (int index = 0; index < aArgsLength; index++) { for (int index = 0; index < aArgsLength; index++) {
cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", aArgs[index]); if (end > cur + strlen(aArgs[index])) {
cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", aArgs[index]);
} else {
return OT_ERROR_INVALID_ARGS;
}
} }
return s_radio.PlatDiagProcess(cmd); return s_radio.PlatDiagProcess(cmd);
@@ -223,4 +223,5 @@ otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
void otPlatSettingsWipe(otInstance *aInstance) void otPlatSettingsWipe(otInstance *aInstance)
{ {
nvs_erase_all(s_ot_nvs_handle); nvs_erase_all(s_ot_nvs_handle);
nvs_commit(s_ot_nvs_handle);
} }
@@ -36,6 +36,7 @@ esp_err_t esp_openthread_sleep_init(void)
void esp_openthread_sleep_process(void) void esp_openthread_sleep_process(void)
{ {
assert(s_pm_lock != NULL);
if (s_ot_sleep == false && esp_ieee802154_get_state() == ESP_IEEE802154_RADIO_SLEEP) { if (s_ot_sleep == false && esp_ieee802154_get_state() == ESP_IEEE802154_RADIO_SLEEP) {
esp_pm_lock_release(s_pm_lock); esp_pm_lock_release(s_pm_lock);
s_ot_sleep = true; s_ot_sleep = true;
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -67,21 +67,22 @@ static void IRAM_ATTR handle_spi_transaction_done(spi_slave_transaction_t *trans
trans->rx_buffer, pending_transaction->input_buf_len, trans->trans_len)) { trans->rx_buffer, pending_transaction->input_buf_len, trans->trans_len)) {
esp_openthread_task_queue_post(s_process_callback, s_context); esp_openthread_task_queue_post(s_process_callback, s_context);
} }
trans = NULL;
} }
esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_t *config) esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_t *config)
{ {
esp_err_t ret = ESP_OK;
s_spi_config = heap_caps_malloc(sizeof(esp_openthread_spi_slave_config_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); s_spi_config = heap_caps_malloc(sizeof(esp_openthread_spi_slave_config_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(s_spi_config != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, ESP_GOTO_ON_FALSE(s_spi_config != NULL, ESP_ERR_NO_MEM, err, OT_PLAT_LOG_TAG,
"failed to allocate memory for SPI transaction on internal heap"); "failed to allocate memory for SPI transaction on internal heap");
memcpy(s_spi_config, &(config->host_config.spi_slave_config), sizeof(esp_openthread_spi_slave_config_t)); memcpy(s_spi_config, &(config->host_config.spi_slave_config), sizeof(esp_openthread_spi_slave_config_t));
gpio_config_t io_conf = { gpio_config_t io_conf = {
.intr_type = GPIO_INTR_DISABLE, .intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_OUTPUT, .mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = (1 << s_spi_config->intr_pin), .pin_bit_mask = (1ULL << s_spi_config->intr_pin),
}; };
ESP_RETURN_ON_ERROR(gpio_config(&io_conf), OT_PLAT_LOG_TAG, "fail to configure SPI gpio"); ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, OT_PLAT_LOG_TAG, "fail to configure SPI gpio");
gpio_set_pull_mode(s_spi_config->bus_config.mosi_io_num, GPIO_PULLUP_ONLY); gpio_set_pull_mode(s_spi_config->bus_config.mosi_io_num, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(s_spi_config->bus_config.sclk_io_num, GPIO_PULLUP_ONLY); gpio_set_pull_mode(s_spi_config->bus_config.sclk_io_num, GPIO_PULLUP_ONLY);
@@ -90,11 +91,9 @@ esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_
s_spi_transaction = heap_caps_malloc(sizeof(spi_slave_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); s_spi_transaction = heap_caps_malloc(sizeof(spi_slave_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
s_pending_transaction = heap_caps_malloc(sizeof(pending_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); s_pending_transaction = heap_caps_malloc(sizeof(pending_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (s_spi_transaction == NULL || s_pending_transaction == NULL) { if (s_spi_transaction == NULL || s_pending_transaction == NULL) {
heap_caps_free(s_spi_config);
heap_caps_free(s_spi_transaction);
heap_caps_free(s_pending_transaction);
ESP_LOGE(OT_PLAT_LOG_TAG, "failed to allocate memory for SPI transaction on internal heap"); ESP_LOGE(OT_PLAT_LOG_TAG, "failed to allocate memory for SPI transaction on internal heap");
return ESP_ERR_NO_MEM; ret = ESP_ERR_NO_MEM;
goto err;
} }
s_spi_transaction->user = (void *)s_pending_transaction; s_spi_transaction->user = (void *)s_pending_transaction;
@@ -102,11 +101,20 @@ esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_
/* Initialize SPI slave interface */ /* Initialize SPI slave interface */
s_spi_config->slave_config.post_setup_cb = handle_spi_setup_done; s_spi_config->slave_config.post_setup_cb = handle_spi_setup_done;
s_spi_config->slave_config.post_trans_cb = handle_spi_transaction_done; s_spi_config->slave_config.post_trans_cb = handle_spi_transaction_done;
ESP_RETURN_ON_ERROR(spi_slave_initialize(s_spi_config->host_device, &s_spi_config->bus_config, ESP_GOTO_ON_ERROR(spi_slave_initialize(s_spi_config->host_device, &s_spi_config->bus_config,
&s_spi_config->slave_config, SPI_DMA_CH_AUTO), &s_spi_config->slave_config, SPI_DMA_CH_AUTO),
OT_PLAT_LOG_TAG, "fail to initialize SPI slave"); err, OT_PLAT_LOG_TAG, "fail to initialize SPI slave");
return ESP_OK; return ESP_OK;
err:
heap_caps_free(s_spi_config);
s_spi_config = NULL;
heap_caps_free(s_spi_transaction);
s_spi_transaction = NULL;
heap_caps_free(s_pending_transaction);
s_pending_transaction = NULL;
return ret;
} }
void esp_openthread_spi_slave_deinit(void) void esp_openthread_spi_slave_deinit(void)
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -191,6 +191,8 @@ esp_err_t esp_openthread_trel_process(otInstance *aInstance, const esp_openthrea
} }
if (should_handle) { if (should_handle) {
otPlatTrelHandleReceived(aInstance, data_buf, length, source_addr); otPlatTrelHandleReceived(aInstance, data_buf, length, source_addr);
s_trel_counters.mRxPackets++;
s_trel_counters.mRxBytes += length;
} }
pbuf_free(recv_buf); pbuf_free(recv_buf);
free(data_buf_to_free); free(data_buf_to_free);
@@ -255,7 +257,13 @@ void otPlatTrelSend(otInstance *aInstance,
esp_openthread_task_switching_lock_release(); esp_openthread_task_switching_lock_release();
err = esp_netif_tcpip_exec(trel_send_task, &task); err = esp_netif_tcpip_exec(trel_send_task, &task);
esp_openthread_task_switching_lock_acquire(portMAX_DELAY); esp_openthread_task_switching_lock_acquire(portMAX_DELAY);
ESP_RETURN_ON_FALSE(err == ESP_OK, , OT_PLAT_LOG_TAG, "Failed to send TREL message"); if (err == ESP_OK) {
s_trel_counters.mTxPackets++;
s_trel_counters.mTxBytes += aUdpPayloadLen;
} else {
s_trel_counters.mTxFailure++;
ESP_LOGW(OT_PLAT_LOG_TAG, "Failed to send TREL message");
}
} }
void otPlatTrelNotifyPeerSocketAddressDifference(otInstance *aInstance, void otPlatTrelNotifyPeerSocketAddressDifference(otInstance *aInstance,
@@ -284,8 +292,10 @@ void otPlatTrelRegisterService(otInstance *aInstance, uint16_t aPort, const uint
s_is_service_registered = true; s_is_service_registered = true;
uint16_t index = 0; uint16_t index = 0;
while (index < aTxtLength) { while (index < aTxtLength) {
const uint8_t *item_header = aTxtData + index + 1;
uint8_t item_len = aTxtData[index]; uint8_t item_len = aTxtData[index];
ESP_GOTO_ON_FALSE(index + 1 + item_len <= aTxtLength, ESP_FAIL, exit, OT_PLAT_LOG_TAG,
"Malformed _trel._udp TXT record: item exceeds data length");
const uint8_t *item_header = aTxtData + index + 1;
char key[UINT8_MAX + 1]; char key[UINT8_MAX + 1];
for (uint16_t i = 0; i < item_len; i++) { for (uint16_t i = 0; i < item_len; i++) {
@@ -348,6 +358,7 @@ void otPlatTrelDisable(otInstance *aInstance)
free_all_buffer(); free_all_buffer();
close(s_trel_event_fd); close(s_trel_event_fd);
s_trel_event_fd = -1; s_trel_event_fd = -1;
s_trel_netif = NULL;
} }
const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance) const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance)
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -30,7 +30,8 @@
#endif #endif
static int s_uart_port; static int s_uart_port;
static int s_uart_fd; static int s_uart_fd = -1;
static bool s_uart_driver_installed = false;
static uint8_t s_uart_buffer[ESP_OPENTHREAD_UART_BUFFER_SIZE]; static uint8_t s_uart_buffer[ESP_OPENTHREAD_UART_BUFFER_SIZE];
static const char *uart_workflow = "uart"; static const char *uart_workflow = "uart";
@@ -89,6 +90,7 @@ esp_err_t esp_openthread_uart_init_port(const esp_openthread_uart_config_t *conf
OT_PLAT_LOG_TAG, "uart_set_pin failed"); OT_PLAT_LOG_TAG, "uart_set_pin failed");
ESP_RETURN_ON_ERROR(uart_driver_install(config->port, ESP_OPENTHREAD_UART_BUFFER_SIZE, 0, 0, NULL, 0), ESP_RETURN_ON_ERROR(uart_driver_install(config->port, ESP_OPENTHREAD_UART_BUFFER_SIZE, 0, 0, NULL, 0),
OT_PLAT_LOG_TAG, "uart_driver_install failed"); OT_PLAT_LOG_TAG, "uart_driver_install failed");
s_uart_driver_installed = true;
uart_vfs_dev_use_driver(config->port); uart_vfs_dev_use_driver(config->port);
return ESP_OK; return ESP_OK;
} }
@@ -173,7 +175,10 @@ void esp_openthread_uart_deinit()
close(s_uart_fd); close(s_uart_fd);
s_uart_fd = -1; s_uart_fd = -1;
} }
uart_driver_delete(s_uart_port); if (s_uart_driver_installed) {
uart_driver_delete(s_uart_port);
s_uart_driver_installed = false;
}
esp_openthread_platform_workflow_unregister(uart_workflow); esp_openthread_platform_workflow_unregister(uart_workflow);
} }
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -135,8 +135,12 @@ static void udp_recv_task(void *ctx)
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to copy OpenThread message when receiving OpenThread plat UDP")); ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to copy OpenThread message when receiving OpenThread plat UDP"));
task->socket->mHandler(task->socket->mContext, message, &message_info); task->socket->mHandler(task->socket->mContext, message, &message_info);
otMessageFree(message); otMessageFree(message);
message = NULL;
exit: exit:
if (message != NULL) {
otMessageFree(message);
}
free(task); free(task);
if (data_buf_to_free) { if (data_buf_to_free) {
free(data_buf_to_free); free(data_buf_to_free);
@@ -156,6 +160,8 @@ static void handle_udp_recv(void *ctx, struct udp_pcb *pcb, struct pbuf *p, cons
if (task == NULL) { if (task == NULL) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to allocate recv task when receiving OpenThread plat UDP"); ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to allocate recv task when receiving OpenThread plat UDP");
pbuf_free(p);
return;
} }
task->socket = (otUdpSocket *)ctx; task->socket = (otUdpSocket *)ctx;
task->recv_buf = p; task->recv_buf = p;