diff --git a/components/esp_common/src/esp_err_to_name.c b/components/esp_common/src/esp_err_to_name.c index 14037c6725..7ace43d9e9 100644 --- a/components/esp_common/src/esp_err_to_name.c +++ b/components/esp_common/src/esp_err_to_name.c @@ -537,6 +537,12 @@ static const esp_err_msg_t esp_err_msg_table[] = { # endif # ifdef ESP_ERR_ESP_NETIF_DNS_NOT_CONFIGURED ERR_TBL_IT(ESP_ERR_ESP_NETIF_DNS_NOT_CONFIGURED), /* 20490 0x500a */ +# endif +# ifdef ESP_ERR_ESP_NETIF_MLD6_FAILED + ERR_TBL_IT(ESP_ERR_ESP_NETIF_MLD6_FAILED), /* 20490 0x500b */ +# endif +# ifdef ESP_ERR_ESP_NETIF_IP6_ADDR_FAILED + ERR_TBL_IT(ESP_ERR_ESP_NETIF_IP6_ADDR_FAILED), /* 20490 0x500a */ # endif // components/esp_common/include/esp_err.h # ifdef ESP_ERR_FLASH_BASE @@ -759,7 +765,7 @@ const char *esp_err_to_name(esp_err_t code) #ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP size_t i; - for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + for (i = 0; i < sizeof(esp_err_msg_table) / sizeof(esp_err_msg_table[0]); ++i) { if (esp_err_msg_table[i].code == code) { return esp_err_msg_table[i].msg; } @@ -774,7 +780,7 @@ const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen) #ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP size_t i; - for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + for (i = 0; i < sizeof(esp_err_msg_table) / sizeof(esp_err_msg_table[0]); ++i) { if (esp_err_msg_table[i].code == code) { strlcpy(buf, esp_err_msg_table[i].msg, buflen); return buf; diff --git a/components/esp_netif/esp_netif_defaults.c b/components/esp_netif/esp_netif_defaults.c index 8757ac9a39..73ff340314 100644 --- a/components/esp_netif/esp_netif_defaults.c +++ b/components/esp_netif/esp_netif_defaults.c @@ -39,6 +39,8 @@ const esp_netif_inherent_config_t _g_esp_netif_inherent_ppp_config = ESP_NETIF_I const esp_netif_inherent_config_t _g_esp_netif_inherent_slip_config = ESP_NETIF_INHERENT_DEFAULT_SLIP(); +const esp_netif_inherent_config_t _g_esp_netif_inherent_openthread_config = ESP_NETIF_INHERENT_DEFAULT_OPENTHREAD(); + const esp_netif_ip_info_t _g_esp_netif_soft_ap_ip = { .ip = { .addr = ESP_IP4TOADDR( 192, 168, 4, 1) }, .gw = { .addr = ESP_IP4TOADDR( 192, 168, 4, 1) }, diff --git a/components/esp_netif/esp_netif_handlers.c b/components/esp_netif/esp_netif_handlers.c index 4c3405b90a..ba1e8179f4 100644 --- a/components/esp_netif/esp_netif_handlers.c +++ b/components/esp_netif/esp_netif_handlers.c @@ -103,3 +103,31 @@ void esp_netif_action_got_ip(void *esp_netif, esp_event_base_t base, int32_t eve IP2STR(&event->ip_info.netmask), IP2STR(&event->ip_info.gw)); } + +void esp_netif_action_join_ip6_multicast_group(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data) +{ + ESP_LOGD(TAG, "esp_netif action join_ip6_multicast group with netif%p from event_id=%d", esp_netif, event_id); + const esp_ip6_addr_t *addr = (const esp_ip6_addr_t *)data; + esp_netif_join_ip6_multicast_group(esp_netif, addr); +} + +void esp_netif_action_leave_ip6_multicast_group(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data) +{ + ESP_LOGD(TAG, "esp_netif action leave_ip6_multicast_group with netif%p from event_id=%d", esp_netif, event_id); + const esp_ip6_addr_t *addr = (const esp_ip6_addr_t *)data; + esp_netif_leave_ip6_multicast_group(esp_netif, addr); +} + +void esp_netif_action_add_ip6_address(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data) +{ + ESP_LOGD(TAG, "esp_netif action add_ip6_address with netif%p from event_id=%d", esp_netif, event_id); + const ip_event_add_ip6_t *addr = (const ip_event_add_ip6_t *)data; + esp_netif_add_ip6_address(esp_netif, addr); +} + +void esp_netif_action_remove_ip6_address(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data) +{ + ESP_LOGD(TAG, "esp_netif action remove_ip6_address with netif%p from event_id=%d", esp_netif, event_id); + const esp_ip6_addr_t *addr = (const esp_ip6_addr_t *)data; + esp_netif_remove_ip6_address(esp_netif, addr); +} diff --git a/components/esp_netif/include/esp_netif.h b/components/esp_netif/include/esp_netif.h index 20f468739b..92c937c129 100644 --- a/components/esp_netif/include/esp_netif.h +++ b/components/esp_netif/include/esp_netif.h @@ -237,6 +237,54 @@ void esp_netif_action_disconnected(void *esp_netif, esp_event_base_t base, int32 */ void esp_netif_action_got_ip(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data); +/** + * @brief Default building block for network interface action upon IPv6 multicast group join + * + * @note This API can be directly used as event handler + * + * @param[in] esp_netif Handle to esp-netif instance + * @param base + * @param event_id + * @param data + */ +void esp_netif_action_join_ip6_multicast_group(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data); + +/** + * @brief Default building block for network interface action upon IPv6 multicast group leave + * + * @note This API can be directly used as event handler + * + * @param[in] esp_netif Handle to esp-netif instance + * @param base + * @param event_id + * @param data + */ +void esp_netif_action_leave_ip6_multicast_group(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data); + +/** + * @brief Default building block for network interface action upon IPv6 address added by the underlying stack + * + * @note This API can be directly used as event handler + * + * @param[in] esp_netif Handle to esp-netif instance + * @param base + * @param event_id + * @param data + */ +void esp_netif_action_add_ip6_address(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data); + +/** + * @brief Default building block for network interface action upon IPv6 address removed by the underlying stack + * + * @note This API can be directly used as event handler + * + * @param[in] esp_netif Handle to esp-netif instance + * @param base + * @param event_id + * @param data + */ +void esp_netif_action_remove_ip6_address(void *esp_netif, esp_event_base_t base, int32_t event_id, void *data); + /** * @} */ diff --git a/components/esp_netif/include/esp_netif_defaults.h b/components/esp_netif/include/esp_netif_defaults.h index 903a678e00..da01500db1 100644 --- a/components/esp_netif/include/esp_netif_defaults.h +++ b/components/esp_netif/include/esp_netif_defaults.h @@ -73,6 +73,18 @@ extern "C" { .route_prio = 20 \ }; +#define ESP_NETIF_INHERENT_DEFAULT_OPENTHREAD() \ + { \ + .flags = 0, \ + ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(mac) \ + ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(ip_info) \ + .get_ip_event = 0, \ + .lost_ip_event = 0, \ + .if_key = "OT_DEF", \ + .if_desc = "openthread", \ + .route_prio = 15 \ +}; + #define ESP_NETIF_INHERENT_DEFAULT_SLIP() \ { \ .flags = ESP_NETIF_FLAG_IS_SLIP, \ @@ -85,6 +97,7 @@ extern "C" { .route_prio = 16 \ }; + /** * @brief Default configuration reference of ethernet interface */ @@ -162,12 +175,12 @@ extern "C" { #define ESP_NETIF_BASE_DEFAULT_SLIP &_g_esp_netif_inherent_slip_config - #define ESP_NETIF_NETSTACK_DEFAULT_ETH _g_esp_netif_netstack_default_eth #define ESP_NETIF_NETSTACK_DEFAULT_WIFI_STA _g_esp_netif_netstack_default_wifi_sta #define ESP_NETIF_NETSTACK_DEFAULT_WIFI_AP _g_esp_netif_netstack_default_wifi_ap #define ESP_NETIF_NETSTACK_DEFAULT_PPP _g_esp_netif_netstack_default_ppp #define ESP_NETIF_NETSTACK_DEFAULT_SLIP _g_esp_netif_netstack_default_slip +#define ESP_NETIF_NETSTACK_DEFAULT_OPENTHREAD _g_esp_netif_netstack_default_openthread // // Include default network stacks configs @@ -194,6 +207,27 @@ extern const esp_netif_inherent_config_t _g_esp_netif_inherent_slip_config; extern const esp_netif_ip_info_t _g_esp_netif_soft_ap_ip; +#if CONFIG_OPENTHREAD_ENABLED +/** +* @brief Default configuration reference of SLIP client +*/ +#define ESP_NETIF_DEFAULT_OPENTHREAD() \ + { \ + .base = ESP_NETIF_BASE_DEFAULT_OPENTHREAD, \ + .driver = NULL, \ + .stack = ESP_NETIF_NETSTACK_DEFAULT_OPENTHREAD, \ + } + +/** + * @brief Default base config (esp-netif inherent) of openthread interface + */ +#define ESP_NETIF_BASE_DEFAULT_OPENTHREAD &_g_esp_netif_inherent_openthread_config + +extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_openthread; +extern const esp_netif_inherent_config_t _g_esp_netif_inherent_openthread_config; + +#endif // CONFIG_OPENTHREAD_ENABLED + #ifdef __cplusplus } #endif diff --git a/components/esp_netif/include/esp_netif_types.h b/components/esp_netif/include/esp_netif_types.h index 7c68c7172a..c6a7f3d623 100644 --- a/components/esp_netif/include/esp_netif_types.h +++ b/components/esp_netif/include/esp_netif_types.h @@ -33,6 +33,8 @@ extern "C" { #define ESP_ERR_ESP_NETIF_DRIVER_ATTACH_FAILED ESP_ERR_ESP_NETIF_BASE + 0x08 #define ESP_ERR_ESP_NETIF_INIT_FAILED ESP_ERR_ESP_NETIF_BASE + 0x09 #define ESP_ERR_ESP_NETIF_DNS_NOT_CONFIGURED ESP_ERR_ESP_NETIF_BASE + 0x0A +#define ESP_ERR_ESP_NETIF_MLD6_FAILED ESP_ERR_ESP_NETIF_BASE + 0x0B +#define ESP_ERR_ESP_NETIF_IP6_ADDR_FAILED ESP_ERR_ESP_NETIF_BASE + 0x0C /** @brief Type of esp_netif_object server */ @@ -125,6 +127,12 @@ typedef struct { int ip_index; /*!< IPv6 address index */ } ip_event_got_ip6_t; +/** Event structure for ADD_IP6 event */ +typedef struct { + esp_ip6_addr_t addr; /*!< The address to be added to the interface */ + bool preferred; /*!< The default preference of the address */ +} ip_event_add_ip6_t; + /** Event structure for IP_EVENT_AP_STAIPASSIGNED event */ typedef struct { esp_ip4_addr_t ip; /*!< IP address which was assigned to the station */ diff --git a/components/esp_netif/loopback/esp_netif_loopback.c b/components/esp_netif/loopback/esp_netif_loopback.c index 86f48e4f1d..e50b3b8785 100644 --- a/components/esp_netif/loopback/esp_netif_loopback.c +++ b/components/esp_netif/loopback/esp_netif_loopback.c @@ -455,4 +455,24 @@ int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif) return 0; } +esp_err_t esp_netif_join_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_leave_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_add_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr, uint8_t preference) +{ + return ESP_ERR_NOT_SUPPORTED; +} + +esp_err_t esp_netif_remove_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) +{ + return ESP_ERR_NOT_SUPPORTED; +} + #endif /* CONFIG_ESP_NETIF_LOOPBACK */ diff --git a/components/esp_netif/lwip/esp_netif_lwip.c b/components/esp_netif/lwip/esp_netif_lwip.c index a352f03df7..ae3f16854a 100644 --- a/components/esp_netif/lwip/esp_netif_lwip.c +++ b/components/esp_netif/lwip/esp_netif_lwip.c @@ -16,6 +16,7 @@ #include #include +#include "esp_check.h" #include "esp_netif_lwip_internal.h" #include "esp_netif.h" @@ -27,6 +28,7 @@ #include "lwip/dhcp.h" #include "lwip/ip_addr.h" #include "lwip/ip6_addr.h" +#include "lwip/mld6.h" #include "lwip/nd6.h" #include "lwip/priv/tcpip_priv.h" #include "lwip/netif.h" @@ -1861,4 +1863,95 @@ esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char* name) return ESP_OK; } +#if CONFIG_LWIP_IPV6 + +static esp_err_t esp_netif_join_ip6_multicast_group_api(esp_netif_api_msg_t *msg) +{ + esp_ip6_addr_t *addr = (esp_ip6_addr_t *)msg->data; + esp_err_t error = ESP_OK; + ip6_addr_t ip6addr; + + ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif); + memcpy(ip6addr.addr, addr->addr, sizeof(ip6addr.addr)); +#if LWIP_IPV6_SCOPES + ip6addr.zone = 0; +#endif + if (mld6_joingroup_netif(msg->esp_netif->lwip_netif, &ip6addr) != ERR_OK) { + error = ESP_ERR_ESP_NETIF_MLD6_FAILED; + ESP_LOGE(TAG, "failed to join ip6 multicast group"); + } + return error; +} + +esp_err_t esp_netif_join_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) + _RUN_IN_LWIP_TASK(esp_netif_join_ip6_multicast_group_api, esp_netif, addr) + +static esp_err_t esp_netif_leave_ip6_multicast_group_api(esp_netif_api_msg_t *msg) +{ + esp_ip6_addr_t *addr = (esp_ip6_addr_t *)msg->data; + ip6_addr_t ip6addr; + + ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif); + memcpy(ip6addr.addr, addr->addr, sizeof(ip6addr.addr)); +#if LWIP_IPV6_SCOPES + ip6addr.zone = 0; +#endif + ESP_RETURN_ON_FALSE(mld6_leavegroup_netif(msg->esp_netif->lwip_netif, &ip6addr) != ERR_OK, + ESP_ERR_ESP_NETIF_MLD6_FAILED, TAG, "Failed to leave ip6 multicast group"); + return ESP_OK; +} + +esp_err_t esp_netif_leave_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) + _RUN_IN_LWIP_TASK(esp_netif_leave_ip6_multicast_group_api, esp_netif, addr) + +static esp_err_t esp_netif_add_ip6_address_api(esp_netif_api_msg_t *msg) +{ + ip_event_add_ip6_t *addr = (ip_event_add_ip6_t *)msg->data; + ip6_addr_t ip6addr; + esp_err_t error = ESP_OK; + int8_t index = -1; + + ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif); + memcpy(ip6addr.addr, addr->addr.addr, sizeof(ip6addr.addr)); +#if LWIP_IPV6_SCOPES + ip6addr.zone = 0; +#endif + err_t err = netif_add_ip6_address(msg->esp_netif->lwip_netif, &ip6addr, &index); + ESP_RETURN_ON_FALSE(err == ERR_OK && index >= 0, ESP_ERR_ESP_NETIF_IP6_ADDR_FAILED, TAG, + "Failed to add ip6 address"); + + netif_ip6_addr_set_state(msg->esp_netif->lwip_netif, index, + addr->preferred ? IP6_ADDR_PREFERRED : IP6_ADDR_DEPRECATED); + ip_event_got_ip6_t evt = {.esp_netif = msg->esp_netif, .if_index = -1, .ip_index = index}; + evt.ip6_info.ip = addr->addr; + ESP_RETURN_ON_ERROR(esp_event_send_internal(IP_EVENT, IP_EVENT_GOT_IP6, &evt, sizeof(evt), 0), TAG, + "Failed to post IP_EVENT_GOT_IP6"); + return error; +} + +esp_err_t esp_netif_add_ip6_address(esp_netif_t *esp_netif, const ip_event_add_ip6_t *addr) + _RUN_IN_LWIP_TASK(esp_netif_add_ip6_address_api, esp_netif, addr) + +static esp_err_t esp_netif_remove_ip6_address_api(esp_netif_api_msg_t *msg) +{ + esp_ip6_addr_t *addr = (esp_ip6_addr_t *)msg->data; + ip6_addr_t ip6addr; + + ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif); + memcpy(ip6addr.addr, addr->addr, sizeof(ip6addr.addr)); +#if LWIP_IPV6_SCOPES + ip6addr.zone = 0; +#endif + int8_t index = netif_get_ip6_addr_match(msg->esp_netif->lwip_netif, &ip6addr); + if (index != -1) { + netif_ip6_addr_set_state(msg->esp_netif->lwip_netif, index, IP6_ADDR_INVALID); + } + return ESP_OK; +} + +esp_err_t esp_netif_remove_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr) + _RUN_IN_LWIP_TASK(esp_netif_remove_ip6_address_api, esp_netif, addr) + +#endif // CONFIG_LWIP_IPV6 + #endif /* CONFIG_ESP_NETIF_TCPIP_LWIP */ diff --git a/components/esp_netif/lwip/esp_netif_lwip_defaults.c b/components/esp_netif/lwip/esp_netif_lwip_defaults.c index 91a6196a3c..28e623e688 100644 --- a/components/esp_netif/lwip/esp_netif_lwip_defaults.c +++ b/components/esp_netif/lwip/esp_netif_lwip_defaults.c @@ -20,6 +20,9 @@ #include "netif/wlanif.h" #include "netif/ethernetif.h" +#if CONFIG_OPENTHREAD_ENABLED +#include "netif/openthreadif.h" +#endif // // Purpose of this object is to define default network stack configuration @@ -56,10 +59,19 @@ static const struct esp_netif_netstack_config s_netif_config_ppp = { } }; - const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_eth = &s_eth_netif_config; const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_sta = &s_wifi_netif_config_sta; const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_ap = &s_wifi_netif_config_ap; const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_ppp = &s_netif_config_ppp; +#if CONFIG_OPENTHREAD_ENABLED +static const struct esp_netif_netstack_config s_netif_config_openthread = { + .lwip = { + .init_fn = openthread_netif_init, + .input_fn = openthread_netif_input, + } +}; +const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_openthread = &s_netif_config_openthread; +#endif // CONFIG_OPENTHREAD_ENABLED + #endif /*CONFIG_ESP_NETIF_TCPIP_LWIP*/ diff --git a/components/esp_netif/private_include/esp_netif_private.h b/components/esp_netif/private_include/esp_netif_private.h index b34711d163..f5355614c9 100644 --- a/components/esp_netif/private_include/esp_netif_private.h +++ b/components/esp_netif/private_include/esp_netif_private.h @@ -145,4 +145,60 @@ void esp_netif_list_unlock(void); */ bool esp_netif_is_netif_listed(esp_netif_t *esp_netif); +/** + * @brief Cause the TCP/IP stack to join a multicast group + * + * @param[in] esp_netif Handle to esp-netif instance + * @param[in] addr The multicast group to join + * + * @return + * - ESP_OK + * - ESP_ERR_ESP_NETIF_INVALID_PARAMS + * - ESP_ERR_ESP_NETIF_MLD6_FAILED + * - ESP_ERR_NO_MEM + */ +esp_err_t esp_netif_join_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr); + +/** + * @brief Cause the TCP/IP stack to leave a multicast group + * + * @param[in] esp_netif Handle to esp-netif instance + * @param[in] addr The multicast group to leave + * + * @return + * - ESP_OK + * - ESP_ERR_ESP_NETIF_INVALID_PARAMS + * - ESP_ERR_ESP_NETIF_MLD6_FAILED + * - ESP_ERR_NO_MEM + */ +esp_err_t esp_netif_leave_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr); + +/** + * @brief Cause the TCP/IP stack to add an IPv6 address to the interface + * + * @param[in] esp_netif Handle to esp-netif instance + * @param[in] addr The address to be added + * + * @return + * - ESP_OK + * - ESP_ERR_ESP_NETIF_INVALID_PARAMS + * - ESP_ERR_ESP_NETIF_IP6_ADDR_FAILED + * - ESP_ERR_NO_MEM + */ +esp_err_t esp_netif_add_ip6_address(esp_netif_t *esp_netif, const ip_event_add_ip6_t *addr); + +/** + * @brief Cause the TCP/IP stack to remove an IPv6 address from the interface + * + * @param[in] esp_netif Handle to esp-netif instance + * @param[in] addr The address to be removed + * + * @return + * - ESP_OK + * - ESP_ERR_ESP_NETIF_INVALID_PARAMS + * - ESP_ERR_ESP_NETIF_IP6_ADDR_FAILED + * - ESP_ERR_NO_MEM + */ +esp_err_t esp_netif_remove_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr); + #endif //_ESP_NETIF_PRIVATE_H_ diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 92ab45a9fd..d920197912 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -137,11 +137,15 @@ else() list(APPEND srcs "port/esp32/no_vfs_syscalls.c") endif() +if(CONFIG_OPENTHREAD_ENABLED) + list(APPEND srcs "port/esp32/netif/openthreadif.c") +endif() + idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" LDFRAGMENTS linker.lf REQUIRES vfs esp_wifi - PRIV_REQUIRES esp_eth esp_netif tcpip_adapter nvs_flash) + PRIV_REQUIRES esp_eth esp_netif tcpip_adapter nvs_flash openthread) # lots of LWIP source files evaluate macros that check address of stack variables target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address) diff --git a/components/lwip/component.mk b/components/lwip/component.mk index 6b9ca1df69..63b6fced76 100644 --- a/components/lwip/component.mk +++ b/components/lwip/component.mk @@ -35,6 +35,9 @@ ifndef CONFIG_VFS_SUPPORT_IO else COMPONENT_OBJEXCLUDE += port/esp32/no_vfs_syscalls.o endif +ifndef CONFIG_OPENTHREAD_ENABLED + COMPONENT_OBJEXCLUDE += port/esp32/netif/openthreadif.o +endif ifdef CONFIG_LWIP_PPP_SUPPORT COMPONENT_SRCDIRS += lwip/src/netif/ppp lwip/src/netif/ppp/polarssl diff --git a/components/lwip/port/esp32/include/netif/openthreadif.h b/components/lwip/port/esp32/include/netif/openthreadif.h new file mode 100644 index 0000000000..066e973ad2 --- /dev/null +++ b/components/lwip/port/esp32/include/netif/openthreadif.h @@ -0,0 +1,52 @@ +// Copyright 2021 Espressif Systems (Shanghai) CO LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#ifndef _OPENTHREAD_LWIP_IF_H_ +#define _OPENTHREAD_LWIP_IF_H_ + +#include "lwip/netif.h" +#include "lwip/err.h" +#include "lwip/ip6.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief This function initializes the OpenThread lwIP network interface. + * + * @param[in] netif The lwIP interface to initialize + * + * @return + * - ERR_OK + * + */ +err_t openthread_netif_init(struct netif *netif); + +/** + * @brief This function sends the buffer to the lwIP network interface + * + * @param[in] netif The lwIP interface to send to. + * @param[in] buffer The packet to send. + * @param[in] len The length of the buffer. + * @param[in] eb Unused. + * + */ +void openthread_netif_input(void *netif, void *buffer, size_t len, void *eb); + +#ifdef __cplusplus +} +#endif + +#endif /* _OPENTHREAD_LWIP_IF_H_ */ diff --git a/components/lwip/port/esp32/netif/openthreadif.c b/components/lwip/port/esp32/netif/openthreadif.c new file mode 100644 index 0000000000..fdfce6572f --- /dev/null +++ b/components/lwip/port/esp32/netif/openthreadif.c @@ -0,0 +1,113 @@ +// Copyright 2021 Espressif Systems (Shanghai) CO LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + + +#include + +#include "esp_netif.h" +#include "esp_netif_net_stack.h" +#include "lwip/netif.h" +#include "netif/openthreadif.h" +#include "openthread/ip6.h" +#include "openthread/link.h" + +#define OPENTHREAD_IP6_MTU 1280 + +static void openthread_free_rx_buf_l2(struct netif *netif, void *buf) +{ + free(buf); +} + +static err_t openthread_output_ip6(struct netif *netif, struct pbuf *p, const struct ip6_addr *peer_addr) +{ + struct pbuf *q = p; + esp_netif_t *esp_netif = esp_netif_get_handle_from_netif_impl(netif); + esp_err_t ret = ESP_FAIL; + if (!esp_netif) { + LWIP_DEBUGF(NETIF_DEBUG, ("corresponding esp-netif is NULL: netif=%p pbuf=%p len=%d\n", netif, p, p->len)); + return ERR_IF; + } + + if (q->next == NULL) { + ret = esp_netif_transmit(esp_netif, q->payload, q->len); + } else { + LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug")); + q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM); + if (q != NULL) { +#if ESP_LWIP + /* This pbuf RAM was not allocated on layer2, no extra free operation needed in pbuf_free */ + q->l2_owner = NULL; + q->l2_buf = NULL; +#endif + pbuf_copy(q, p); + } else { + return ERR_MEM; + } + ret = esp_netif_transmit(esp_netif, q->payload, q->len); + /* content in payload has been copied to OpenThread queue, it's safe to free pbuf now */ + pbuf_free(q); + } + /* Check error */ + if (unlikely(ret != ESP_OK)) { + return ERR_ABRT; + } else { + return ERR_OK; + } +} + +void openthread_netif_input(void *h, void *buffer, size_t len, void *eb) +{ + struct netif *netif = h; + struct pbuf *p; + + if (unlikely(buffer == NULL || !netif_is_up(netif))) { + if (buffer) { + openthread_free_rx_buf_l2(netif, buffer); + } + return; + } + + /* acquire new pbuf, type: PBUF_REF */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); + if (p == NULL) { + openthread_free_rx_buf_l2(netif, buffer); + return; + } + p->payload = buffer; +#if ESP_LWIP + p->l2_owner = netif; + p->l2_buf = buffer; +#endif + /* full packet send to tcpip_thread to process */ + if (unlikely(netif->input(p, netif) != ERR_OK)) { + LWIP_DEBUGF(NETIF_DEBUG, ("openthread_netif_input: IP input error\n")); + pbuf_free(p); + } + /* the pbuf will be free in upper layer, eg: tcpip_input */ +} + +err_t openthread_netif_init(struct netif *netif) +{ + netif->name[0] = 'o'; + netif->name[1] = 't'; + netif->hwaddr_len = sizeof(otExtAddress); + memset(netif->hwaddr, 0, sizeof(netif->hwaddr)); + netif->mtu = OPENTHREAD_IP6_MTU; + netif->flags = NETIF_FLAG_BROADCAST; + netif->output = NULL; + netif->output_ip6 = openthread_output_ip6; + netif->l2_buffer_free_notify = openthread_free_rx_buf_l2; + netif_set_link_up(netif); + + return ERR_OK; +} diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 750e291c3e..018df2fe3c 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -65,4 +65,11 @@ menu "OpenThread" help The storage size should be at least 8192 bytes. + config OPENTHREAD_NETIF_QUEUE_SIZE + int "The size of the packet queue for OpenThread lwIP network interface" + depends on OPENTHREAD_ENABLED + default 10 + help + The size of the packet queue for OpenThread lwIP network interface. + endmenu diff --git a/components/openthread/include/esp_openthread_netif_glue.h b/components/openthread/include/esp_openthread_netif_glue.h new file mode 100644 index 0000000000..035f201fd4 --- /dev/null +++ b/components/openthread/include/esp_openthread_netif_glue.h @@ -0,0 +1,64 @@ +// Copyright 2021 Espressif Systems (Shanghai) CO LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#pragma once + +#include "esp_err.h" +#include "esp_openthread_types.h" +#include "openthread/instance.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief This function initializes the OpenThread network interface glue. + * + * @return + * - glue pointer on success + * - NULL on failure + * + */ +void *esp_openthread_netif_glue_init(void); + +/** + * @brief This function deinitializes the OpenThread network interface glue. + * + */ +void esp_openthread_netif_glue_deinit(void); + +/** + * @brief This function updates the netif fds and timeouts to the main loop. + * + * @param[inout] mainloop The main loop context. + * + */ +void esp_openthread_netif_glue_update(esp_openthread_mainloop_context_t *mainloop); + +/** + * @brief This function performs the netif process. + * + * @param[in] instance The OpenThread instance. + * + * @return + * - ESP_OK on success + * - ESP_FAIL on OpenThread failure + * - ESP_ERR_NO_MEM on memory allocation failure + * + */ +esp_err_t esp_openthread_netif_glue_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop); + +#ifdef __cplusplus +} +#endif diff --git a/components/openthread/include/esp_openthread_types.h b/components/openthread/include/esp_openthread_types.h index 83b7ff8b17..dbe7c01797 100644 --- a/components/openthread/include/esp_openthread_types.h +++ b/components/openthread/include/esp_openthread_types.h @@ -16,11 +16,33 @@ #include "hal/uart_types.h" #include "sys/select.h" +#include "esp_event_base.h" #ifdef __cplusplus extern "C" { #endif +/** +* @brief OpenThread event declarations +* +*/ +typedef enum { + OPENTHREAD_EVENT_START, /*!< OpenThread stack start */ + OPENTHREAD_EVENT_STOP, /*!< OpenThread stack stop */ + 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 */ + OPENTHREAD_EVENT_LOST_IP6, /*!< OpenThread stack removed IPv6 address */ + OPENTHREAD_EVENT_MULTICAST_GROUP_JOIN, /*!< OpenThread stack joined IPv6 multicast group */ + OPENTHREAD_EVENT_MULTICAST_GROUP_LEAVE, /*!< OpenThread stack left IPv6 multicast group */ +} esp_openthread_event_t; + +/** +* @brief OpenThread event base declaration +* +*/ +ESP_EVENT_DECLARE_BASE(OPENTHREAD_EVENT); + /** * This structure represents a context for a select() based mainloop. * diff --git a/components/openthread/port/esp_openthread.cpp b/components/openthread/port/esp_openthread.cpp index 95e2ed56ba..69a859a0b2 100644 --- a/components/openthread/port/esp_openthread.cpp +++ b/components/openthread/port/esp_openthread.cpp @@ -19,6 +19,7 @@ #include "esp_openthread_alarm.h" #include "esp_openthread_common_macro.h" #include "esp_openthread_lock.h" +#include "esp_openthread_netif_glue.h" #include "esp_openthread_radio_uart.h" #include "esp_openthread_types.h" #include "esp_openthread_uart.h" @@ -92,6 +93,7 @@ void esp_openthread_platform_update(esp_openthread_mainloop_context_t *mainloop) esp_openthread_uart_update(mainloop); } esp_openthread_radio_update(mainloop); + esp_openthread_netif_glue_update(mainloop); } esp_err_t esp_openthread_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop) @@ -101,6 +103,5 @@ esp_err_t esp_openthread_platform_process(otInstance *instance, const esp_openth } esp_openthread_radio_process(instance, mainloop); esp_openthread_alarm_process(instance); - - return ESP_OK; + return esp_openthread_netif_glue_process(instance, mainloop); } diff --git a/components/openthread/port/esp_openthread_lock.c b/components/openthread/port/esp_openthread_lock.c index a0fe2f0aaa..a3472d0b84 100644 --- a/components/openthread/port/esp_openthread_lock.c +++ b/components/openthread/port/esp_openthread_lock.c @@ -22,13 +22,13 @@ static SemaphoreHandle_t s_openthread_mutex = NULL; bool esp_openthread_lock_acquire(TickType_t block_ticks) { - BaseType_t ret = xSemaphoreTake(s_openthread_mutex, block_ticks); + BaseType_t ret = xSemaphoreTakeRecursive(s_openthread_mutex, block_ticks); return (ret == pdTRUE); } void esp_openthread_lock_release(void) { - xSemaphoreGive(s_openthread_mutex); + xSemaphoreGiveRecursive(s_openthread_mutex); } esp_err_t esp_openthread_lock_init(void) @@ -36,7 +36,7 @@ esp_err_t esp_openthread_lock_init(void) if (s_openthread_mutex != NULL) { return ESP_ERR_INVALID_STATE; } - s_openthread_mutex = xSemaphoreCreateMutex(); + s_openthread_mutex = xSemaphoreCreateRecursiveMutex(); if (s_openthread_mutex == NULL) { return ESP_ERR_NO_MEM; } diff --git a/components/openthread/port/esp_openthread_netif_glue.c b/components/openthread/port/esp_openthread_netif_glue.c new file mode 100644 index 0000000000..d031599fcd --- /dev/null +++ b/components/openthread/port/esp_openthread_netif_glue.c @@ -0,0 +1,351 @@ +// Copyright 2021 Espressif Systems (Shanghai) CO LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License + +#include "esp_openthread_netif_glue.h" + +#include +#include + +#include "esp_check.h" +#include "esp_err.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_openthread.h" +#include "esp_openthread_common_macro.h" +#include "esp_openthread_lock.h" +#include "esp_vfs_eventfd.h" +#include "sdkconfig.h" +#include "common/code_utils.hpp" +#include "common/logging.hpp" +#include "config/link_quality.h" +#include "freertos/FreeRTOS.h" +#include "openthread/error.h" +#include "openthread/icmp6.h" +#include "openthread/instance.h" +#include "openthread/ip6.h" +#include "openthread/link.h" +#include "openthread/message.h" +#include "openthread/thread.h" + +typedef struct { + esp_netif_driver_base_t base; + int event_fd; +} esp_openthread_netif_glue_t; + +static esp_openthread_netif_glue_t s_openthread_netif_glue = { + .event_fd = -1, +}; + +ESP_EVENT_DEFINE_BASE(OPENTHREAD_EVENT); + +static QueueHandle_t s_packet_queue; + +#define NETIF_OUTPUT_SIGNAL 1 + +static esp_err_t notify_packets_pending(void) +{ + uint64_t signal = NETIF_OUTPUT_SIGNAL; + ssize_t ret = write(s_openthread_netif_glue.event_fd, &signal, sizeof(signal)); + if (ret != sizeof(signal)) { + otLogWarnPlat("Thread netif failed to notify eventfd"); + return ESP_FAIL; + } + return ESP_OK; +} + +void process_thread_address(const otIp6AddressInfo *address_info, bool is_added, void *context) +{ + bool is_multicast = address_info->mAddress->mFields.m8[0] == 0xff; + esp_ip6_addr_t addr; + + memcpy(addr.addr, address_info->mAddress->mFields.m8, sizeof(addr.addr)); + if (is_added) { + if (is_multicast) { + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_MULTICAST_GROUP_JOIN, &addr, sizeof(addr), 0) != + ESP_OK) { + otLogCritPlat("Failed to post OpenThread join multicast group event"); + } + } else { + ip_event_add_ip6_t add_addr; + add_addr.addr = addr; + add_addr.preferred = !address_info->mIsAnycast; + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_GOT_IP6, &add_addr, sizeof(add_addr), 0) != ESP_OK) { + otLogCritPlat("Failed to post OpenThread got ip6 address event"); + } + } + } else { + if (is_multicast) { + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_MULTICAST_GROUP_LEAVE, &addr, sizeof(addr), 0) != + ESP_OK) { + otLogCritPlat("Failed to post OpenThread leave multicast group event"); + } + } else { + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_LOST_IP6, &addr, sizeof(addr), 0) != ESP_OK) { + otLogCritPlat("Failed to post OpenThread lost ip6 address event"); + } + } + } +} + +static void process_thread_receive(otMessage *message, void *context) +{ + esp_err_t error; + uint16_t length = otMessageGetLength(message); + uint8_t *buffer = malloc(length); + + VerifyOrExit(buffer != NULL, error = OT_ERROR_NO_BUFS); + uint16_t read_length = otMessageRead(message, 0, buffer, length); + assert(read_length == length); + + error = esp_netif_receive(s_openthread_netif_glue.base.netif, buffer, length, NULL); + buffer = NULL; + +exit: + if (error != ESP_OK) { + otLogWarnPlat("process_thread_receive failed: %s", esp_err_to_name(error)); + } + + otMessageFree(message); +} + +static esp_err_t process_thread_transmit(otInstance *instance) +{ + otMessage *msg = NULL; + esp_err_t error = ESP_OK; + uint64_t event; + + int ret = read(s_openthread_netif_glue.event_fd, &event, sizeof(event)); + assert(ret == sizeof(event)); + while (xQueueReceive(s_packet_queue, &msg, 0) == pdTRUE) { + if (msg) { + otError ot_error = otIp6Send(esp_openthread_get_instance(), msg); + if (ot_error != OT_ERROR_NONE && ot_error != OT_ERROR_DROP) { + otLogWarnPlat("ThreadNetif Failed to send OpenThread IP6 message: %s", otThreadErrorToString(ot_error)); + } + if (ot_error == OT_ERROR_DROP) { + // OpenThread will intentionally drop some multicast and ICMPv6 packets + // which are not required for the Thread network. + otLogDebgPlat("OpenThread stack filtered netif packet"); + } + if (ot_error != OT_ERROR_NONE) { + break; + } + } + } + + if (uxQueueMessagesWaiting(s_packet_queue) > 0) { + error = notify_packets_pending(); + } + + return error; +} + +static void process_thread_state(otChangedFlags changed_flags, void *context) +{ + otInstance *instance = (otInstance *)context; + esp_err_t err = ESP_OK; + + if (OT_CHANGED_THREAD_NETIF_STATE & changed_flags) { + if (otLinkIsEnabled(instance)) { + otLogInfoPlat("netif up"); + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_UP, NULL, 0, 0) != ESP_OK) { + otLogCritPlat("Failed to post OpenThread if up event"); + } + } else { + otLogInfoPlat("netif down"); + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_DOWN, NULL, 0, 0) != ESP_OK) { + otLogCritPlat("Failed to post OpenThread if down event"); + } + } + } + + if (err != ESP_OK) { + otLogCritPlat("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; + otError ot_error = OT_ERROR_NONE; + + esp_openthread_lock_acquire(portMAX_DELAY); + otMessage *message = otIp6NewMessage(esp_openthread_get_instance(), NULL); + if (message == NULL) { + otLogCritPlat("Failed to allocate OpenThread message"); + ExitNow(error = ESP_ERR_NO_MEM); + } + + ot_error = otMessageAppend(message, buffer, len); + if (ot_error != OT_ERROR_NONE) { + otLogCritPlat("Failed to copy to OpenThread message: %s", otThreadErrorToString(ot_error)); + ExitNow(error = ESP_ERR_NO_MEM); + } + + if (xQueueSend(s_packet_queue, &message, 0) != pdTRUE) { + otLogCritPlat("Failed to send to Thread netif: packet queue full"); + ExitNow(error = ESP_ERR_NO_MEM); + } + VerifyOrExit(notify_packets_pending() == ESP_OK, error = ESP_FAIL); + +exit: + if (ot_error != OT_ERROR_NONE && message != NULL) { + otMessageFree(message); + } + esp_openthread_lock_release(); + return error; +} + +static esp_err_t register_openthread_event_handlers(esp_netif_t *esp_netif) +{ + ESP_RETURN_ON_ERROR( + esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_START, esp_netif_action_start, esp_netif), + OT_PLAT_LOG_TAG, "OpenThread start event register failed"); + ESP_RETURN_ON_ERROR( + esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_STOP, esp_netif_action_stop, esp_netif), + OT_PLAT_LOG_TAG, "OpenThread stop event register failed"); + ESP_RETURN_ON_ERROR( + esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_UP, esp_netif_action_connected, esp_netif), + OT_PLAT_LOG_TAG, "OpenThread interface up event register failed"); + ESP_RETURN_ON_ERROR(esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_DOWN, + esp_netif_action_disconnected, esp_netif), + OT_PLAT_LOG_TAG, "OpenThread interface down event register failed"); + ESP_RETURN_ON_ERROR(esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_GOT_IP6, + esp_netif_action_add_ip6_address, esp_netif), + OT_PLAT_LOG_TAG, "OpenThread interface got ip6 event register failed"); + ESP_RETURN_ON_ERROR(esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_LOST_IP6, + esp_netif_action_remove_ip6_address, esp_netif), + OT_PLAT_LOG_TAG, "OpenThread interface remove ip6 event register failed"); + ESP_RETURN_ON_ERROR(esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_MULTICAST_GROUP_JOIN, + esp_netif_action_join_ip6_multicast_group, esp_netif), + OT_PLAT_LOG_TAG, "OpenThread interface join ip6 multicast group event register failed"); + ESP_RETURN_ON_ERROR(esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_MULTICAST_GROUP_LEAVE, + esp_netif_action_leave_ip6_multicast_group, esp_netif), + OT_PLAT_LOG_TAG, "OpenThread interface leave ip6 multicast group event register failed"); + return ESP_OK; +} + +static void unregister_openthread_event_handlers(void) +{ + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_START, esp_netif_action_start); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_STOP, esp_netif_action_stop); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_UP, esp_netif_action_connected); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_IF_DOWN, esp_netif_action_disconnected); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_GOT_IP6, esp_netif_action_add_ip6_address); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_LOST_IP6, esp_netif_action_remove_ip6_address); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_MULTICAST_GROUP_JOIN, + esp_netif_action_join_ip6_multicast_group); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_MULTICAST_GROUP_LEAVE, + esp_netif_action_leave_ip6_multicast_group); +} + +static esp_err_t openthread_netif_post_attach(esp_netif_t *esp_netif, void *args) +{ + esp_netif_driver_base_t *base = (esp_netif_driver_base_t *)args; + base->netif = esp_netif; + + // set driver related config to esp-netif + esp_netif_driver_ifconfig_t driver_ifconfig = { + .handle = &s_openthread_netif_glue, .transmit = openthread_netif_transmit, .driver_free_rx_buffer = NULL + }; + + ESP_ERROR_CHECK(esp_netif_set_driver_config(esp_netif, &driver_ifconfig)); + + otLogInfoPlat("OpenThread attached to netif"); + esp_err_t error = register_openthread_event_handlers(esp_netif); + if (error == ESP_OK) { + error = esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_START, NULL, 0, 0); + } + + return error; +} + +void *esp_openthread_netif_glue_init(void) +{ + otInstance *instance = esp_openthread_get_instance(); + otError ot_err; + esp_err_t error = ESP_OK; + + if (instance == NULL || s_packet_queue || s_openthread_netif_glue.event_fd >= 0) { + return NULL; + } + + s_packet_queue = xQueueCreate(CONFIG_OPENTHREAD_NETIF_QUEUE_SIZE, sizeof(otMessage *)); + if (s_packet_queue == NULL) { + otLogCritPlat("Failed to allocate Thread netif packet queue"); + ExitNow(error = ESP_ERR_NO_MEM); + } + + otIp6SetAddressCallback(instance, process_thread_address, instance); + otIp6SetReceiveCallback(instance, process_thread_receive, instance); + ot_err = otSetStateChangedCallback(instance, process_thread_state, instance); + if (ot_err != OT_ERROR_NONE) { + otLogCritPlat("Failed to register callback for OpenThread lwip interface: %s", otThreadErrorToString(ot_err)); + ExitNow(error = ESP_FAIL); + } + otIp6SetReceiveFilterEnabled(instance, true); + otIcmp6SetEchoMode(instance, OT_ICMP6_ECHO_HANDLER_DISABLED); + + s_openthread_netif_glue.event_fd = eventfd(0, 0); + if (s_openthread_netif_glue.event_fd < 0) { + otLogCritPlat("Failed to create event fd for Thread netif"); + ExitNow(error = ESP_FAIL); + } + s_openthread_netif_glue.base.post_attach = openthread_netif_post_attach; + +exit: + if (error != ESP_OK) { + return NULL; + } + + return &s_openthread_netif_glue.base; +} + +void esp_openthread_netif_glue_deinit(void) +{ + otInstance *instance = esp_openthread_get_instance(); + otRemoveStateChangeCallback(instance, process_thread_state, instance); + otIp6SetAddressCallback(instance, NULL, NULL); + otIp6SetReceiveCallback(instance, NULL, NULL); + if (s_packet_queue) { + vQueueDelete(s_packet_queue); + s_packet_queue = NULL; + } + if (s_openthread_netif_glue.event_fd >= 0) { + close(s_openthread_netif_glue.event_fd); + s_openthread_netif_glue.event_fd = -1; + } + if (esp_event_post(OPENTHREAD_EVENT, OPENTHREAD_EVENT_STOP, NULL, 0, 0) != ESP_OK) { + otLogCritPlat("Failed to stop OpenThread netif"); + } + unregister_openthread_event_handlers(); +} + +void esp_openthread_netif_glue_update(esp_openthread_mainloop_context_t *mainloop) +{ + if (s_openthread_netif_glue.event_fd >= 0) { + FD_SET(s_openthread_netif_glue.event_fd, &mainloop->read_fds); + if (s_openthread_netif_glue.event_fd > mainloop->max_fd) { + mainloop->max_fd = s_openthread_netif_glue.event_fd; + } + } +} + +esp_err_t esp_openthread_netif_glue_process(otInstance *instance, const esp_openthread_mainloop_context_t *context) +{ + if (s_openthread_netif_glue.event_fd >= 0 && FD_ISSET(s_openthread_netif_glue.event_fd, &context->read_fds)) { + return process_thread_transmit(instance); + } + return ESP_OK; +} diff --git a/examples/openthread/ot_cli/main/ot_esp_cli.c b/examples/openthread/ot_cli/main/ot_esp_cli.c index 34a1bf9e58..5cc7cd7bf5 100644 --- a/examples/openthread/ot_cli/main/ot_esp_cli.c +++ b/examples/openthread/ot_cli/main/ot_esp_cli.c @@ -16,12 +16,14 @@ #include #include "esp_err.h" +#include "esp_event.h" #include "esp_log.h" #include "esp_netif.h" #include "esp_openthread.h" #include "esp_openthread_lock.h" +#include "esp_openthread_netif_glue.h" #include "esp_openthread_types.h" -#include "sdkconfig.h" +#include "esp_vfs_eventfd.h" #include "driver/uart.h" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" @@ -79,10 +81,20 @@ static void ot_task_worker(void *aContext) }, }, }; + esp_vfs_eventfd_config_t eventfd_config = { + .max_fds = 2, + }; + + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD(); + esp_netif_t *netif = esp_netif_new(&cfg); + assert(netif != NULL); + esp_openthread_mainloop_context_t mainloop; + ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); ESP_ERROR_CHECK(esp_openthread_platform_init(&config)); otInstance *instance = otInstanceInitSingle(); + ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init())); assert(instance != NULL); esp_openthread_lock_acquire(portMAX_DELAY); @@ -120,12 +132,17 @@ static void ot_task_worker(void *aContext) } } + esp_netif_destroy(netif); + esp_openthread_netif_glue_deinit(); otInstanceFinalize(instance); esp_openthread_platform_deinit(); + esp_vfs_eventfd_unregister(); vTaskDelete(NULL); } void app_main(void) { + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_netif_init()); xTaskCreate(ot_task_worker, "ot_cli_main", 10240, xTaskGetCurrentTaskHandle(), 5, NULL); } diff --git a/examples/openthread/ot_cli/sdkconfig.defaults b/examples/openthread/ot_cli/sdkconfig.defaults index 334f459b73..a19ba9b2f0 100644 --- a/examples/openthread/ot_cli/sdkconfig.defaults +++ b/examples/openthread/ot_cli/sdkconfig.defaults @@ -31,3 +31,9 @@ CONFIG_MBEDTLS_ECJPAKE_C=y # CONFIG_OPENTHREAD_ENABLED=y # end of OpenThread + +# +# lwIP +# +CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 +# end of lwIP