From a71fa82177214657a62dda77d148631227f68e9e Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 27 Oct 2022 19:07:07 +0200 Subject: [PATCH] esp_netif/lwip: Fix core-locking config * Fix thread safety issues in non-core locking * Add option to verify thread safety issues in lwip (core-lock assertion) * Make esp_sntp.h thread safe API * Fix sntp examples * Fix openthread libs Closes https://github.com/espressif/esp-idf/issues/9908 Closes https://github.com/espressif/esp-idf/issues/10502 Closes https://github.com/espressif/esp-idf/issues/10466 --- components/esp_netif/CMakeLists.txt | 2 + components/esp_netif/include/esp_netif.h | 49 ++++ components/esp_netif/include/esp_netif_sntp.h | 116 ++++++++ components/esp_netif/lwip/esp_netif_lwip.c | 268 ++++++++++++------ .../esp_netif/lwip/esp_netif_lwip_internal.h | 5 +- components/esp_netif/lwip/esp_netif_sntp.c | 179 ++++++++++++ .../private_include/esp_netif_private.h | 46 +-- .../test_app_esp_netif/main/esp_netif_test.c | 28 +- .../test_app_vfs_l2tap/sdkconfig.defaults | 1 + components/lwip/CMakeLists.txt | 1 + components/lwip/Kconfig | 13 +- components/lwip/apps/sntp/sntp.c | 114 +++++++- components/lwip/include/apps/esp_sntp.h | 125 +++++++- components/lwip/include/apps/sntp/sntp.h | 27 +- components/lwip/lwip | 2 +- .../lwip/port/esp32/freertos/sys_arch.c | 40 ++- .../lwip/port/esp32/include/arch/sys_arch.h | 11 + .../port/esp32/include/lwip_default_hooks.h | 1 + components/lwip/port/esp32/include/lwipopts.h | 28 +- .../lwip/test_afl_host/sdkconfig.defaults | 2 + components/lwip/test_apps/main/lwip_test.c | 101 ++++--- components/openthread/lib | 2 +- docs/doxygen/Doxyfile | 1 + docs/en/api-guides/lwip.rst | 7 +- docs/en/api-reference/network/esp_netif.rst | 83 +++++- docs/en/api-reference/system/system_time.rst | 38 ++- .../release-5.x/5.1/index.rst | 1 + .../release-5.x/5.1/networking.rst | 9 + .../release-5.x/5.1/index.rst | 1 + .../release-5.x/5.1/networking.rst | 9 + .../openthread/ot_br/main/idf_component.yml | 3 +- .../openthread/ot_cli/main/idf_component.yml | 3 +- .../main/http2_request_example_main.c | 10 +- .../protocols/https_request/main/time_sync.c | 25 +- examples/protocols/mqtt/ssl/sdkconfig.ci | 1 + examples/protocols/mqtt/tcp/sdkconfig.ci | 2 + examples/protocols/mqtt/ws/sdkconfig.ci | 1 + examples/protocols/mqtt/wss/sdkconfig.ci | 2 + .../protocols/sntp/main/sntp_example_main.c | 134 +++++---- examples/protocols/sntp/pytest_sntp.py | 2 +- .../ota/advanced_https_ota/sdkconfig.ci | 1 + tools/ci/check_copyright_ignore.txt | 2 - tools/unit-test-app/configs/mqtt | 2 + 43 files changed, 1189 insertions(+), 309 deletions(-) create mode 100644 components/esp_netif/include/esp_netif_sntp.h create mode 100644 components/esp_netif/lwip/esp_netif_sntp.c create mode 100644 docs/en/migration-guides/release-5.x/5.1/networking.rst create mode 100644 docs/zh_CN/migration-guides/release-5.x/5.1/networking.rst diff --git a/components/esp_netif/CMakeLists.txt b/components/esp_netif/CMakeLists.txt index 5050df9346f..b0b678db5cb 100644 --- a/components/esp_netif/CMakeLists.txt +++ b/components/esp_netif/CMakeLists.txt @@ -8,6 +8,7 @@ endif() set(srcs_lwip "lwip/esp_netif_lwip.c" + "lwip/esp_netif_sntp.c" "lwip/esp_netif_lwip_defaults.c" "lwip/netif/wlanif.c" "lwip/netif/ethernetif.c" @@ -55,3 +56,4 @@ endif() target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") +target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_NETIF_COMPONENT_BUILD) diff --git a/components/esp_netif/include/esp_netif.h b/components/esp_netif/include/esp_netif.h index 3831655a4d8..aeb5ffdd6ab 100644 --- a/components/esp_netif/include/esp_netif.h +++ b/components/esp_netif/include/esp_netif.h @@ -306,6 +306,34 @@ esp_err_t esp_netif_bridge_fdb_add(esp_netif_t *esp_netif_br, uint8_t *addr, uin esp_err_t esp_netif_bridge_fdb_remove(esp_netif_t *esp_netif_br, uint8_t *addr); #endif // CONFIG_ESP_NETIF_BRIDGE_EN +/** + * @brief Cause the TCP/IP stack to join a IPv6 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 IPv6 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); + /** * @} */ @@ -940,6 +968,27 @@ void esp_netif_netstack_buf_ref(void *netstack_buf); */ void esp_netif_netstack_buf_free(void *netstack_buf); +/** + * @} + */ + +/** @addtogroup ESP_NETIF_TCPIP_EXEC + * @{ + */ + +/** + * @brief TCPIP thread safe callback used with esp_netif_tcpip_exec() + */ +typedef esp_err_t (*esp_netif_callback_fn)(void *ctx); + +/** + * @brief Utility to execute the supplied callback in TCP/IP context + * @param fn Pointer to the callback + * @param ctx Parameter to the callback + * @return The error code (esp_err_t) returned by the callback + */ +esp_err_t esp_netif_tcpip_exec(esp_netif_callback_fn fn, void *ctx); + /** * @} */ diff --git a/components/esp_netif/include/esp_netif_sntp.h b/components/esp_netif/include/esp_netif_sntp.h new file mode 100644 index 00000000000..96f9f58df59 --- /dev/null +++ b/components/esp_netif/include/esp_netif_sntp.h @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "freertos/FreeRTOS.h" +#include "esp_err.h" +#include "esp_netif_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup ESP_NETIF_SNTP_API ESP-NETIF SNTP API + * @brief SNTP API for underlying TCP/IP stack + * + */ + +/** @addtogroup ESP_NETIF_SNTP_API + * @{ + */ + + +/** + * @brief Time sync notification function + */ +typedef void (*esp_sntp_time_cb_t)(struct timeval *tv); + +/** + * @brief Utility macro for providing multiple servers in parentheses + */ +#define ESP_SNTP_SERVER_LIST(...) { __VA_ARGS__ } + +/** + * @brief Default configuration to init SNTP with multiple servers + * @param servers_in_list Number of servers in the list + * @param list_of_servers List of servers (use ESP_SNTP_SERVER_LIST(...)) + * + */ +#define ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(servers_in_list, list_of_servers) { \ + .smooth_sync = false, \ + .server_from_dhcp = false, \ + .wait_for_sync = true, \ + .start = true, \ + .sync_cb = NULL, \ + .renew_servers_after_new_IP = false, \ + .ip_event_to_renew = 0, \ + .index_of_first_server = 0, \ + .num_of_servers = (servers_in_list), \ + .servers = list_of_servers, \ +} + +/** + * @brief Default configuration with a single server + */ +#define ESP_NETIF_SNTP_DEFAULT_CONFIG(server) \ + ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(1, {server}) + +/** + * @brief SNTP configuration struct + */ +typedef struct esp_sntp_config { + bool smooth_sync; ///< set to true if smooth sync required + bool server_from_dhcp; ///< set to true to request NTP server config from DHCP + bool wait_for_sync; ///< if true, we create a semaphore to signal time sync event + bool start; ///< set to true to automatically start the SNTP service + esp_sntp_time_cb_t sync_cb; ///< optionally sets callback function on time sync event + bool renew_servers_after_new_IP; ///< this is used to refresh server list if NTP provided by DHCP (which cleans other pre-configured servers) + ip_event_t ip_event_to_renew; ///< set the IP event id on which we refresh server list (if renew_servers_after_new_IP=true) + size_t index_of_first_server; ///< refresh server list after this server (if renew_servers_after_new_IP=true) + size_t num_of_servers; ///< number of preconfigured NTP servers + const char* servers[CONFIG_LWIP_SNTP_MAX_SERVERS]; ///< list of servers +} esp_sntp_config_t; + +/** + * @brief Initialize SNTP with supplied config struct + * @param config Config struct + * @return ESP_OK on success + */ +esp_err_t esp_netif_sntp_init(const esp_sntp_config_t * config); + +/** + * @brief Start SNTP service + * if it wasn't started during init (config.start = false) + * or restart it if already started + * @return ESP_OK on success + */ +esp_err_t esp_netif_sntp_start(void); + +/** + * @brief Deinitialize esp_netif SNTP module + */ +void esp_netif_sntp_deinit(void); + +/** + * @brief Wait for time sync event + * @param tout Specified timeout in RTOS ticks + * @return ESP_TIMEOUT if sync event didn't came withing the timeout + * ESP_ERR_NOT_FINISHED if the sync event came, but we're in smooth update mode and still in progress (SNTP_SYNC_STATUS_IN_PROGRESS) + * ESP_OK if time sync'ed + */ +esp_err_t esp_netif_sntp_sync_wait(TickType_t tout); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_netif/lwip/esp_netif_lwip.c b/components/esp_netif/lwip/esp_netif_lwip.c index dbc78b34ffb..3cf86f1980f 100644 --- a/components/esp_netif/lwip/esp_netif_lwip.c +++ b/components/esp_netif/lwip/esp_netif_lwip.c @@ -97,12 +97,8 @@ typedef enum esp_netif_action { // // Internal variables for this module // -extern sys_thread_t g_lwip_task; - static const char *TAG = "esp_netif_lwip"; -static bool tcpip_initialized = false; - #if LWIP_ESP_NETIF_DATA static u8_t lwip_netif_client_id = 0xff; #endif @@ -131,17 +127,28 @@ static void netif_callback_fn(struct netif* netif, netif_nsc_reason_t reason, co #endif /* #if LWIP_IPV6 */ } -static void set_lwip_netif_callback(void) +#if LWIP_ESP_NETIF_DATA +static esp_err_t alloc_client_data_id(esp_netif_api_msg_t *msg) { - if (netif_callback.callback_fn == NULL ) { - netif_add_ext_callback(&netif_callback, netif_callback_fn); - } + uint8_t *client_data_id = msg->data; + *client_data_id = netif_alloc_client_data_id(); + return ESP_OK; +} +#endif // LWIP_ESP_NETIF_DATA + +static esp_err_t set_lwip_netif_callback(struct esp_netif_api_msg_s *msg) +{ + (void)msg; + netif_add_ext_callback(&netif_callback, netif_callback_fn); + return ESP_OK; } -static void remove_lwip_netif_callback(void) +static esp_err_t remove_lwip_netif_callback(struct esp_netif_api_msg_s *msg) { + (void)msg; netif_remove_ext_callback(&netif_callback); memset(&netif_callback, 0, sizeof(netif_callback)); + return ESP_OK; } static void dns_clear_servers(bool keep_fallback) @@ -181,6 +188,7 @@ static void netif_unset_garp_flag(struct netif *netif) #if !LWIP_TCPIP_CORE_LOCKING static sys_sem_t api_sync_sem = NULL; static sys_sem_t api_lock_sem = NULL; +#endif /** * @brief Api callback from tcpip thread used to call esp-netif @@ -197,33 +205,59 @@ static void esp_netif_api_cb(void *api_msg) msg->ret = msg->api_fn(msg); ESP_LOGD(TAG, "call api in lwip: ret=0x%x, give sem", msg->ret); +#if !LWIP_TCPIP_CORE_LOCKING sys_sem_signal(&api_sync_sem); - -} #endif +} + /** * @brief Initiates a tcpip remote call if called from another task * or calls the function directly if executed from lwip task */ -static inline esp_err_t esp_netif_lwip_ipc_call(esp_netif_api_fn fn, esp_netif_t *netif, void *data) +static inline esp_err_t esp_netif_lwip_ipc_call_msg(esp_netif_api_msg_t *msg) +{ + if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { + ESP_LOGD(TAG, "check: remote, if=%p fn=%p\n", msg->esp_netif, msg->api_fn); +#if LWIP_TCPIP_CORE_LOCKING + tcpip_send_msg_wait_sem((tcpip_callback_fn)esp_netif_api_cb, msg, NULL); +#else + sys_arch_sem_wait(&api_lock_sem, 0); + tcpip_send_msg_wait_sem((tcpip_callback_fn)esp_netif_api_cb, msg, &api_sync_sem); + sys_sem_signal(&api_lock_sem); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + return msg->ret; + } + ESP_LOGD(TAG, "check: local, if=%p fn=%p\n", msg->esp_netif, msg->api_fn); + return msg->api_fn(msg); +} + +static inline esp_err_t esp_netif_lwip_ipc_call(esp_netif_api_fn fn, esp_netif_t* netif, void *data) { esp_netif_api_msg_t msg = { .esp_netif = netif, .data = data, .api_fn = fn }; -#if !LWIP_TCPIP_CORE_LOCKING - if (tcpip_initialized && g_lwip_task != xTaskGetCurrentTaskHandle()) { - ESP_LOGD(TAG, "check: remote, if=%p fn=%p\n", netif, fn); - sys_arch_sem_wait(&api_lock_sem, 0); - tcpip_send_msg_wait_sem((tcpip_callback_fn)esp_netif_api_cb, &msg, &api_sync_sem); - sys_sem_signal(&api_lock_sem); - return msg.ret; - } -#endif /* !LWIP_TCPIP_CORE_LOCKING */ - ESP_LOGD(TAG, "check: local, if=%p fn=%p\n", netif, fn); - return fn(&msg); + return esp_netif_lwip_ipc_call_msg(&msg); +} + +static inline esp_err_t esp_netif_lwip_ipc_call_fn(esp_netif_api_fn fn, esp_netif_callback_fn user_fn, void *ctx) +{ + esp_netif_api_msg_t msg = { + .user_fn = user_fn, + .data = ctx, + .api_fn = fn + }; + return esp_netif_lwip_ipc_call_msg(&msg); +} + +static inline esp_err_t esp_netif_lwip_ipc_no_args(esp_netif_api_fn fn) +{ + esp_netif_api_msg_t msg = { + .api_fn = fn + }; + return esp_netif_lwip_ipc_call_msg(&msg); } /** @@ -451,10 +485,15 @@ void* esp_netif_get_netif_impl(esp_netif_t *esp_netif) return NULL; } +static void tcpip_init_done(void *arg) +{ + sys_sem_t *init_sem = arg; + sys_sem_signal(init_sem); +} + esp_err_t esp_netif_init(void) { - if (tcpip_initialized == false) { - tcpip_initialized = true; + if (!sys_thread_tcpip(LWIP_CORE_IS_TCPIP_INITIALIZED)) { #if CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT uint8_t rand_buf[16]; /* @@ -467,13 +506,21 @@ esp_err_t esp_netif_init(void) esp_fill_random(rand_buf, sizeof(rand_buf)); lwip_init_tcp_isn(esp_log_timestamp(), rand_buf); #endif - tcpip_init(NULL, NULL); - ESP_LOGD(TAG, "LwIP stack has been initialized"); -#if LWIP_ESP_NETIF_DATA - if (lwip_netif_client_id == 0xFF) { - lwip_netif_client_id = netif_alloc_client_data_id(); + sys_sem_t init_sem; + if (sys_sem_new(&init_sem, 0) != ERR_OK) { + ESP_LOGE(TAG, "esp netif cannot create tcpip_init semaphore"); + return ESP_FAIL; } +#if LWIP_TCPIP_CORE_LOCKING + /* TCPIP thread is not initialized yet, + * pretend that the calling thread is holder + * to correctly set up the TCPIP task */ + sys_thread_tcpip(LWIP_CORE_LOCK_MARK_HOLDER); #endif + tcpip_init(tcpip_init_done, &init_sem); + sys_sem_wait(&init_sem); + sys_sem_free(&init_sem); + ESP_LOGD(TAG, "LwIP stack has been initialized"); } #if !LWIP_TCPIP_CORE_LOCKING @@ -492,18 +539,22 @@ esp_err_t esp_netif_init(void) } #endif +#if LWIP_ESP_NETIF_DATA + if (lwip_netif_client_id == 0xFF) { + esp_netif_lwip_ipc_call(alloc_client_data_id, NULL, &lwip_netif_client_id); + } +#endif ESP_LOGD(TAG, "esp-netif has been successfully initialized"); return ESP_OK; } esp_err_t esp_netif_deinit(void) { - if (tcpip_initialized == true) { + if (sys_thread_tcpip(LWIP_CORE_IS_TCPIP_INITIALIZED)) { /* deinit of LwIP not supported: * do not deinit semaphores and states, * so init could be called multiple times * - tcpip_initialized = false; sys_sem_free(&api_sync_sem); sys_sem_free(&api_lock_sem); */ @@ -605,6 +656,16 @@ static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_ return ESP_OK; } +static esp_err_t tcpip_exec_api(esp_netif_api_msg_t *msg) +{ + return msg->user_fn(msg->data); +} + +esp_err_t esp_netif_tcpip_exec(esp_netif_callback_fn fn, void*ctx) +{ + return esp_netif_lwip_ipc_call_fn(tcpip_exec_api, fn, ctx); +} + esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config) { // mandatory configuration must be provided when creating esp_netif object @@ -650,7 +711,7 @@ esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config) // Optionally allocate netif client data for esp-netif ptr // to allow for running esp_netif_new() before esp_netif_init() if (lwip_netif_client_id == 0xFF) { - lwip_netif_client_id = netif_alloc_client_data_id(); + esp_netif_lwip_ipc_call(alloc_client_data_id, NULL, &lwip_netif_client_id); } #endif @@ -689,7 +750,9 @@ esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config) } lwip_set_esp_netif(lwip_netif, esp_netif); - set_lwip_netif_callback(); + if (netif_callback.callback_fn == NULL ) { + esp_netif_lwip_ipc_no_args(set_lwip_netif_callback); + } return esp_netif; } @@ -771,18 +834,24 @@ static void esp_netif_destroy_related(esp_netif_t *esp_netif) } } +static esp_err_t esp_netif_lwip_remove_api(esp_netif_api_msg_t *msg) +{ + esp_netif_lwip_remove(msg->esp_netif); + return ESP_OK; +} + void esp_netif_destroy(esp_netif_t *esp_netif) { if (esp_netif) { esp_netif_remove_from_list(esp_netif); if (esp_netif_get_nr_of_ifs() == 0) { - remove_lwip_netif_callback(); + esp_netif_lwip_ipc_no_args(remove_lwip_netif_callback); } free(esp_netif->ip_info); free(esp_netif->ip_info_old); free(esp_netif->if_key); free(esp_netif->if_desc); - esp_netif_lwip_remove(esp_netif); + esp_netif_lwip_ipc_call(esp_netif_lwip_remove_api, esp_netif, NULL); esp_netif_destroy_related(esp_netif); free(esp_netif->lwip_netif); free(esp_netif->hostname); @@ -830,6 +899,15 @@ static esp_err_t esp_netif_reset_ip_info(esp_netif_t *esp_netif) return ESP_OK; } +esp_err_t esp_netif_set_mac_api(esp_netif_api_msg_t *msg) +{ + uint8_t *mac = msg->data; + esp_netif_t* esp_netif = msg->esp_netif; + memcpy(esp_netif->mac, mac, NETIF_MAX_HWADDR_LEN); + memcpy(esp_netif->lwip_netif->hwaddr, mac, NETIF_MAX_HWADDR_LEN); + return ESP_OK; +} + esp_err_t esp_netif_set_mac(esp_netif_t *esp_netif, uint8_t mac[]) { if (esp_netif == NULL || esp_netif->lwip_netif == NULL) { @@ -838,9 +916,7 @@ esp_err_t esp_netif_set_mac(esp_netif_t *esp_netif, uint8_t mac[]) if (_IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) { return ESP_ERR_NOT_SUPPORTED; } - memcpy(esp_netif->mac, mac, NETIF_MAX_HWADDR_LEN); - memcpy(esp_netif->lwip_netif->hwaddr, mac, NETIF_MAX_HWADDR_LEN); - return ESP_OK; + return esp_netif_lwip_ipc_call(esp_netif_set_mac_api, esp_netif, mac); } esp_err_t esp_netif_get_mac(esp_netif_t *esp_netif, uint8_t mac[]) @@ -1952,70 +2028,75 @@ int32_t esp_netif_get_event_id(esp_netif_t *esp_netif, esp_netif_ip_event_type_t } } +struct dhcp_params { + esp_netif_dhcp_option_mode_t op; + esp_netif_dhcp_option_id_t id; + void *val; + uint32_t len; +}; + #if ESP_DHCPS -esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val, - uint32_t opt_len) +esp_err_t esp_netif_dhcps_option_api(esp_netif_api_msg_t *msg) { - if (esp_netif == NULL || esp_netif->dhcps == NULL) { - return ESP_ERR_ESP_NETIF_IF_NOT_READY; - } - void *opt_info = dhcps_option_info(esp_netif->dhcps, opt_id, opt_len); + esp_netif_t *esp_netif = msg->esp_netif; + struct dhcp_params *opt = msg->data; + void *opt_info = dhcps_option_info(esp_netif->dhcps, opt->id, opt->len); esp_netif_dhcp_status_t dhcps_status = esp_netif->dhcps_status; - if (opt_info == NULL || opt_val == NULL) { + if (opt_info == NULL || opt->val == NULL) { return ESP_ERR_ESP_NETIF_INVALID_PARAMS; } - if (opt_op == ESP_NETIF_OP_GET) { + if (opt->op == ESP_NETIF_OP_GET) { if (dhcps_status == ESP_NETIF_DHCP_STOPPED) { return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED; } - switch (opt_id) { + switch (opt->id) { case IP_ADDRESS_LEASE_TIME: { - *(uint32_t *)opt_val = *(uint32_t *)opt_info; + *(uint32_t *)opt->val = *(uint32_t *)opt_info; break; } case ESP_NETIF_SUBNET_MASK: case REQUESTED_IP_ADDRESS: { - memcpy(opt_val, opt_info, opt_len); + memcpy(opt->val, opt_info, opt->len); break; } case ROUTER_SOLICITATION_ADDRESS: { if ((*(uint8_t *)opt_info) & OFFER_ROUTER) { - *(uint8_t *)opt_val = 1; + *(uint8_t *)opt->val = 1; } else { - *(uint8_t *)opt_val = 0; + *(uint8_t *)opt->val = 0; } break; } case DOMAIN_NAME_SERVER: { if ((*(uint8_t *)opt_info) & OFFER_DNS) { - *(uint8_t *)opt_val = 1; + *(uint8_t *)opt->val = 1; } else { - *(uint8_t *)opt_val = 0; + *(uint8_t *)opt->val = 0; } break; } default: break; } - } else if (opt_op == ESP_NETIF_OP_SET) { + } else if (opt->op == ESP_NETIF_OP_SET) { if (dhcps_status == ESP_NETIF_DHCP_STARTED) { return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED; } - switch (opt_id) { + switch (opt->id) { case IP_ADDRESS_LEASE_TIME: { - if (*(uint32_t *)opt_val != 0) { - *(uint32_t *)opt_info = *(uint32_t *)opt_val; + if (*(uint32_t *)opt->val != 0) { + *(uint32_t *)opt_info = *(uint32_t *)opt->val; } else { *(uint32_t *)opt_info = DHCPS_LEASE_TIME_DEF; } break; } case ESP_NETIF_SUBNET_MASK: { - memcpy(opt_info, opt_val, opt_len); + memcpy(opt_info, opt->val, opt->len); break; } case REQUESTED_IP_ADDRESS: { @@ -2023,7 +2104,7 @@ esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m uint32_t softap_ip = 0; uint32_t start_ip = 0; uint32_t end_ip = 0; - dhcps_lease_t *poll = opt_val; + dhcps_lease_t *poll = opt->val; if (poll->enable) { memset(&info, 0x00, sizeof(esp_netif_ip_info_t)); @@ -2050,11 +2131,11 @@ esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m } } - memcpy(opt_info, opt_val, opt_len); + memcpy(opt_info, opt->val, opt->len); break; } case ROUTER_SOLICITATION_ADDRESS: { - if (*(uint8_t *)opt_val) { + if (*(uint8_t *)opt->val) { *(uint8_t *)opt_info |= OFFER_ROUTER; } else { *(uint8_t *)opt_info &= ((~OFFER_ROUTER) & 0xFF); @@ -2062,7 +2143,7 @@ esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m break; } case DOMAIN_NAME_SERVER: { - if (*(uint8_t *)opt_val) { + if (*(uint8_t *)opt->val) { *(uint8_t *)opt_info |= OFFER_DNS; } else { *(uint8_t *)opt_info &= ((~OFFER_DNS) & 0xFF); @@ -2073,55 +2154,64 @@ esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m default: break; } - dhcps_set_option_info(esp_netif->dhcps, opt_id, opt_info, opt_len); + dhcps_set_option_info(esp_netif->dhcps, opt->id, opt_info, opt->len); } else { return ESP_ERR_ESP_NETIF_INVALID_PARAMS; } return ESP_OK; } -#endif -esp_err_t esp_netif_dhcpc_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val, +esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val, uint32_t opt_len) { - if (esp_netif == NULL || esp_netif->lwip_netif == NULL) { + if (esp_netif == NULL || esp_netif->dhcps == NULL) { return ESP_ERR_ESP_NETIF_IF_NOT_READY; } + struct dhcp_params opts = { .op = opt_op, .id = opt_id, .len = opt_len, .val = opt_val }; + return esp_netif_lwip_ipc_call(esp_netif_dhcps_option_api, esp_netif, &opts); +} +#endif + +esp_err_t esp_netif_dhcpc_option_api(esp_netif_api_msg_t *msg) +{ + esp_netif_t *esp_netif = msg->esp_netif; + struct dhcp_params *opt = msg->data; + struct dhcp *dhcp = netif_dhcp_data(esp_netif->lwip_netif); - if (dhcp == NULL || opt_val == NULL) { + if (dhcp == NULL || opt->val == NULL) { return ESP_ERR_ESP_NETIF_INVALID_PARAMS; } - if (opt_op == ESP_NETIF_OP_GET) { + if (opt->op == ESP_NETIF_OP_GET) { if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STOPPED) { return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED; } - switch (opt_id) { + switch (opt->id) { case ESP_NETIF_IP_REQUEST_RETRY_TIME: - if (opt_len == sizeof(dhcp->tries)) { - *(uint8_t *)opt_val = dhcp->tries; + if (opt->len == sizeof(dhcp->tries)) { + *(uint8_t *)opt->val = dhcp->tries; } break; #if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER case ESP_NETIF_VENDOR_SPECIFIC_INFO: - return dhcp_get_vendor_specific_information(opt_len, opt_val); + return dhcp_get_vendor_specific_information(opt->len, opt->val); #endif default: return ESP_ERR_ESP_NETIF_INVALID_PARAMS; } - } else if (opt_op == ESP_NETIF_OP_SET) { + } else if (opt->op == ESP_NETIF_OP_SET) { if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STARTED) { return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED; } - switch (opt_id) { + switch (opt->id) { case ESP_NETIF_IP_REQUEST_RETRY_TIME: - if (opt_len == sizeof(dhcp->tries)) { - dhcp->tries = *(uint8_t *)opt_val; + if (opt->len == sizeof(dhcp->tries)) { + dhcp->tries = *(uint8_t *)opt->val; } break; #if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER - case ESP_NETIF_VENDOR_CLASS_IDENTIFIER: - return dhcp_set_vendor_class_identifier(opt_len, opt_val); + case ESP_NETIF_VENDOR_CLASS_IDENTIFIER: + return dhcp_set_vendor_class_identifier(opt->len, opt->val); #endif default: return ESP_ERR_ESP_NETIF_INVALID_PARAMS; @@ -2132,6 +2222,16 @@ esp_err_t esp_netif_dhcpc_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_m return ESP_OK; } +esp_err_t esp_netif_dhcpc_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val, + uint32_t opt_len) +{ + if (esp_netif == NULL || esp_netif->lwip_netif == NULL) { + return ESP_ERR_ESP_NETIF_IF_NOT_READY; + } + struct dhcp_params opts = { .op = opt_op, .id = opt_id, .len = opt_len, .val = opt_val }; + return esp_netif_lwip_ipc_call(esp_netif_dhcpc_option_api, esp_netif, &opts); +} + int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif) { if (esp_netif == NULL || esp_netif->lwip_netif == NULL) { @@ -2140,6 +2240,13 @@ int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif) return netif_get_index(esp_netif->lwip_netif); } +esp_err_t esp_netif_get_netif_impl_name_api(esp_netif_api_msg_t *msg) +{ + struct netif* netif = msg->esp_netif->lwip_netif; + netif_index_to_name(netif_get_index(netif), msg->data); + return ESP_OK; +} + esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char* name) { ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif); @@ -2147,8 +2254,7 @@ esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char* name) if (esp_netif == NULL || esp_netif->lwip_netif == NULL) { return ESP_ERR_ESP_NETIF_INVALID_PARAMS; } - netif_index_to_name(netif_get_index(esp_netif->lwip_netif), name); - return ESP_OK; + return esp_netif_lwip_ipc_call(esp_netif_get_netif_impl_name_api, esp_netif, name); } #if MIB2_STATS diff --git a/components/esp_netif/lwip/esp_netif_lwip_internal.h b/components/esp_netif/lwip/esp_netif_lwip_internal.h index 3316bf19f39..30ecdb71eb4 100644 --- a/components/esp_netif/lwip/esp_netif_lwip_internal.h +++ b/components/esp_netif/lwip/esp_netif_lwip_internal.h @@ -19,7 +19,10 @@ typedef struct esp_netif_api_msg_s { int type; /**< The first field MUST be int */ int ret; esp_netif_api_fn api_fn; - esp_netif_t *esp_netif; + union { + esp_netif_t *esp_netif; + esp_netif_callback_fn user_fn; + }; void *data; } esp_netif_api_msg_t; diff --git a/components/esp_netif/lwip/esp_netif_sntp.c b/components/esp_netif/lwip/esp_netif_sntp.c new file mode 100644 index 00000000000..1aadcbef693 --- /dev/null +++ b/components/esp_netif/lwip/esp_netif_sntp.c @@ -0,0 +1,179 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_netif.h" +#include "esp_netif_sntp.h" +#include "esp_sntp.h" + +// Remove compat macro and include lwip API +#undef SNTP_OPMODE_POLL +#include "lwip/apps/sntp.h" + +static const char *TAG = "esp_netif_sntp"; + +typedef struct sntp_storage { + esp_sntp_time_cb_t sync_cb; + SemaphoreHandle_t sync_sem; + ip_event_t ip_event_to_renew; + size_t index_of_first_server; + size_t num_of_servers; + char* servers[]; +} sntp_storage_t; + +static sntp_storage_t *s_storage = NULL; + +static void sync_time_cb(struct timeval *tv) +{ + if (s_storage && s_storage->sync_sem) { + xSemaphoreGive(s_storage->sync_sem); + } + if (s_storage && s_storage->sync_cb) { + s_storage->sync_cb(tv); + } +} + +static esp_err_t sntp_init_api(void *ctx) +{ + esp_err_t ret = ESP_OK; + + esp_sntp_config_t * config = ctx; + ESP_GOTO_ON_FALSE(config->num_of_servers <= SNTP_MAX_SERVERS, ESP_ERR_INVALID_ARG, err, TAG, "Tried to configure more servers than enabled in lwip. Please update CONFIG_SNTP_MAX_SERVERS"); + + sntp_set_time_sync_notification_cb(sync_time_cb); + sntp_setoperatingmode(SNTP_OPMODE_POLL); + + for (int i = 0; i < config->num_of_servers; ++i) { + sntp_setservername(i, config->servers[i]); + } + + if (config->server_from_dhcp) { +#if LWIP_DHCP_GET_NTP_SRV + sntp_servermode_dhcp(1); +#else + ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "Tried to configure SNTP server from DHCP, while disabled. Please enable CONFIG_LWIP_DHCP_GET_NTP_SRV"); +#endif + } + + if (config->smooth_sync) { + sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH); + } + + if (config->start) { + sntp_init(); + } +err: + return ret; +} + +static esp_err_t renew_servers_api(void *ctx) +{ + if (s_storage && s_storage->num_of_servers) { + for (int i = 0; i < s_storage->num_of_servers; ++i) { + sntp_setservername(i + s_storage->index_of_first_server, s_storage->servers[i]); + } + } + return ESP_OK; +} + +void esp_netif_sntp_renew_servers(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + esp_netif_tcpip_exec(renew_servers_api, NULL); +} + +esp_err_t esp_netif_sntp_init(const esp_sntp_config_t * config) +{ + esp_err_t ret = ESP_OK; + s_storage = calloc(1, sizeof(sntp_storage_t) + // allocate space for servers only if we are supposed to refresh the settings + (config->renew_servers_after_new_IP ? config->num_of_servers * sizeof(char*) : 0)); + ESP_GOTO_ON_FALSE(s_storage != NULL, ESP_ERR_NO_MEM, err, TAG, "Failed to allocate SNTP storage"); + if (config->wait_for_sync) { + s_storage->sync_sem = xSemaphoreCreateBinary(); + ESP_GOTO_ON_FALSE(s_storage->sync_sem != NULL, ESP_ERR_NO_MEM, err, TAG, "Failed to SNTP sync semaphore"); + } + if (config->renew_servers_after_new_IP && config->num_of_servers > 0) { + s_storage->num_of_servers = config->num_of_servers; + s_storage->index_of_first_server = config->index_of_first_server; + // store the server names, as we'd have to refresh the config after IP event + for (int i = 0; i < config->num_of_servers; ++i) { + s_storage->servers[i] = strdup(config->servers[i]); + } + + ESP_GOTO_ON_ERROR(esp_event_handler_register(IP_EVENT, config->ip_event_to_renew, esp_netif_sntp_renew_servers, NULL), + err, TAG, "Failed to register IP event"); + s_storage->ip_event_to_renew = config->ip_event_to_renew; + + } + if (config->sync_cb) { + s_storage->sync_cb = config->sync_cb; + } + + ESP_GOTO_ON_ERROR(esp_netif_tcpip_exec(sntp_init_api, (void*)config), err, TAG, "Failed initialize SNTP service"); + + return ret; + +err: + esp_netif_sntp_deinit(); + return ret; +} + +static esp_err_t sntp_stop_api(void *ctx) +{ + sntp_stop(); + return ESP_OK; +} + +void esp_netif_sntp_deinit(void) +{ + if (s_storage) { + sntp_storage_t *storage = s_storage; + s_storage = NULL; + sntp_set_time_sync_notification_cb(NULL); + esp_netif_tcpip_exec(sntp_stop_api, NULL); + if (storage->num_of_servers) { + for (int i = 0; i < storage->num_of_servers; ++i) { + free(storage->servers[i]); + } + esp_event_handler_unregister(IP_EVENT, storage->ip_event_to_renew, esp_netif_sntp_renew_servers); + } + if (storage->sync_sem) { + vSemaphoreDelete(storage->sync_sem); + } + free(storage); + + } +} + +esp_err_t esp_netif_sntp_sync_wait(TickType_t tout) +{ + if (s_storage == NULL || s_storage->sync_sem == NULL) { + return ESP_ERR_INVALID_STATE; + } + if (xQueueSemaphoreTake(s_storage->sync_sem, tout) != pdTRUE) { + return ESP_ERR_TIMEOUT; + } + if (sntp_get_sync_mode() == SNTP_SYNC_MODE_SMOOTH && + sntp_get_sync_status() == SNTP_SYNC_STATUS_IN_PROGRESS) { + return ESP_ERR_NOT_FINISHED; + } + return ESP_OK; +} + +static esp_err_t sntp_start_api(void* ctx) +{ + sntp_stop(); + sntp_init(); + return ESP_OK; +} + +esp_err_t esp_netif_sntp_start(void) +{ + return esp_netif_tcpip_exec(sntp_start_api, NULL); +} diff --git a/components/esp_netif/private_include/esp_netif_private.h b/components/esp_netif/private_include/esp_netif_private.h index f5355614c98..b7fcfa6ef10 100644 --- a/components/esp_netif/private_include/esp_netif_private.h +++ b/components/esp_netif/private_include/esp_netif_private.h @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE 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. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef _ESP_NETIF_PRIVATE_H_ #define _ESP_NETIF_PRIVATE_H_ @@ -145,34 +137,6 @@ 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 * diff --git a/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c b/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c index 0866eff446e..d4a1827ad29 100644 --- a/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c +++ b/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -8,21 +8,26 @@ #include "unity.h" #include "unity_fixture.h" #include "esp_netif.h" +#include "esp_netif_sntp.h" #include "esp_wifi.h" #include "nvs_flash.h" #include "esp_wifi_netif.h" #include "sdkconfig.h" -#include "lwip/sockets.h" #include "test_utils.h" +#include "memory_checks.h" TEST_GROUP(esp_netif); TEST_SETUP(esp_netif) { + test_utils_record_free_mem(); + TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL)); } TEST_TEAR_DOWN(esp_netif) { + test_utils_finish_and_evaluate_leaks(test_utils_get_leak_level(ESP_LEAK_TYPE_WARNING, ESP_COMP_LEAK_ALL), + test_utils_get_leak_level(ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_ALL)); } TEST(esp_netif, init_and_destroy) @@ -37,6 +42,13 @@ TEST(esp_netif, init_and_destroy) esp_netif_destroy(esp_netif); } +TEST(esp_netif, init_and_destroy_sntp) +{ + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("127.0.0.1"); + config.start = false; + esp_netif_sntp_init(&config); + esp_netif_sntp_deinit(); +} TEST(esp_netif, get_from_if_key) { @@ -275,14 +287,22 @@ TEST(esp_netif, get_set_hostname) TEST_GROUP_RUNNER(esp_netif) { + /** + * Keep the tests that don't need to start TCP/IP stack first, when the leak checker + * is more strict with leak level set to 0 + */ RUN_TEST_CASE(esp_netif, init_and_destroy) + RUN_TEST_CASE(esp_netif, init_and_destroy_sntp) RUN_TEST_CASE(esp_netif, get_from_if_key) RUN_TEST_CASE(esp_netif, create_delete_multiple_netifs) + RUN_TEST_CASE(esp_netif, create_custom_wifi_interfaces) + /** + * After follow tests which start lwIP and thus expect some mem-leaks by TCP/IP stack + */ + RUN_TEST_CASE(esp_netif, get_set_hostname) RUN_TEST_CASE(esp_netif, dhcp_client_state_transitions_wifi_sta) RUN_TEST_CASE(esp_netif, dhcp_server_state_transitions_wifi_ap) RUN_TEST_CASE(esp_netif, dhcp_server_state_transitions_mesh) - RUN_TEST_CASE(esp_netif, create_custom_wifi_interfaces) - RUN_TEST_CASE(esp_netif, get_set_hostname) } void app_main(void) diff --git a/components/esp_netif/test_apps/test_app_vfs_l2tap/sdkconfig.defaults b/components/esp_netif/test_apps/test_app_vfs_l2tap/sdkconfig.defaults index 5cec6ae4f06..c439354b15d 100644 --- a/components/esp_netif/test_apps/test_app_vfs_l2tap/sdkconfig.defaults +++ b/components/esp_netif/test_apps/test_app_vfs_l2tap/sdkconfig.defaults @@ -2,3 +2,4 @@ CONFIG_UNITY_ENABLE_FIXTURE=y CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y CONFIG_ESP_NETIF_L2_TAP=y +CONFIG_LWIP_CHECK_THREAD_SAFETY=y diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index edcf16878f6..170e59478cb 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -153,6 +153,7 @@ idf_component_register(SRCS "${srcs}" # lots of LWIP source files evaluate macros that check address of stack variables target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address) +target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_LWIP_COMPONENT_BUILD) set_source_files_properties( lwip/src/netif/ppp/pppos.c diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 01f3d7517e4..9edc5717610 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -19,12 +19,21 @@ menu "LWIP" bool "Enable tcpip core locking" default n help - If Enable tcpip core locking,Creates a global mutex that is held + If Enable tcpip core locking,Creates a global mutex that is held during TCPIP thread operations.Can be locked by client code to perform lwIP operations without changing into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and UNLOCK_TCPIP_CORE(). - If disable tcpip core locking,TCP IP will perform tasks through context switching. + If disable tcpip core locking,TCP IP will perform tasks through context switching + + config LWIP_CHECK_THREAD_SAFETY + bool "Checks that lwip API runs in expected context" + default n + help + Enable to check that the project does not violate lwip thread safety. + If enabled, all lwip functions that require thread awareness run an assertion + to verify that the TCP/IP core functionality is either locked or accessed + from the correct thread. config LWIP_DNS_SUPPORT_MDNS_QUERIES bool "Enable mDNS queries in resolving host name" diff --git a/components/lwip/apps/sntp/sntp.c b/components/lwip/apps/sntp/sntp.c index ef3bb7c82ca..f959e9ba547 100644 --- a/components/lwip/apps/sntp/sntp.c +++ b/components/lwip/apps/sntp/sntp.c @@ -9,11 +9,18 @@ #include #include #include "esp_log.h" -#include "sntp.h" +#include "esp_sntp.h" + +// Remove compat macro and include lwip API +#undef SNTP_OPMODE_POLL #include "lwip/apps/sntp.h" +#include "lwip/tcpip.h" static const char *TAG = "sntp"; +ESP_STATIC_ASSERT(SNTP_OPMODE_POLL == ESP_SNTP_OPMODE_POLL, "SNTP mode in lwip doesn't match the IDF enum. Please make sure lwIP version is correct"); +ESP_STATIC_ASSERT(SNTP_OPMODE_LISTENONLY == ESP_SNTP_OPMODE_LISTENONLY, "SNTP mode in lwip doesn't match the IDF enum. Please make sure lwIP version is correct"); + static volatile sntp_sync_mode_t sntp_sync_mode = SNTP_SYNC_MODE_IMMED; static volatile sntp_sync_status_t sntp_sync_status = SNTP_SYNC_STATUS_RESET; static sntp_sync_time_cb_t time_sync_notification_cb = NULL; @@ -100,11 +107,17 @@ uint32_t sntp_get_sync_interval(void) return s_sync_interval; } +static void sntp_do_restart(void *ctx) +{ + (void)ctx; + sntp_stop(); + sntp_init(); +} + bool sntp_restart(void) { if (sntp_enabled()) { - sntp_stop(); - sntp_init(); + tcpip_callback(sntp_do_restart, NULL); return true; } return false; @@ -138,3 +151,98 @@ void sntp_get_system_time(uint32_t *sec, uint32_t *us) *(us) = tv.tv_usec; sntp_set_sync_status(SNTP_SYNC_STATUS_RESET); } + +static void do_setoperatingmode(void *ctx) +{ + esp_sntp_operatingmode_t operating_mode = (esp_sntp_operatingmode_t)ctx; + sntp_setoperatingmode(operating_mode); +} + +void esp_sntp_setoperatingmode(esp_sntp_operatingmode_t operating_mode) +{ + tcpip_callback(do_setoperatingmode, (void*)operating_mode); +} + +static void do_init(void *ctx) +{ + sntp_init(); +} + +void esp_sntp_init(void) +{ + tcpip_callback(do_init, NULL); +} + +static void do_stop(void *ctx) +{ + sntp_stop(); +} + +void esp_sntp_stop(void) +{ + tcpip_callback(do_stop, NULL); +} + +struct do_setserver { + u8_t idx; + const ip_addr_t *addr; +}; + +static void do_setserver(void *ctx) +{ + struct do_setserver *params = ctx; + sntp_setserver(params->idx, params->addr); +} + +void esp_sntp_setserver(u8_t idx, const ip_addr_t *addr) +{ + struct do_setserver params = { + .idx = idx, + .addr = addr + }; + tcpip_callback(do_setserver, ¶ms); +} + +struct do_setservername { + u8_t idx; + const char *server; +}; + +static void do_setservername(void *ctx) +{ + struct do_setservername *params = ctx; + sntp_setservername(params->idx, params->server); +} + +void esp_sntp_setservername(u8_t idx, const char *server) +{ + struct do_setservername params = { + .idx = idx, + .server = server + }; + tcpip_callback(do_setservername, ¶ms); +} + +const char *esp_sntp_getservername(u8_t idx) +{ + return sntp_getservername(idx); +} + +const ip_addr_t* esp_sntp_getserver(u8_t idx) +{ + return sntp_getserver(idx); +} + +#if LWIP_DHCP_GET_NTP_SRV +static void do_servermode_dhcp(void* ctx) +{ + u8_t servermode = (bool)ctx ? 1 : 0; + sntp_servermode_dhcp(servermode); +} + +void esp_sntp_servermode_dhcp(bool enable) +{ + tcpip_callback(do_servermode_dhcp, (void*)enable); +} + +#endif /* LWIP_DHCP_GET_NTP_SRV */ diff --git a/components/lwip/include/apps/esp_sntp.h b/components/lwip/include/apps/esp_sntp.h index 1a4f9db37fd..4086bb7825c 100644 --- a/components/lwip/include/apps/esp_sntp.h +++ b/components/lwip/include/apps/esp_sntp.h @@ -8,7 +8,7 @@ #define __ESP_SNTP_H__ #include "lwip/err.h" -#include "lwip/apps/sntp.h" +#include "lwip/ip.h" #ifdef __cplusplus @@ -38,6 +38,23 @@ extern "C" { * to wait for the next sync cycle. */ +/// Aliases for esp_sntp prefixed API (inherently thread safe) +#define esp_sntp_sync_time sntp_sync_time +#define esp_sntp_set_sync_mode sntp_set_sync_mode +#define esp_sntp_get_sync_mode sntp_get_sync_mode +#define esp_sntp_get_sync_status sntp_get_sync_status +#define esp_sntp_set_sync_status sntp_set_sync_status +#define esp_sntp_set_time_sync_notification_cb sntp_set_time_sync_notification_cb +#define esp_sntp_set_sync_interval sntp_set_sync_interval +#define esp_sntp_get_sync_interval sntp_get_sync_interval +#define esp_sntp_restart sntp_restart + +#ifndef SNTP_OPMODE_POLL +#define SNTP_OPMODE_POLL ESP_SNTP_OPMODE_POLL +#else +#warning "Defined!" +#endif /* SNTP_OPMODE_POLL */ + /// SNTP time update mode typedef enum { SNTP_SYNC_MODE_IMMED, /*!< Update system time immediately when receiving a response from the SNTP server. */ @@ -51,6 +68,12 @@ typedef enum { SNTP_SYNC_STATUS_IN_PROGRESS, // Smooth time sync in progress. } sntp_sync_status_t; +/// SNTP operating modes per lwip SNTP module +typedef enum { + ESP_SNTP_OPMODE_POLL, + ESP_SNTP_OPMODE_LISTENONLY, +} esp_sntp_operatingmode_t; + /** * @brief SNTP callback function for notifying about time sync event * @@ -143,6 +166,106 @@ uint32_t sntp_get_sync_interval(void); */ bool sntp_restart(void); +/** + * @brief Sets SNTP operating mode. The mode has to be set before init. + * + * @param operating_mode Desired operating mode + */ +void esp_sntp_setoperatingmode(esp_sntp_operatingmode_t operating_mode); + +/** + * @brief Init and start SNTP service + */ +void esp_sntp_init(void); + +/** + * @brief Stops SNTP service + */ +void esp_sntp_stop(void); + +/** + * @brief Sets SNTP server address + * + * @param idx Index of the server + * @param addr IP address of the server + */ +void esp_sntp_setserver(u8_t idx, const ip_addr_t *addr); + +/** + * @brief Sets SNTP hostname + * @param idx Index of the server + * @param server Name of the server + */ +void esp_sntp_setservername(u8_t idx, const char *server); + +/** + * @brief Gets SNTP server name + * @param idx Index of the server + * @return Name of the server + */ +const char *esp_sntp_getservername(u8_t idx); + +/** + * @brief Get SNTP server IP + * @param idx Index of the server + * @return IP address of the server + */ +const ip_addr_t* esp_sntp_getserver(u8_t idx); + +#if LWIP_DHCP_GET_NTP_SRV +/** + * @brief Enable acquiring SNTP server from DHCP + * @param enable True for enabling SNTP from DHCP + */ +void esp_sntp_servermode_dhcp(bool enable); +#endif /* LWIP_DHCP_GET_NTP_SRV */ + +#if !defined(ESP_LWIP_COMPONENT_BUILD) && !defined(ESP_NETIF_COMPONENT_BUILD) +/** + * @brief if not build within lwip, provide translating inlines, + * that will warn about thread safety + */ +static inline __attribute__((deprecated("use esp_sntp_setoperatingmode() instead"))) +void sntp_setoperatingmode(u8_t operating_mode) +{ + esp_sntp_setoperatingmode(operating_mode); +} + +static inline __attribute__((deprecated("use esp_sntp_servermode_dhcp() instead"))) +void sntp_servermode_dhcp(int set_servers_from_dhcp) +{ +#if LWIP_DHCP_GET_NTP_SRV + esp_sntp_servermode_dhcp(set_servers_from_dhcp); +#endif +} + +static inline __attribute__((deprecated("use esp_sntp_setservername() instead"))) +void sntp_setservername(u8_t idx, const char *server) +{ + esp_sntp_setservername(idx, server); +} + +static inline __attribute__((deprecated("use esp_sntp_init() instead"))) +void sntp_init(void) +{ + esp_sntp_init(); +} + +static inline __attribute__((deprecated("use esp_sntp_getservername() instead"))) +const char *sntp_getservername(u8_t idx) +{ + return esp_sntp_getservername(idx); +} + +static inline __attribute__((deprecated("use esp_sntp_getserver() instead"))) +const ip_addr_t* sntp_getserver(u8_t idx) +{ + return esp_sntp_getserver(idx); +} + +#endif /* ESP_LWIP_COMPONENT_BUILD */ + + #ifdef __cplusplus } #endif diff --git a/components/lwip/include/apps/sntp/sntp.h b/components/lwip/include/apps/sntp/sntp.h index 616fd554609..50ba6b3843f 100644 --- a/components/lwip/include/apps/sntp/sntp.h +++ b/components/lwip/include/apps/sntp/sntp.h @@ -1,27 +1,16 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE 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. +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ -#ifndef __SNTP_H__ -#define __SNTP_H__ +#pragma once +#warning "sntp.h in IDF's lwip port folder is deprecated. Please include esp_sntp.h" /* * This header is provided only for compatibility reasons for existing * applications which directly include "sntp.h" from the IDF default paths. - * and will be removed in IDF v5.0. + * and will be removed in IDF v6.0. * It is recommended to use "esp_sntp.h" from IDF's lwip port folder */ - #include "esp_sntp.h" - -#endif // __SNTP_H__ diff --git a/components/lwip/lwip b/components/lwip/lwip index 705dd71d467..10197b212a9 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit 705dd71d46779bf29653f1f1d7b1af5a09fb2aa7 +Subproject commit 10197b212a95c49c733fb18ffed56cafb0d196d4 diff --git a/components/lwip/port/esp32/freertos/sys_arch.c b/components/lwip/port/esp32/freertos/sys_arch.c index 28228ff5059..fa9c1ef0fa6 100644 --- a/components/lwip/port/esp32/freertos/sys_arch.c +++ b/components/lwip/port/esp32/freertos/sys_arch.c @@ -53,7 +53,6 @@ static sys_mutex_t g_lwip_protect_mutex = NULL; static pthread_key_t sys_thread_sem_key; static void sys_thread_sem_free(void* data); -sys_thread_t g_lwip_task; #if !LWIP_COMPAT_MUTEX @@ -428,10 +427,8 @@ sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize ret = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &rtos_task, CONFIG_LWIP_TCPIP_TASK_AFFINITY); - g_lwip_task = rtos_task; - - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_task_hdlxxx : %x, prio:%d,stack:%d\n", - (u32_t)g_lwip_task,TCPIP_THREAD_PRIO,TCPIP_THREAD_STACKSIZE)); + LWIP_DEBUGF(TCPIP_DEBUG, ("new lwip task : %x, prio:%d,stack:%d\n", + (u32_t)rtos_task, prio, stacksize)); if (ret != pdTRUE) { return NULL; @@ -577,3 +574,36 @@ sys_delay_ms(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } + +bool +sys_thread_tcpip(sys_thread_core_lock_t type) +{ + static sys_thread_t lwip_task = NULL; +#if LWIP_TCPIP_CORE_LOCKING + static sys_thread_t core_lock_holder = NULL; +#endif + switch (type) { + default: + return false; + case LWIP_CORE_IS_TCPIP_INITIALIZED: + return lwip_task != NULL; + case LWIP_CORE_MARK_TCPIP_TASK: + LWIP_ASSERT("LWIP_CORE_MARK_TCPIP_TASK: lwip_task == NULL", (lwip_task == NULL)); + lwip_task = (sys_thread_t) xTaskGetCurrentTaskHandle(); + return true; +#if LWIP_TCPIP_CORE_LOCKING + case LWIP_CORE_LOCK_QUERY_HOLDER: + return lwip_task ? core_lock_holder == (sys_thread_t) xTaskGetCurrentTaskHandle() : true; + case LWIP_CORE_LOCK_MARK_HOLDER: + core_lock_holder = (sys_thread_t) xTaskGetCurrentTaskHandle(); + return true; + case LWIP_CORE_LOCK_UNMARK_HOLDER: + core_lock_holder = NULL; + return true; +#else + case LWIP_CORE_LOCK_QUERY_HOLDER: + return lwip_task == NULL || lwip_task == (sys_thread_t) xTaskGetCurrentTaskHandle(); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + } + return true; +} diff --git a/components/lwip/port/esp32/include/arch/sys_arch.h b/components/lwip/port/esp32/include/arch/sys_arch.h index b4fb53a834d..1cec1e01b71 100644 --- a/components/lwip/port/esp32/include/arch/sys_arch.h +++ b/components/lwip/port/esp32/include/arch/sys_arch.h @@ -100,6 +100,17 @@ sys_sem_t* sys_thread_sem_init(void); void sys_thread_sem_deinit(void); sys_sem_t* sys_thread_sem_get(void); +typedef enum { + LWIP_CORE_LOCK_QUERY_HOLDER, + LWIP_CORE_LOCK_MARK_HOLDER, + LWIP_CORE_LOCK_UNMARK_HOLDER, + LWIP_CORE_MARK_TCPIP_TASK, + LWIP_CORE_IS_TCPIP_INITIALIZED, +} sys_thread_core_lock_t; + +bool +sys_thread_tcpip(sys_thread_core_lock_t type); + #ifdef __cplusplus } #endif diff --git a/components/lwip/port/esp32/include/lwip_default_hooks.h b/components/lwip/port/esp32/include/lwip_default_hooks.h index 359263a207c..28220ba75cc 100644 --- a/components/lwip/port/esp32/include/lwip_default_hooks.h +++ b/components/lwip/port/esp32/include/lwip_default_hooks.h @@ -12,6 +12,7 @@ #include "lwip/pbuf.h" #include "netif/dhcp_state.h" + #ifdef ESP_IDF_LWIP_HOOK_FILENAME #include ESP_IDF_LWIP_HOOK_FILENAME #endif diff --git a/components/lwip/port/esp32/include/lwipopts.h b/components/lwip/port/esp32/include/lwipopts.h index 97dfa2b65be..b1e4d0ed068 100644 --- a/components/lwip/port/esp32/include/lwipopts.h +++ b/components/lwip/port/esp32/include/lwipopts.h @@ -26,6 +26,7 @@ #include "sdkconfig.h" #include "sntp/sntp_get_set_time.h" #include "sockets_ext.h" +#include "arch/sys_arch.h" #ifdef __cplusplus extern "C" { @@ -46,9 +47,20 @@ extern "C" { */ #ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING #define LWIP_TCPIP_CORE_LOCKING 1 +#define LOCK_TCPIP_CORE() do { sys_mutex_lock(&lock_tcpip_core); sys_thread_tcpip(LWIP_CORE_LOCK_MARK_HOLDER); } while(0) +#define UNLOCK_TCPIP_CORE() do { sys_thread_tcpip(LWIP_CORE_LOCK_UNMARK_HOLDER); sys_mutex_unlock(&lock_tcpip_core); } while(0) +#ifdef CONFIG_LWIP_CHECK_THREAD_SAFETY +#define LWIP_ASSERT_CORE_LOCKED() do { LWIP_ASSERT("Required to lock TCPIP core functionality!", sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)); } while(0) +#endif /* CONFIG_LWIP_CHECK_THREAD_SAFETY */ + #else #define LWIP_TCPIP_CORE_LOCKING 0 -#endif +#ifdef CONFIG_LWIP_CHECK_THREAD_SAFETY +#define LWIP_ASSERT_CORE_LOCKED() do { LWIP_ASSERT("Required to run in TCPIP context!", sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)); } while(0) +#endif /* CONFIG_LWIP_CHECK_THREAD_SAFETY */ +#endif /* CONFIG_LWIP_TCPIP_CORE_LOCKING */ + +#define LWIP_MARK_TCPIP_THREAD() sys_thread_tcpip(LWIP_CORE_MARK_TCPIP_TASK) /** * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain @@ -845,11 +857,7 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min) * The latter 2 can be invoked up by calling netconn_thread_init()/netconn_thread_cleanup(). * Ports may call these for threads created with sys_thread_new(). */ -#if LWIP_TCPIP_CORE_LOCKING -#define LWIP_NETCONN_SEM_PER_THREAD 0 -#else #define LWIP_NETCONN_SEM_PER_THREAD 1 -#endif /** LWIP_NETCONN_FULLDUPLEX==1: Enable code that allows reading from one thread, * writing from a 2nd thread and closing from a 3rd thread at the same time. @@ -1198,11 +1206,17 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min) #endif #define LWIP_HOOK_FILENAME "lwip_default_hooks.h" #define LWIP_HOOK_IP4_ROUTE_SRC ip4_route_src_hook +#if LWIP_NETCONN_FULLDUPLEX +#define LWIP_DONE_SOCK(s) done_socket(sock) +#else +#define LWIP_DONE_SOCK(s) ((void)1) +#endif /* LWIP_NETCONN_FULLDUPLEX */ + #define LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, err) \ - lwip_getsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(done_socket(sock), true): false + lwip_getsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(LWIP_DONE_SOCK(sock), true): false #define LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, err) \ - lwip_setsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(done_socket(sock), true): false + lwip_setsockopt_impl_ext(sock, level, optname, optval, optlen, err)?(LWIP_DONE_SOCK(sock), true): false /* --------------------------------------- diff --git a/components/lwip/test_afl_host/sdkconfig.defaults b/components/lwip/test_afl_host/sdkconfig.defaults index 81952aa5bb2..ee235abe9f7 100644 --- a/components/lwip/test_afl_host/sdkconfig.defaults +++ b/components/lwip/test_afl_host/sdkconfig.defaults @@ -1,2 +1,4 @@ +CONFIG_LWIP_TCPIP_CORE_LOCKING=n +CONFIG_LWIP_CHECK_THREAD_SAFETY=n CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=n CONFIG_FREERTOS_SMP=n diff --git a/components/lwip/test_apps/main/lwip_test.c b/components/lwip/test_apps/main/lwip_test.c index dc5fbc792ed..376bb561587 100644 --- a/components/lwip/test_apps/main/lwip_test.c +++ b/components/lwip/test_apps/main/lwip_test.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,8 @@ #include "lwip/inet.h" #include "lwip/netdb.h" #include "lwip/sockets.h" +#include "lwip/tcpip.h" +#include "lwip/prot/iana.h" #include "ping/ping_sock.h" #include "dhcpserver/dhcpserver.h" #include "dhcpserver/dhcpserver_options.h" @@ -142,12 +144,18 @@ TEST(lwip, dhcp_server_init_deinit) dhcps_delete(dhcps); } -TEST(lwip, dhcp_server_start_stop_localhost) +struct dhcps_api { + EventGroupHandle_t event; + ip4_addr_t netmask; + ip4_addr_t ip; + err_t ret_start; + err_t ret_stop; +}; + +static void dhcps_test_net_classes_api(void* ctx) { - test_case_uses_tcpip(); struct netif *netif; - dhcps_t *dhcps; - ip4_addr_t netmask; + struct dhcps_api *api = ctx; NETIF_FOREACH(netif) { if (netif->name[0] == 'l' && netif->name[1] == 'o') { @@ -156,41 +164,51 @@ TEST(lwip, dhcp_server_start_stop_localhost) } TEST_ASSERT_NOT_NULL(netif); - //Class A - dhcps = dhcps_new(); - IP4_ADDR(&netmask, 255,0,0,0); - dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&netmask, sizeof(netmask)); - ip4_addr_t a_ip = { .addr = 0x7f0001 }; - IP4_ADDR(&netmask, 255,0,0,0); - TEST_ASSERT(dhcps_start(dhcps, netif, a_ip) == ERR_OK); - TEST_ASSERT(dhcps_stop(dhcps, netif) == ERR_OK); + dhcps_t *dhcps = dhcps_new(); + dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&api->netmask, sizeof(api->netmask)); + api->ret_start = dhcps_start(dhcps, netif, api->ip); + api->ret_stop = dhcps_stop(dhcps, netif); dhcps_delete(dhcps); + xEventGroupSetBits(api->event, 1); +} - //Class B - dhcps = dhcps_new(); - IP4_ADDR(&netmask, 255,255,0,0); - dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&netmask, sizeof(netmask)); - ip4_addr_t b_ip = { .addr = 0x1000080 }; - TEST_ASSERT(dhcps_start(dhcps, netif, b_ip) == ERR_OK); - TEST_ASSERT(dhcps_stop(dhcps, netif) == ERR_OK); - dhcps_delete(dhcps); +static void dhcps_test_net_classes(uint32_t ip, uint32_t mask, bool pass) +{ - //Class C - dhcps = dhcps_new(); - IP4_ADDR(&netmask, 255,255,255,0); - dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&netmask, sizeof(netmask)); - ip4_addr_t c_ip = { .addr = 0x101A8C0 }; - TEST_ASSERT(dhcps_start(dhcps, netif, c_ip) == ERR_OK); - TEST_ASSERT(dhcps_stop(dhcps, netif) == ERR_OK); - dhcps_delete(dhcps); + struct dhcps_api api = { + .ret_start = ERR_IF, + .ret_stop = ERR_IF, + .ip = {.addr = PP_HTONL(ip)}, + .netmask = {.addr = PP_HTONL(mask)}, + .event = xEventGroupCreate() + }; + + tcpip_callback(dhcps_test_net_classes_api, &api); + xEventGroupWaitBits(api.event, 1, true, true, pdMS_TO_TICKS(5000)); + vEventGroupDelete(api.event); + err_t ret_start_expected = pass ? ERR_OK : ERR_ARG; + TEST_ASSERT(api.ret_start == ret_start_expected); + TEST_ASSERT(api.ret_stop == ERR_OK); + +} + +TEST(lwip, dhcp_server_start_stop_localhost) +{ + test_case_uses_tcpip(); + + // Class A: IP: 127.0.0.1, Mask: 255.0.0.0 + dhcps_test_net_classes(0x7f000001, 0xFF000000, true); + + // Class B: IP: 128.1.1.1, Mask: 255.255.0.0 + dhcps_test_net_classes(0x80010101, 0xFFFF0000, true); + + // Class C: IP: 192.168.1.1, Mask: 255.255.255.0 + dhcps_test_net_classes(0xC0A80101, 0xFFFFFF00, true); + + // Class A: IP: 127.0.0.1, with Class C Mask: 255.255.255.0 + // expect dhcps_start() to fail + dhcps_test_net_classes(0x7f000001, 0xFFFFFF00, false); - //Class A Subnet C - dhcps = dhcps_new(); - IP4_ADDR(&netmask, 255,255,255,0); - dhcps_set_option_info(dhcps, SUBNET_MASK, (void*)&netmask, sizeof(netmask)); - TEST_ASSERT(dhcps_start(dhcps, netif, a_ip) == ERR_ARG); - TEST_ASSERT(dhcps_stop(dhcps, netif) == ERR_OK); - dhcps_delete(dhcps); } @@ -248,11 +266,10 @@ void test_sntp_timestamps(int year, bool msb_flag) { int sock = test_sntp_server_create(); - // setup lwip's SNTP in polling mode - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_setservername(0, "127.0.0.1"); - sntp_init(); - + // init and start the SNTP + esp_sntp_setoperatingmode(SNTP_OPMODE_POLL); + esp_sntp_setservername(0, "127.0.0.1"); + esp_sntp_init(); // wait until time sync int retry = 0; while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET) { @@ -269,7 +286,7 @@ void test_sntp_timestamps(int year, bool msb_flag) TEST_ASSERT_EQUAL(year, 1900 + timeinfo.tm_year); // close the SNTP and the fake server - sntp_stop(); + esp_sntp_stop(); close(sock); } diff --git a/components/openthread/lib b/components/openthread/lib index 7d57b18006d..2e5a3f236f8 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit 7d57b18006da6e182ddb87698abdced1566f3b56 +Subproject commit 2e5a3f236f8cd7c753fd8b8f775e48e8be5f08d6 diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 74140455f4f..aa205b4bfde 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -155,6 +155,7 @@ INPUT = \ $(PROJECT_PATH)/components/esp_netif/include/esp_netif_types.h \ $(PROJECT_PATH)/components/esp_netif/include/esp_netif.h \ $(PROJECT_PATH)/components/esp_netif/include/esp_vfs_l2tap.h \ + $(PROJECT_PATH)/components/esp_netif/include/esp_netif_sntp.h \ $(PROJECT_PATH)/components/esp_partition/include/esp_partition.h \ $(PROJECT_PATH)/components/esp_phy/include/esp_phy_init.h \ $(PROJECT_PATH)/components/esp_pm/include/$(IDF_TARGET)/pm.h \ diff --git a/docs/en/api-guides/lwip.rst b/docs/en/api-guides/lwip.rst index 012a32f4aa8..19685c5146d 100644 --- a/docs/en/api-guides/lwip.rst +++ b/docs/en/api-guides/lwip.rst @@ -14,10 +14,15 @@ ESP-IDF supports the following lwIP TCP/IP stack functions: Adapted APIs ^^^^^^^^^^^^ + .. warning:: + + When using any lwIP API (other than `BSD Sockets API`_), please make sure that it is thread safe. To check if a given API call is safe, enable :ref:`CONFIG_LWIP_CHECK_THREAD_SAFETY` and run the application. This way lwIP asserts the TCP/IP core functionality to be correctly accessed; the execution aborts if it is not locked properly or accessed from the correct task (`lwIP FreeRTOS Task`_). + The general recommendation is to use :doc:`/api-reference/network/esp_netif` component to interact with lwIP. + Some common lwIP "app" APIs are supported indirectly by ESP-IDF: - DHCP Server & Client are supported indirectly via the :doc:`/api-reference/network/esp_netif` functionality -- Simple Network Time Protocol (SNTP) is supported via the :component_file:`lwip/include/apps/sntp/sntp.h` :component_file:`lwip/lwip/src/include/lwip/apps/sntp.h` functions (see also :ref:`system-time-sntp-sync`) +- Simple Network Time Protocol (SNTP) is also supported via the :doc:`/api-reference/network/esp_netif`, or directly via the :component_file:`lwip/include/apps/esp_sntp.h` functions that provide thread-safe API to :component_file:`lwip/lwip/src/include/lwip/apps/sntp.h` functions (see also :ref:`system-time-sntp-sync`) - ICMP Ping is supported using a variation on the lwIP ping API. See :doc:`/api-reference/protocols/icmp_echo`. - NetBIOS lookup is available using the standard lwIP API. :example:`protocols/http_server/restful_server` has an option to demonstrate using NetBIOS to look up a host on the LAN. - mDNS uses a different implementation to the lwIP default mDNS (see :doc:`/api-reference/protocols/mdns`), but lwIP can look up mDNS hosts using standard APIs such as ``gethostbyname()`` and the convention ``hostname.local``, provided the :ref:`CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES` setting is enabled. diff --git a/docs/en/api-reference/network/esp_netif.rst b/docs/en/api-reference/network/esp_netif.rst index fbdd9333b89..f0a3aef403d 100644 --- a/docs/en/api-reference/network/esp_netif.rst +++ b/docs/en/api-reference/network/esp_netif.rst @@ -21,14 +21,14 @@ ESP-NETIF architecture | (A) USER CODE | - | | + | Apps | .................| init settings events | . +----------------------------------------+ . . | * . . | * --------+ +===========================+ * +-----------------------+ - | | new/config get/set | * | | - | | |...*.....| init | + | | new/config get/set/apps | * | init | + | | |...*.....| Apps (DHCP, SNTP) | | |---------------------------| * | | init | | |**** | | start |************| event handler |*********| DHCP | @@ -132,6 +132,7 @@ ESP-NETIF is an intermediary between an IO driver and a network stack, connectin * Set interface up or down * DHCP server and client API * DNS API + * `SNTP API`_ 6) Driver conversion utilities @@ -242,6 +243,81 @@ select() Select is used in a standard way, just :ref:`CONFIG_VFS_SUPPORT_SELECT` needs to be enabled to be the ``select()`` function available. +.. _esp_netif-sntp-api: + +SNTP API +-------- + +You can find a brief introduction to SNTP in general, its initialization code and basic modes in :ref:`system-time-sntp-sync` section in the :doc:`System Time Document`. + +This section provides more details about specific use cases of SNTP service, with statically configured servers, or using DHCP provided servers, or both. +The workflow is usually very simple: + +1) Initialize and configure the service using :cpp:func:`esp_netif_sntp_init()`. +2) Start the service via :cpp:func:`esp_netif_sntp_start()`. This step is not needed if we auto-started the service in the previous step (default). It's useful to start the service explicitly after connecting, if we want to use DHCP obtained NTP servers. (This option needs to be enabled before connecting, but SNTP service should be started after) +3) Wait for the system time to synchronize using :cpp:func:`esp_netif_sntp_sync_wait()` (only if needed). +4) Stop and destroy the service using :cpp:func:`esp_netif_sntp_deinit()`. + + +Basic mode with statically defined server(s) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Initialize the module with the default configuration after connecting to network. Note that it's possible to provide multiple NTP servers in the configuration struct: + +.. code-block:: c + + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2, + ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org" ) ); + esp_netif_sntp_init(&config); + +.. note:: + + If we want to configure multiple SNTP servers, we have to update lwIP configuration :ref:`CONFIG_LWIP_SNTP_MAX_SERVERS`. + + +Use DHCP obtained SNTP server(s) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +First of all, we have to enable lwIP configuration option :ref:`CONFIG_LWIP_DHCP_GET_NTP_SRV`. +Then we have to initialize the SNTP module with the DHCP option and no NTP server: + +.. code-block:: c + + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(0, {} ); + config.start = false; // start SNTP service explicitly + config.server_from_dhcp = true; // accept NTP offer from DHCP server + esp_netif_sntp_init(&config); + +Then, once we're connected, we could start the service using: + +.. code-block:: c + + esp_netif_sntp_start(); + +.. note:: + + It's also possible to start the service during initialization (default ``config.start=true``). This would likely cause the initial SNTP request to fail (since we are not connected yet) and thus some backoff time for subsequent requests. + + +Use both static and dynamic servers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Very similar to the scenario above (DHCP provided SNTP server), but in this configuration we need to make sure that the static server configuration is refreshed when obtaining NTP servers by DHCP. The underlying lwIP code cleans up the rest of the list of NTP servers when DHCP provided information gets accepted. Thus the ESP-NETIF SNTP module saves the statically configured server(s) and reconfigures them after obtaining DHCP lease. + +The typical configuration now looks as per below, providing the specific ``IP_EVENT`` to update the config and index of the first server to reconfigure (for example setting ``config.index_of_first_server=1`` would keep DHCP provided server at index 0, and the statically configured server at index 1). + +.. code-block:: c + + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org"); + config.start = false; // start SNTP service explicitly (after connecting) + config.server_from_dhcp = true; // accept NTP offers from DHCP server + config.renew_servers_after_new_IP = true; // let esp-netif update configured SNTP server(s) after receiving DHCP lease + config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact + config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; // IP event on which we refresh the configuration + +Then we start the service normally with :cpp:func:`esp_netif_sntp_start()`. + + ESP-NETIF programmer's manual ----------------------------- @@ -287,6 +363,7 @@ API Reference ------------- .. include-build-file:: inc/esp_netif.inc +.. include-build-file:: inc/esp_netif_sntp.inc .. include-build-file:: inc/esp_netif_types.inc .. include-build-file:: inc/esp_netif_ip_addr.inc .. include-build-file:: inc/esp_vfs_l2tap.inc diff --git a/docs/en/api-reference/system/system_time.rst b/docs/en/api-reference/system/system_time.rst index 3643e76dc8b..41b2958576b 100644 --- a/docs/en/api-reference/system/system_time.rst +++ b/docs/en/api-reference/system/system_time.rst @@ -108,28 +108,46 @@ SNTP Time Synchronization To set the current time, you can use the POSIX functions ``settimeofday()`` and ``adjtime()``. They are used internally in the lwIP SNTP library to set current time when a response from the NTP server is received. These functions can also be used separately from the lwIP SNTP library. -The function to use inside the lwIP SNTP library depends on the sync mode for system time. Use the function :cpp:func:`sntp_set_sync_mode` to set one of the following sync modes: +Some lwIP APIs, including SNTP functions, are not thread safe, so it is recommended to use :doc:`esp_netif component <../network/esp_netif>` when interacting with SNTP module. -- :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` (default): Updates system time immediately upon receiving a response from the SNTP server after using ``settimeofday()``. -- :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH`: Updates time smoothly by gradually reducing time error using the function ``adjtime()``. If the difference between the SNTP response time and system time is more than 35 minutes, update system time immediately by using ``settimeofday()``. +To initialize a particular SNTP server and also start the SNTP service, simply create a default SNTP server configuration with a particular server name, then call :cpp:func:`esp_netif_sntp_init()` to register that server and start the SNTP service. -The lwIP SNTP library has API functions for setting a callback function for a certain event. You might need the following functions: +.. code-block:: c -- :cpp:func:`sntp_set_time_sync_notification_cb()`: Can be used to set a callback function that will notify of the time synchronization process. -- :cpp:func:`sntp_get_sync_status()` and :cpp:func:`sntp_set_sync_status()`: Can be used to get/set time synchronization status. + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org"); + esp_netif_sntp_init(&config); -To start synchronization via SNTP, just call the following three functions: +This code automatically performs time synchronization once a reply from the SNTP server is received. Sometimes it is useful to wait until the time gets synchronized, :cpp:func:`esp_netif_sntp_sync_wait()` can be used for this purpose: .. code-block:: c - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_setservername(0, "pool.ntp.org"); - sntp_init(); + if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) { + printf("Failed to update system time within 10s timeout"); + } + +To configure multiple NTP servers (or use more advanced settings, such as DHCP provided NTP servers), please refer to the detailed description of :ref:`esp_netif-sntp-api` in :doc:`esp_netif <../network/esp_netif>` documentation. + +The lwIP SNTP library could work in one of the following sync modes: + +- :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` (default): Updates system time immediately upon receiving a response from the SNTP server after using ``settimeofday()``. +- :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH`: Updates time smoothly by gradually reducing time error using the function ``adjtime()``. If the difference between the SNTP response time and system time is more than 35 minutes, update system time immediately by using ``settimeofday()``. + +If you want to choose the :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH` mode, please set the :cpp:member:`esp_sntp_config::smooth` to ``true`` in the SNTP configuration struct. Otherwise (and by default) the :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` mode will be used. + +For setting a callback function when time gets synchronized, use the :cpp:member:`esp_sntp_config::sync_cb` field in the configuration struct. An application with this initialization code will periodically synchronize the time. The time synchronization period is determined by :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` (the default value is one hour). To modify the variable, set :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` in project configuration. A code example that demonstrates the implementation of time synchronization based on the lwIP SNTP library is provided in the :example:`protocols/sntp` directory. +Note that it's also possible to use lwIP API directly, but care must be taken to thread safety. Here we list the thread-safe APIs: + +- :cpp:func:`sntp_set_time_sync_notification_cb()`: Can be used to set a callback function that will notify of the time synchronization process. +- :cpp:func:`sntp_get_sync_status()` and :cpp:func:`sntp_set_sync_status()`: Can be used to get/set time synchronization status. +- :cpp:func:`sntp_set_sync_mode` can be used to set the synchronization mode +- :cpp:func:`esp_sntp_setoperatingmode` sets the preferred operating mode :cpp:enumerator:`ESP_SNTP_OPMODE_POLL` and :cpp:func:`esp_sntp_init` initializes SNTP modeule +- :cpp:func:`esp_sntp_setservername` configures one SNTP server + Timezones --------- diff --git a/docs/en/migration-guides/release-5.x/5.1/index.rst b/docs/en/migration-guides/release-5.x/5.1/index.rst index a20553ae6f9..21ae7745522 100644 --- a/docs/en/migration-guides/release-5.x/5.1/index.rst +++ b/docs/en/migration-guides/release-5.x/5.1/index.rst @@ -7,3 +7,4 @@ Migration from 5.0 to 5.1 :maxdepth: 1 peripherals + networking diff --git a/docs/en/migration-guides/release-5.x/5.1/networking.rst b/docs/en/migration-guides/release-5.x/5.1/networking.rst new file mode 100644 index 00000000000..a8b842810e3 --- /dev/null +++ b/docs/en/migration-guides/release-5.x/5.1/networking.rst @@ -0,0 +1,9 @@ +Networking +=========== + +:link_to_translation:`zh_CN:[中文]` + +SNTP +---- + +SNTP module now provides thread safe APIs to access lwIP functionality. It's recommended to use :doc:`ESP_NETIF ` API. Please refer to the chapter :ref:`esp_netif-sntp-api` for more details. diff --git a/docs/zh_CN/migration-guides/release-5.x/5.1/index.rst b/docs/zh_CN/migration-guides/release-5.x/5.1/index.rst index b27372a2ca4..3c2f45c8dc4 100644 --- a/docs/zh_CN/migration-guides/release-5.x/5.1/index.rst +++ b/docs/zh_CN/migration-guides/release-5.x/5.1/index.rst @@ -7,3 +7,4 @@ :maxdepth: 1 peripherals + networking diff --git a/docs/zh_CN/migration-guides/release-5.x/5.1/networking.rst b/docs/zh_CN/migration-guides/release-5.x/5.1/networking.rst new file mode 100644 index 00000000000..39da77226e4 --- /dev/null +++ b/docs/zh_CN/migration-guides/release-5.x/5.1/networking.rst @@ -0,0 +1,9 @@ +网络 +=========== + +:link_to_translation:`en:[English]` + +SNTP +***** + +请参考章节 :ref:`esp_netif-sntp-api` 了解更多详情。 diff --git a/examples/openthread/ot_br/main/idf_component.yml b/examples/openthread/ot_br/main/idf_component.yml index c5955f8e3b5..06ebf10ab6b 100644 --- a/examples/openthread/ot_br/main/idf_component.yml +++ b/examples/openthread/ot_br/main/idf_component.yml @@ -1,6 +1,7 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp_ot_cli_extension: "~0.2.0" + espressif/esp_ot_cli_extension: + version: "~0.3.0" espressif/mdns: "^1.0.3" ## Required IDF version idf: diff --git a/examples/openthread/ot_cli/main/idf_component.yml b/examples/openthread/ot_cli/main/idf_component.yml index 768f5e8b22c..33680db455a 100644 --- a/examples/openthread/ot_cli/main/idf_component.yml +++ b/examples/openthread/ot_cli/main/idf_component.yml @@ -1,5 +1,6 @@ ## IDF Component Manager Manifest File dependencies: - espressif/esp_ot_cli_extension: "~0.2.0" + espressif/esp_ot_cli_extension: + version: "~0.3.0" idf: version: ">=4.1.0" diff --git a/examples/protocols/http2_request/main/http2_request_example_main.c b/examples/protocols/http2_request/main/http2_request_example_main.c index b7fd45bd7dc..e1b79c3a668 100644 --- a/examples/protocols/http2_request/main/http2_request_example_main.c +++ b/examples/protocols/http2_request/main/http2_request_example_main.c @@ -17,11 +17,11 @@ #include "freertos/task.h" #include "esp_wifi.h" #include "esp_event.h" -#include "lwip/apps/sntp.h" #include "esp_system.h" #include "nvs_flash.h" #include "protocol_examples_common.h" #include "esp_netif.h" +#include "esp_netif_sntp.h" #include "sdkconfig.h" #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE @@ -90,8 +90,12 @@ static void set_time(void) settimeofday(&tv, &tz); /* Start SNTP service */ - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_init(); + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("time.windows.com"); + esp_netif_sntp_init(&config); + if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) { + printf("Failed to update system time, continuing"); + } + esp_netif_deinit(); } static void http2_task(void *args) diff --git a/examples/protocols/https_request/main/time_sync.c b/examples/protocols/https_request/main/time_sync.c index faeca0d4846..5e158c17cea 100644 --- a/examples/protocols/https_request/main/time_sync.c +++ b/examples/protocols/https_request/main/time_sync.c @@ -16,8 +16,8 @@ #include "esp_system.h" #include "nvs_flash.h" #include "nvs.h" -#include "esp_sntp.h" #include "esp_netif.h" +#include "esp_netif_sntp.h" #include "lwip/err.h" #include "lwip/sockets.h" @@ -33,31 +33,18 @@ static const char *TAG = "time_sync"; void initialize_sntp(void) { ESP_LOGI(TAG, "Initializing SNTP"); - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_setservername(0, "time.windows.com"); - sntp_setservername(1, "pool.ntp.org"); -#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH - sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH); -#endif - sntp_init(); + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2, + ESP_SNTP_SERVER_LIST("time.windows.com", "pool.ntp.org" ) ); + esp_netif_sntp_init(&config); } static esp_err_t obtain_time(void) { - /** - * NTP server address could be aquired via DHCP, - * see LWIP_DHCP_GET_NTP_SRV menuconfig option - */ -#ifdef LWIP_DHCP_GET_NTP_SRV - sntp_servermode_dhcp(1); -#endif - // wait for time to be set int retry = 0; const int retry_count = 10; - while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) { + while (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(2000)) != ESP_OK && ++retry < retry_count) { ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); - vTaskDelay(2000 / portTICK_PERIOD_MS); } if (retry == retry_count) { return ESP_FAIL; @@ -96,7 +83,7 @@ esp_err_t fetch_and_store_time_in_nvs(void *args) } nvs_close(my_handle); - sntp_stop(); + esp_netif_deinit(); exit: if (err != ESP_OK) { diff --git a/examples/protocols/mqtt/ssl/sdkconfig.ci b/examples/protocols/mqtt/ssl/sdkconfig.ci index 3271d9678e4..e8d4a52f63f 100644 --- a/examples/protocols/mqtt/ssl/sdkconfig.ci +++ b/examples/protocols/mqtt/ssl/sdkconfig.ci @@ -19,3 +19,4 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_ADDR=1 CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_LWIP_CHECK_THREAD_SAFETY=y diff --git a/examples/protocols/mqtt/tcp/sdkconfig.ci b/examples/protocols/mqtt/tcp/sdkconfig.ci index 28ce9ac93d8..acf084a9e45 100644 --- a/examples/protocols/mqtt/tcp/sdkconfig.ci +++ b/examples/protocols/mqtt/tcp/sdkconfig.ci @@ -9,3 +9,5 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_ADDR=1 CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_LWIP_TCPIP_CORE_LOCKING=y +CONFIG_LWIP_CHECK_THREAD_SAFETY=y diff --git a/examples/protocols/mqtt/ws/sdkconfig.ci b/examples/protocols/mqtt/ws/sdkconfig.ci index 2f8e425e467..eebcafdead0 100644 --- a/examples/protocols/mqtt/ws/sdkconfig.ci +++ b/examples/protocols/mqtt/ws/sdkconfig.ci @@ -8,3 +8,4 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_ADDR=1 CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_LWIP_CHECK_THREAD_SAFETY=y diff --git a/examples/protocols/mqtt/wss/sdkconfig.ci b/examples/protocols/mqtt/wss/sdkconfig.ci index f355614e4fa..c8e8ef94a47 100644 --- a/examples/protocols/mqtt/wss/sdkconfig.ci +++ b/examples/protocols/mqtt/wss/sdkconfig.ci @@ -9,3 +9,5 @@ CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 CONFIG_EXAMPLE_ETH_PHY_ADDR=1 CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_LWIP_TCPIP_CORE_LOCKING=y +CONFIG_LWIP_CHECK_THREAD_SAFETY=y diff --git a/examples/protocols/sntp/main/sntp_example_main.c b/examples/protocols/sntp/main/sntp_example_main.c index 1cfa6eb3c60..cdb681890da 100644 --- a/examples/protocols/sntp/main/sntp_example_main.c +++ b/examples/protocols/sntp/main/sntp_example_main.c @@ -9,10 +9,6 @@ #include #include #include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/event_groups.h" #include "esp_system.h" #include "esp_event.h" #include "esp_log.h" @@ -20,6 +16,8 @@ #include "esp_sleep.h" #include "nvs_flash.h" #include "protocol_examples_common.h" +#include "esp_netif_sntp.h" +#include "lwip/ip_addr.h" #include "esp_sntp.h" static const char *TAG = "example"; @@ -35,7 +33,6 @@ static const char *TAG = "example"; RTC_DATA_ATTR static int boot_count = 0; static void obtain_time(void); -static void initialize_sntp(void); #ifdef CONFIG_SNTP_TIME_SYNC_METHOD_CUSTOM void sntp_sync_time(struct timeval *tv) @@ -121,24 +118,55 @@ void app_main(void) esp_deep_sleep(1000000LL * deep_sleep_sec); } +static void print_servers(void) +{ + ESP_LOGI(TAG, "List of configured NTP servers:"); + + for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){ + if (esp_sntp_getservername(i)){ + ESP_LOGI(TAG, "server %d: %s", i, esp_sntp_getservername(i)); + } else { + // we have either IPv4 or IPv6 address, let's print it + char buff[INET6_ADDRSTRLEN]; + ip_addr_t const *ip = esp_sntp_getserver(i); + if (ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN) != NULL) + ESP_LOGI(TAG, "server %d: %s", i, buff); + } + } +} + static void obtain_time(void) { ESP_ERROR_CHECK( nvs_flash_init() ); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK( esp_event_loop_create_default() ); +#if LWIP_DHCP_GET_NTP_SRV /** - * NTP server address could be aquired via DHCP, + * NTP server address could be acquired via DHCP, * see following menuconfig options: * 'LWIP_DHCP_GET_NTP_SRV' - enable STNP over DHCP * 'LWIP_SNTP_DEBUG' - enable debugging messages * - * NOTE: This call should be made BEFORE esp aquires IP address from DHCP, + * NOTE: This call should be made BEFORE esp acquires IP address from DHCP, * otherwise NTP option would be rejected by default. */ -#ifdef LWIP_DHCP_GET_NTP_SRV - sntp_servermode_dhcp(1); // accept NTP offers from DHCP server, if any + ESP_LOGI(TAG, "Initializing SNTP"); + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER); + config.start = false; // start SNTP service explicitly (after connecting) + config.server_from_dhcp = true; // accept NTP offers from DHCP server, if any (need to enable *before* connecting) + config.renew_servers_after_new_IP = true; // let esp-netif update configured SNTP server(s) after receiving DHCP lease + config.index_of_first_server = 1; // updates from server num 1, leaving server 0 (from DHCP) intact + // configure the event on which we renew servers +#ifdef CONFIG_EXAMPLE_CONNECT_WIFI + config.ip_event_to_renew = IP_EVENT_STA_GOT_IP; +#else + config.ip_event_to_renew = IP_EVENT_ETH_GOT_IP; #endif + config.sync_cb = time_sync_notification_cb; // only if we need the notification function + esp_netif_sntp_init(&config); + +#endif /* LWIP_DHCP_GET_NTP_SRV */ /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. * Read "Establishing Wi-Fi or Ethernet Connection" section in @@ -146,67 +174,53 @@ static void obtain_time(void) */ ESP_ERROR_CHECK(example_connect()); - initialize_sntp(); +#if LWIP_DHCP_GET_NTP_SRV + ESP_LOGI(TAG, "Starting SNTP"); + esp_netif_sntp_start(); +#if LWIP_IPV6 && SNTP_MAX_SERVERS > 2 + /* This demonstrates using IPv6 address as an additional SNTP server + * (statically assigned IPv6 address is also possible) + */ + ip_addr_t ip6; + if (ipaddr_aton("2a01:3f7::1", &ip6)) { // ipv6 ntp source "ntp.netnod.se" + esp_sntp_setserver(2, &ip6); + } +#endif /* LWIP_IPV6 */ + +#else + ESP_LOGI(TAG, "Initializing and starting SNTP"); +#if CONFIG_LWIP_SNTP_MAX_SERVERS > 1 + /* This demonstrates configuring more than one server + */ + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(2, + ESP_SNTP_SERVER_LIST(CONFIG_SNTP_TIME_SERVER, "pool.ntp.org" ) ); +#else + /* + * This is the basic default config with one server and starting the service + */ + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER); +#endif + config.sync_cb = time_sync_notification_cb; // Note: This is only needed if we want +#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH + config.smooth_sync = true; +#endif + + esp_netif_sntp_init(&config); +#endif + + print_servers(); // wait for time to be set time_t now = 0; struct tm timeinfo = { 0 }; int retry = 0; const int retry_count = 15; - while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) { + while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) { ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); - vTaskDelay(2000 / portTICK_PERIOD_MS); } time(&now); localtime_r(&now, &timeinfo); ESP_ERROR_CHECK( example_disconnect() ); -} - -static void initialize_sntp(void) -{ - ESP_LOGI(TAG, "Initializing SNTP"); - sntp_setoperatingmode(SNTP_OPMODE_POLL); - -/* - * If 'NTP over DHCP' is enabled, we set dynamic pool address - * as a 'secondary' server. It will act as a fallback server in case that address - * provided via NTP over DHCP is not accessible - */ -#if LWIP_DHCP_GET_NTP_SRV && SNTP_MAX_SERVERS > 1 - sntp_setservername(1, "pool.ntp.org"); - -#if LWIP_IPV6 && SNTP_MAX_SERVERS > 2 // statically assigned IPv6 address is also possible - ip_addr_t ip6; - if (ipaddr_aton("2a01:3f7::1", &ip6)) { // ipv6 ntp source "ntp.netnod.se" - sntp_setserver(2, &ip6); - } -#endif /* LWIP_IPV6 */ - -#else /* LWIP_DHCP_GET_NTP_SRV && (SNTP_MAX_SERVERS > 1) */ - // otherwise, use DNS address from a pool - sntp_setservername(0, CONFIG_SNTP_TIME_SERVER); - - sntp_setservername(1, "pool.ntp.org"); // set the secondary NTP server (will be used only if SNTP_MAX_SERVERS > 1) -#endif - - sntp_set_time_sync_notification_cb(time_sync_notification_cb); -#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH - sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH); -#endif - sntp_init(); - - ESP_LOGI(TAG, "List of configured NTP servers:"); - - for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i){ - if (sntp_getservername(i)){ - ESP_LOGI(TAG, "server %d: %s", i, sntp_getservername(i)); - } else { - // we have either IPv4 or IPv6 address, let's print it - char buff[INET6_ADDRSTRLEN]; - ip_addr_t const *ip = sntp_getserver(i); - if (ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN) != NULL) - ESP_LOGI(TAG, "server %d: %s", i, buff); - } - } + esp_netif_sntp_deinit(); } diff --git a/examples/protocols/sntp/pytest_sntp.py b/examples/protocols/sntp/pytest_sntp.py index fb5f83dc68f..a32eed3c721 100644 --- a/examples/protocols/sntp/pytest_sntp.py +++ b/examples/protocols/sntp/pytest_sntp.py @@ -22,7 +22,7 @@ def test_get_time_from_sntp_server(dut: Dut) -> None: dut.write(f'{ap_ssid} {ap_password}') dut.expect('IPv4 address:') - dut.expect('Initializing SNTP') + dut.expect('Initializing and starting SNTP') dut.expect(r'Waiting for system time to be set... \(\d+/\d+\)') dut.expect('Notification of a time synchronization event') diff --git a/examples/system/ota/advanced_https_ota/sdkconfig.ci b/examples/system/ota/advanced_https_ota/sdkconfig.ci index 162324ed34e..9a7434b63cf 100644 --- a/examples/system/ota/advanced_https_ota/sdkconfig.ci +++ b/examples/system/ota/advanced_https_ota/sdkconfig.ci @@ -15,3 +15,4 @@ CONFIG_EXAMPLE_ETH_PHY_ADDR=1 CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_EXAMPLE_CONNECT_IPV6=n +CONFIG_LWIP_CHECK_THREAD_SAFETY=y diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index fc5c2b16ba9..bb526168f40 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -437,7 +437,6 @@ components/esp_local_ctrl/src/esp_local_ctrl_handler.c components/esp_local_ctrl/src/esp_local_ctrl_priv.h components/esp_local_ctrl/src/esp_local_ctrl_transport_ble.c components/esp_netif/include/esp_netif_ppp.h -components/esp_netif/private_include/esp_netif_private.h components/esp_netif/test/test_esp_netif.c components/esp_netif/test_apps/component_ut_test.py components/esp_netif/test_apps/main/esp_netif_test.c @@ -724,7 +723,6 @@ components/lwip/apps/ping/ping.c components/lwip/include/apps/dhcpserver/dhcpserver_options.h components/lwip/include/apps/esp_ping.h components/lwip/include/apps/ping/ping.h -components/lwip/include/apps/sntp/sntp.h components/lwip/port/esp32/debug/lwip_debug.c components/lwip/port/esp32/freertos/sys_arch.c components/lwip/port/esp32/hooks/tcp_isn_default.c diff --git a/tools/unit-test-app/configs/mqtt b/tools/unit-test-app/configs/mqtt index 7608145d39e..7ba01ae76ba 100644 --- a/tools/unit-test-app/configs/mqtt +++ b/tools/unit-test-app/configs/mqtt @@ -1,3 +1,5 @@ TEST_COMPONENTS=mqtt CONFIG_MQTT_PROTOCOL_5=y CONFIG_MQTT5_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTTV5_BROKER_TCP}" +CONFIG_LWIP_TCPIP_CORE_LOCKING=y +CONFIG_LWIP_CHECK_THREAD_SAFETY=y