From 52a68cb7fe605b194348556146a8bedef864235b Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Wed, 19 May 2021 11:52:51 +0800 Subject: [PATCH] openthread: integrate OpenThread network interface with esp_netif --- components/esp_common/src/esp_err_to_name.c | 10 +- components/esp_netif/esp_netif_defaults.c | 2 + components/esp_netif/esp_netif_handlers.c | 28 ++ components/esp_netif/include/esp_netif.h | 48 ++ .../esp_netif/include/esp_netif_defaults.h | 36 +- .../esp_netif/include/esp_netif_types.h | 8 + .../esp_netif/loopback/esp_netif_loopback.c | 20 + components/esp_netif/lwip/esp_netif_lwip.c | 93 ++++ .../esp_netif/lwip/esp_netif_lwip_defaults.c | 14 +- .../private_include/esp_netif_private.h | 56 +++ components/lwip/CMakeLists.txt | 6 +- components/lwip/component.mk | 3 + .../port/esp32/include/netif/openthreadif.h | 52 ++ .../lwip/port/esp32/netif/openthreadif.c | 113 +++++ ...ad_netif.h => esp_openthread_netif_glue.h} | 17 +- .../openthread/include/esp_openthread_types.h | 22 + components/openthread/port/esp_openthread.cpp | 7 +- .../openthread/port/esp_openthread_lock.c | 6 +- .../openthread/port/esp_openthread_netif.c | 452 ------------------ .../port/esp_openthread_netif_glue.c | 351 ++++++++++++++ examples/openthread/ot_cli/main/ot_esp_cli.c | 13 +- examples/openthread/ot_cli/sdkconfig.defaults | 6 + 22 files changed, 888 insertions(+), 475 deletions(-) create mode 100644 components/lwip/port/esp32/include/netif/openthreadif.h create mode 100644 components/lwip/port/esp32/netif/openthreadif.c rename components/openthread/include/{esp_openthread_netif.h => esp_openthread_netif_glue.h} (69%) delete mode 100644 components/openthread/port/esp_openthread_netif.c create mode 100644 components/openthread/port/esp_openthread_netif_glue.c 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/include/esp_openthread_netif.h b/components/openthread/include/esp_openthread_netif_glue.h similarity index 69% rename from components/openthread/include/esp_openthread_netif.h rename to components/openthread/include/esp_openthread_netif_glue.h index 1c7cf97d26..035f201fd4 100644 --- a/components/openthread/include/esp_openthread_netif.h +++ b/components/openthread/include/esp_openthread_netif_glue.h @@ -23,21 +23,20 @@ extern "C" { #endif /** - * @brief This function initializes the OpenThread lwIP network interface. + * @brief This function initializes the OpenThread network interface glue. * * @return - * - ESP_OK on success - * - ESP_FAIL if lwIP reports an error - * - ESP_ERR_NO_MEM if allocation has failed + * - glue pointer on success + * - NULL on failure * */ -esp_err_t esp_openthread_netif_init(void); +void *esp_openthread_netif_glue_init(void); /** - * @brief This function deinitializes the OpenThread lwIP network interface. + * @brief This function deinitializes the OpenThread network interface glue. * */ -void esp_openthread_netif_deinit(void); +void esp_openthread_netif_glue_deinit(void); /** * @brief This function updates the netif fds and timeouts to the main loop. @@ -45,7 +44,7 @@ void esp_openthread_netif_deinit(void); * @param[inout] mainloop The main loop context. * */ -void esp_openthread_netif_update(esp_openthread_mainloop_context_t *mainloop); +void esp_openthread_netif_glue_update(esp_openthread_mainloop_context_t *mainloop); /** * @brief This function performs the netif process. @@ -58,7 +57,7 @@ void esp_openthread_netif_update(esp_openthread_mainloop_context_t *mainloop); * - ESP_ERR_NO_MEM on memory allocation failure * */ -esp_err_t esp_openthread_netif_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop); +esp_err_t esp_openthread_netif_glue_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop); #ifdef __cplusplus } 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 3528d571ce..69a859a0b2 100644 --- a/components/openthread/port/esp_openthread.cpp +++ b/components/openthread/port/esp_openthread.cpp @@ -19,7 +19,7 @@ #include "esp_openthread_alarm.h" #include "esp_openthread_common_macro.h" #include "esp_openthread_lock.h" -#include "esp_openthread_netif.h" +#include "esp_openthread_netif_glue.h" #include "esp_openthread_radio_uart.h" #include "esp_openthread_types.h" #include "esp_openthread_uart.h" @@ -78,7 +78,6 @@ esp_err_t esp_openthread_platform_deinit(void) if (!s_openthread_platform_initialized) { return ESP_ERR_INVALID_STATE; } - esp_openthread_netif_deinit(); esp_openthread_radio_deinit(); if (s_platform_config.host_config.host_connection_mode == HOST_CONNECTION_MODE_UART) { esp_openthread_uart_deinit(); @@ -94,7 +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_update(mainloop); + esp_openthread_netif_glue_update(mainloop); } esp_err_t esp_openthread_platform_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop) @@ -104,5 +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_openthread_netif_process(instance, mainloop); + 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.c b/components/openthread/port/esp_openthread_netif.c deleted file mode 100644 index c086cda061..0000000000 --- a/components/openthread/port/esp_openthread_netif.c +++ /dev/null @@ -1,452 +0,0 @@ -// 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.h" - -#include -#include - -#include "common/code_utils.hpp" -#include "common/logging.hpp" -#include "esp_err.h" -#include "esp_openthread.h" -#include "esp_vfs_eventfd.h" -#include "freertos/FreeRTOS.h" -#include "lwip/err.h" -#include "lwip/ip.h" -#include "lwip/ip6.h" -#include "lwip/mld6.h" -#include "lwip/netif.h" -#include "lwip/pbuf.h" -#include "lwip/tcpip.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 { - otIp6AddressInfo address_info; - bool is_added; -} thread_netif_address_task_t; - -static int s_netif_event_fd = -1; -static struct netif s_thread_netif; -QueueHandle_t s_packet_queue; - -#define NETIF_OUTPUT_SIGNAL 1 - -#ifndef OPENTHREAD_NETIF_QUEUE_SIZE -#define OPENTHREAD_NETIF_QUEUE_SIZE CONFIG_OPENTHREAD_NETIF_QUEUE_SIZE -#endif - -static esp_err_t notify_packets_pending(void) -{ - uint64_t signal = NETIF_OUTPUT_SIGNAL; - ssize_t ret = write(s_netif_event_fd, &signal, sizeof(signal)); - if (ret != sizeof(signal)) { - otLogWarnPlat("Thread netif failed to notify eventfd"); - return ESP_FAIL; - } - return ESP_OK; -} - -static err_t netif_output_ip6(struct netif *interface, struct pbuf *buffer, const struct ip6_addr *peer_addr) -{ - err_t error = ERR_OK; - struct pbuf *copy_buf = pbuf_alloc(PBUF_LINK, buffer->tot_len, PBUF_POOL); - - otLogDebgPlat("ThreadNetif send to %s", ip6addr_ntoa(peer_addr)); - VerifyOrExit(copy_buf != NULL, error = ERR_MEM); - SuccessOrExit(error = pbuf_copy(copy_buf, buffer)); - if (xQueueSend(s_packet_queue, ©_buf, 0) != pdTRUE) { - otLogCritPlat("Failed to send to Thread netif: packet queue full"); - ExitNow(error = ERR_MEM); - } - copy_buf = NULL; - VerifyOrExit(notify_packets_pending() == ESP_OK, error = ERR_IF); - -exit: - if (copy_buf != NULL) { - pbuf_free(copy_buf); - } - return error; -} - -static err_t thread_netif_init(struct netif *interface) -{ - interface->name[0] = 'o'; - interface->name[1] = 't'; - interface->hwaddr_len = sizeof(otExtAddress); - memset(interface->hwaddr, 0, sizeof(interface->hwaddr)); - interface->mtu = OPENTHREAD_CONFIG_IP6_MAX_DATAGRAM_LENGTH; - interface->flags = NETIF_FLAG_BROADCAST; - interface->output = NULL; - interface->output_ip6 = netif_output_ip6; - interface->num = 0; - - return ERR_OK; -} - -static bool is_link_local(const ip6_addr_t *address) -{ - const uint8_t *val = (const uint8_t *)(&address); - return val[0] == 0xfe && val[1] == 0x80; -} - -static otError add_multicast_address(const ip6_addr_t *addres) -{ - otError error = OT_ERROR_NONE; - - if (mld6_joingroup_netif(&s_thread_netif, addres) != ERR_OK) { - error = OT_ERROR_FAILED; - } - - return error; -} - -static otError add_address(const ip6_addr_t *address) -{ - otError error = OT_ERROR_NONE; - err_t err = ERR_OK; - - - if (is_link_local(address)) { - netif_ip6_addr_set(&s_thread_netif, 0, address); - netif_ip6_addr_set_state(&s_thread_netif, 0, IP6_ADDR_PREFERRED); - } else { - int8_t index = -1; - const otMeshLocalPrefix *prefix = otThreadGetMeshLocalPrefix(esp_openthread_get_instance()); - - err = netif_add_ip6_address(&s_thread_netif, address, &index); - VerifyOrExit(err == ERR_OK && index != -1, error = OT_ERROR_FAILED); - if (memcmp(address, prefix, sizeof(prefix->m8)) != 0) { - netif_ip6_addr_set_state(&s_thread_netif, index, IP6_ADDR_PREFERRED); - } else { - netif_ip6_addr_set_state(&s_thread_netif, index, IP6_ADDR_VALID); - } - } - -exit: - return error; -} - -static otError remove_multicast_address(const ip6_addr_t *address) -{ - otError error = OT_ERROR_NONE; - - if (mld6_leavegroup_netif(&s_thread_netif, address) != ERR_OK) { - error = OT_ERROR_FAILED; - } - - return error; -} - -static otError remove_address(const ip6_addr_t *address) -{ - int8_t index; - otError error = OT_ERROR_NONE; - - index = netif_get_ip6_addr_match(&s_thread_netif, address); - VerifyOrExit(index != -1, error = OT_ERROR_NOT_FOUND); - netif_ip6_addr_set_state(&s_thread_netif, index, IP6_ADDR_INVALID); - -exit: - return error; -} - - -static void process_thread_address_task(void *ctx) -{ - // All multicast addresses have prefix ff00::/8 - thread_netif_address_task_t *task = (thread_netif_address_task_t *)ctx; - bool is_multicast = (task->address_info.mAddress->mFields.m8[0] == 0xff); - ip6_addr_t address; - otError error = OT_ERROR_NONE; - - memset(&address, 0, sizeof(address)); - memcpy(&address.addr, &(task->address_info.mAddress->mFields.m8), sizeof(address.addr)); - otLogInfoPlat("address %s: %s", task->is_added ? "added" : "removed", ip6addr_ntoa(&address)); - - if (task->is_added) { - if (is_multicast) { - error = add_multicast_address(&address); - } else { - error = add_address(&address); - } - } else { - if (is_multicast) { - error = remove_multicast_address(&address); - } else { - error = remove_address(&address); - } - } - - if (error != OT_ERROR_NONE) { - otLogCritPlat("Failed to process address: %s", otThreadErrorToString(error)); - } - free(task); -} - -void process_thread_address(const otIp6AddressInfo *address_info, bool is_added, void *context) -{ - thread_netif_address_task_t *task = malloc(sizeof(thread_netif_address_task_t)); - - task->address_info = *address_info; - task->is_added = is_added; - - if (task == NULL) { - otLogCritPlat("Cannot allocate address task"); - } - if (tcpip_callback(process_thread_address_task, task) != ERR_OK) { - free(task); - } -} - -static void netif_input_task(void *ctx) -{ - struct pbuf *buffer = (struct pbuf *)ctx; - if (s_thread_netif.input(buffer, &s_thread_netif) != ERR_OK) { - otLogCritPlat("Failed to send OpenThread message to lwIP network interface"); - pbuf_free(buffer); - } -} - -static void process_thread_receive(otMessage *message, void *context) -{ - otError error = OT_ERROR_NONE; - err_t err = ERR_OK; - const size_t kBlockSize = 128; - uint16_t length = otMessageGetLength(message); - struct pbuf *buffer = NULL; - otInstance *instance = (otInstance *)context; - - assert(s_thread_netif.state == instance); - - buffer = pbuf_alloc(PBUF_LINK, length, PBUF_POOL); - - VerifyOrExit(buffer != NULL, error = OT_ERROR_NO_BUFS); - - for (uint16_t i = 0; i < length; i += kBlockSize) { - uint8_t block[kBlockSize]; - int count = otMessageRead(message, i, block, sizeof(block)); - - assert(count > 0); - err = pbuf_take_at(buffer, block, count, i); - VerifyOrExit(err == ERR_OK, error = OT_ERROR_FAILED); - } - - err = tcpip_callback(netif_input_task, buffer); - VerifyOrExit(err == ERR_OK, error = OT_ERROR_FAILED); - buffer = NULL; - -exit: - if (error != OT_ERROR_NONE) { - if (buffer != NULL) { - pbuf_free(buffer); - } - - if (error == OT_ERROR_FAILED) { - otLogWarnPlat("%s failed for lwip error %d", __func__, err); - } - - otLogWarnPlat("%s failed: %s", __func__, otThreadErrorToString(error)); - } - - otMessageFree(message); -} - -static esp_err_t transmit_pbuf(struct pbuf *buffer) -{ - otMessage *message = otIp6NewMessage(esp_openthread_get_instance(), NULL); - esp_err_t error = ESP_OK; - otError ot_error = OT_ERROR_NONE; - - if (message == NULL) { - otLogCritPlat("Failed to allocate OpenThread message"); - ExitNow(error = ESP_ERR_NO_MEM); - } - for (struct pbuf *p = buffer; p != NULL; p = p->next) { - ot_error = otMessageAppend(message, p->payload, p->len); - if (ot_error != OT_ERROR_NONE) { - otLogCritPlat("Failed to copy to OpenThread message: %s", otThreadErrorToString(ot_error)); - error = ESP_ERR_NO_MEM; - ExitNow(); - } - - } - ot_error = otIp6Send(esp_openthread_get_instance(), message); - message = NULL; - 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_NO_BUFS) { - otLogInfoPlat("Try to retransmit message %p", buffer); - if (xQueueSendToFront(s_packet_queue, &buffer, 0) != pdTRUE) { - otLogWarnPlat("ThreadNetif: No buf, drop packet"); - error = ESP_ERR_NO_MEM; - buffer = NULL; - } - } else { - error = ESP_FAIL; - } - } - 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"); - } - -exit: - if (buffer != NULL) { - pbuf_free(buffer); - } - if (message != NULL) { - otMessageFree(message); - } - return error; -} - -static esp_err_t process_thread_transmit(otInstance *instance) -{ - struct pbuf *buffer = NULL; - esp_err_t error = OT_ERROR_NONE; - uint64_t event; - - read(s_netif_event_fd, &event, sizeof(event)); - while (xQueueReceive(s_packet_queue, &buffer, 0) == pdTRUE) { - if (buffer) { - error = transmit_pbuf(buffer); - } - if (error != OT_ERROR_NONE) { - break; - } - } - - if (uxQueueMessagesWaiting(s_packet_queue) > 0) { - error = notify_packets_pending(); - } - - return error; -} - -static void netif_up_task(void *ctx) -{ - netif_set_up(&s_thread_netif); -} - -static void netif_down_task(void *ctx) -{ - netif_set_down(&s_thread_netif); -} - -static void process_thread_state(otChangedFlags changed_flags, void *context) -{ - otInstance *instance = (otInstance *)context; - err_t err = ERR_OK; - - if (OT_CHANGED_THREAD_NETIF_STATE & changed_flags) { - if (otLinkIsEnabled(instance)) { - otLogInfoPlat("netif up"); - err = tcpip_callback(netif_up_task, NULL); - } else { - otLogInfoPlat("netif down"); - err = tcpip_callback(netif_down_task, NULL); - } - } - - if (err != ERR_OK) { - otLogCritPlat("Faile to configure netif state"); - } -} - -esp_err_t esp_openthread_netif_init(void) -{ - otInstance *instance = esp_openthread_get_instance(); - otError ot_err; - esp_err_t error = ESP_OK; - - if (instance == NULL || s_packet_queue || s_thread_netif.state || s_netif_event_fd >= 0) { - return ESP_ERR_INVALID_STATE; - } - - memset(&s_thread_netif, 0, sizeof(s_thread_netif)); - if (netif_add(&s_thread_netif, NULL, NULL, NULL, instance, thread_netif_init, tcpip_input) == NULL) { - otLogCritPlat("Failed to add Thread netif"); - ExitNow(error = ESP_FAIL); - } - netif_set_link_up(&s_thread_netif); - s_packet_queue = xQueueCreate(OPENTHREAD_NETIF_QUEUE_SIZE, sizeof(void *)); - 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_netif_event_fd = eventfd(0, 0); - if (s_netif_event_fd < 0) { - otLogCritPlat("Failed to create event fd for Thread netif"); - ExitNow(error = ESP_FAIL); - } - -exit: - if (error != ESP_OK) { - esp_openthread_netif_deinit(); - } - - return error; -} - -void esp_openthread_netif_deinit(void) -{ - otInstance *instance = esp_openthread_get_instance(); - otRemoveStateChangeCallback(instance, process_thread_state, instance); - if (s_packet_queue) { - vQueueDelete(s_packet_queue); - s_packet_queue = NULL; - } - if (s_thread_netif.state) { - netif_remove(&s_thread_netif); - } - if (s_netif_event_fd >= 0) { - close(s_netif_event_fd); - } -} - -void esp_openthread_netif_update(esp_openthread_mainloop_context_t *mainloop) -{ - FD_SET(s_netif_event_fd, &mainloop->read_fds); - if (s_netif_event_fd > mainloop->max_fd) { - mainloop->max_fd = s_netif_event_fd; - } -} - -esp_err_t esp_openthread_netif_process(otInstance *instance, const esp_openthread_mainloop_context_t *context) -{ - if (FD_ISSET(s_netif_event_fd, &context->read_fds)) { - return process_thread_transmit(instance); - } else { - return ESP_OK; - } -} 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 e4c663f08c..5cc7cd7bf5 100644 --- a/examples/openthread/ot_cli/main/ot_esp_cli.c +++ b/examples/openthread/ot_cli/main/ot_esp_cli.c @@ -16,11 +16,12 @@ #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.h" +#include "esp_openthread_netif_glue.h" #include "esp_openthread_types.h" #include "esp_vfs_eventfd.h" #include "driver/uart.h" @@ -83,12 +84,17 @@ 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_openthread_netif_init()); + ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init())); assert(instance != NULL); esp_openthread_lock_acquire(portMAX_DELAY); @@ -126,6 +132,8 @@ 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(); @@ -134,6 +142,7 @@ static void ot_task_worker(void *aContext) 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