From 5b75693522d389572c076aa489ad7c273936c47e Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 27 Oct 2022 19:07:07 +0200 Subject: [PATCH 1/5] esp_netif/lwip: Fix core-locking config (v5.0) * 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 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 | 1 + components/esp_netif/include/esp_netif.h | 49 +++ components/esp_netif/lwip/esp_netif_lwip.c | 322 ++++++++++++------ .../esp_netif/lwip/esp_netif_lwip_internal.h | 5 +- .../private_include/esp_netif_private.h | 46 +-- components/lwip/Kconfig | 13 +- components/lwip/apps/sntp/sntp.c | 130 ++++++- components/lwip/include/apps/esp_sntp.h | 72 +++- components/lwip/include/apps/sntp/sntp.h | 27 +- .../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 + docs/en/api-guides/lwip.rst | 5 + docs/en/api-reference/system/system_time.rst | 6 +- .../api-reference/system/system_time.rst | 6 +- .../main/http2_request_example_main.c | 6 +- .../protocols/https_request/main/time_sync.c | 14 +- .../protocols/sntp/main/sntp_example_main.c | 22 +- tools/ci/check_copyright_ignore.txt | 3 - 21 files changed, 578 insertions(+), 231 deletions(-) diff --git a/components/esp_netif/CMakeLists.txt b/components/esp_netif/CMakeLists.txt index 6eb4d85911..5846aa75d9 100644 --- a/components/esp_netif/CMakeLists.txt +++ b/components/esp_netif/CMakeLists.txt @@ -51,3 +51,4 @@ if(CONFIG_ESP_NETIF_L2_TAP OR CONFIG_ESP_NETIF_BRIDGE_EN) 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 3831655a4d..aeb5ffdd6a 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/lwip/esp_netif_lwip.c b/components/esp_netif/lwip/esp_netif_lwip.c index d6bbd733ed..c84d3217c5 100644 --- a/components/esp_netif/lwip/esp_netif_lwip.c +++ b/components/esp_netif/lwip/esp_netif_lwip.c @@ -100,12 +100,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 @@ -136,17 +132,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) @@ -186,6 +193,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 @@ -202,33 +210,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); } /** @@ -458,10 +492,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]; /* @@ -474,13 +513,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 @@ -499,18 +546,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); */ @@ -612,6 +663,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 @@ -657,7 +718,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 @@ -696,7 +757,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; } @@ -783,18 +846,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); @@ -842,6 +911,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) { @@ -850,9 +928,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[]) @@ -2018,70 +2094,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: { @@ -2089,7 +2170,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)); @@ -2116,11 +2197,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); @@ -2128,7 +2209,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); @@ -2139,63 +2220,82 @@ 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; } + +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->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) { + return ESP_ERR_ESP_NETIF_INVALID_PARAMS; + } + 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) { + case ESP_NETIF_IP_REQUEST_RETRY_TIME: + 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); +#endif + default: + return ESP_ERR_ESP_NETIF_INVALID_PARAMS; + } + } 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) { + case ESP_NETIF_IP_REQUEST_RETRY_TIME: + 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); +#endif + default: + return ESP_ERR_ESP_NETIF_INVALID_PARAMS; + } + } else { + return ESP_ERR_ESP_NETIF_INVALID_PARAMS; + } + 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 *dhcp = netif_dhcp_data(esp_netif->lwip_netif); - if (dhcp == NULL || opt_val == NULL) { - return ESP_ERR_ESP_NETIF_INVALID_PARAMS; - } - 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) { - case ESP_NETIF_IP_REQUEST_RETRY_TIME: - 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); -#endif - default: - return ESP_ERR_ESP_NETIF_INVALID_PARAMS; - } - } 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) { - case ESP_NETIF_IP_REQUEST_RETRY_TIME: - 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); -#endif - default: - return ESP_ERR_ESP_NETIF_INVALID_PARAMS; - } - } else { - return ESP_ERR_ESP_NETIF_INVALID_PARAMS; - } - return ESP_OK; + 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) @@ -2206,6 +2306,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); @@ -2213,8 +2320,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 332a4f822d..05eb7aa0dc 100644 --- a/components/esp_netif/lwip/esp_netif_lwip_internal.h +++ b/components/esp_netif/lwip/esp_netif_lwip_internal.h @@ -21,7 +21,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/private_include/esp_netif_private.h b/components/esp_netif/private_include/esp_netif_private.h index f5355614c9..b7fcfa6ef1 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/lwip/Kconfig b/components/lwip/Kconfig index f4fe8634f1..f6a6487d6e 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 677574d200..ab30d89a62 100644 --- a/components/lwip/apps/sntp/sntp.c +++ b/components/lwip/apps/sntp/sntp.c @@ -1,27 +1,22 @@ -// 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-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include #include #include #include "esp_log.h" -#include "sntp.h" -#include "lwip/apps/sntp.h" +#include "esp_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; @@ -108,11 +103,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; @@ -132,3 +133,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 1a4f9db37f..d968befefc 100644 --- a/components/lwip/include/apps/esp_sntp.h +++ b/components/lwip/include/apps/esp_sntp.h @@ -10,7 +10,6 @@ #include "lwip/err.h" #include "lwip/apps/sntp.h" - #ifdef __cplusplus extern "C" { #endif @@ -38,6 +37,17 @@ 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 + /// SNTP time update mode typedef enum { SNTP_SYNC_MODE_IMMED, /*!< Update system time immediately when receiving a response from the SNTP server. */ @@ -51,6 +61,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 +159,60 @@ 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 */ + #ifdef __cplusplus } #endif diff --git a/components/lwip/include/apps/sntp/sntp.h b/components/lwip/include/apps/sntp/sntp.h index 616fd55460..50ba6b3843 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 +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ -// 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 __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/port/esp32/freertos/sys_arch.c b/components/lwip/port/esp32/freertos/sys_arch.c index 28228ff505..fa9c1ef0fa 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 b4fb53a834..1cec1e01b7 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 359263a207..28220ba75c 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 3d39e38015..21c757a6f0 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 @@ -846,11 +858,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. @@ -1199,11 +1207,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 81952aa5bb..ee235abe9f 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/docs/en/api-guides/lwip.rst b/docs/en/api-guides/lwip.rst index 89dcdc868f..71d86d207c 100644 --- a/docs/en/api-guides/lwip.rst +++ b/docs/en/api-guides/lwip.rst @@ -14,6 +14,11 @@ 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 diff --git a/docs/en/api-reference/system/system_time.rst b/docs/en/api-reference/system/system_time.rst index 3643e76dc8..d7f3e27c4e 100644 --- a/docs/en/api-reference/system/system_time.rst +++ b/docs/en/api-reference/system/system_time.rst @@ -122,9 +122,9 @@ To start synchronization via SNTP, just call the following three functions: .. code-block:: c - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_setservername(0, "pool.ntp.org"); - sntp_init(); + esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); + esp_sntp_setservername(0, "pool.ntp.org"); + esp_sntp_init(); 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. diff --git a/docs/zh_CN/api-reference/system/system_time.rst b/docs/zh_CN/api-reference/system/system_time.rst index 1d1a8c7e17..d2ef956931 100644 --- a/docs/zh_CN/api-reference/system/system_time.rst +++ b/docs/zh_CN/api-reference/system/system_time.rst @@ -122,9 +122,9 @@ lwIP SNTP 库提供了 API 函数,用于设置某个事件的回调函数。 .. code-block:: c - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_setservername(0, "pool.ntp.org"); - sntp_init(); + esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); + esp_sntp_setservername(0, "pool.ntp.org"); + esp_sntp_init(); 添加此初始化代码后,应用程序将定期同步时间。时间同步周期由 :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` 设置(默认为一小时)。如需修改,请在项目配置中设置 :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY`。 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 b7fd45bd7d..5a250f73bf 100644 --- a/examples/protocols/http2_request/main/http2_request_example_main.c +++ b/examples/protocols/http2_request/main/http2_request_example_main.c @@ -17,7 +17,7 @@ #include "freertos/task.h" #include "esp_wifi.h" #include "esp_event.h" -#include "lwip/apps/sntp.h" +#include "esp_sntp.h" #include "esp_system.h" #include "nvs_flash.h" #include "protocol_examples_common.h" @@ -90,8 +90,8 @@ static void set_time(void) settimeofday(&tv, &tz); /* Start SNTP service */ - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_init(); + esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); + esp_sntp_init(); } 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 653889617d..895acbc86d 100644 --- a/examples/protocols/https_request/main/time_sync.c +++ b/examples/protocols/https_request/main/time_sync.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,12 +33,12 @@ static const char *TAG = "time_sync"; void initialize_sntp(void) { ESP_LOGI(TAG, "Initializing SNTP"); - sntp_setoperatingmode(SNTP_OPMODE_POLL); - sntp_setservername(0, "pool.ntp.org"); + esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); + esp_sntp_setservername(0, "pool.ntp.org"); #ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH); #endif - sntp_init(); + esp_sntp_init(); } static void obtain_time(void) @@ -47,8 +47,8 @@ static void 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); +#if LWIP_DHCP_GET_NTP_SRV + esp_sntp_servermode_dhcp(1); #endif // wait for time to be set @@ -89,7 +89,7 @@ void fetch_and_store_time_in_nvs(void *args) } nvs_close(my_handle); - sntp_stop(); + esp_sntp_stop(); exit: if (err != ESP_OK) { diff --git a/examples/protocols/sntp/main/sntp_example_main.c b/examples/protocols/sntp/main/sntp_example_main.c index cada529e83..9730bfb9fe 100644 --- a/examples/protocols/sntp/main/sntp_example_main.c +++ b/examples/protocols/sntp/main/sntp_example_main.c @@ -135,8 +135,8 @@ static void obtain_time(void) * NOTE: This call should be made BEFORE esp aquires 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 +#if LWIP_DHCP_GET_NTP_SRV + esp_sntp_servermode_dhcp(1); // accept NTP offers from DHCP server, if any #endif /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. @@ -165,7 +165,7 @@ static void obtain_time(void) static void initialize_sntp(void) { ESP_LOGI(TAG, "Initializing SNTP"); - sntp_setoperatingmode(SNTP_OPMODE_POLL); + esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); /* * If 'NTP over DHCP' is enabled, we set dynamic pool address @@ -173,37 +173,37 @@ static void initialize_sntp(void) * provided via NTP over DHCP is not accessible */ #if LWIP_DHCP_GET_NTP_SRV && SNTP_MAX_SERVERS > 1 - sntp_setservername(1, "pool.ntp.org"); + esp_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); + esp_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); + esp_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) + esp_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_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)); + 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 = sntp_getserver(i); + 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); } diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 47a7d97fb7..00bcdc4fdc 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -459,7 +459,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 @@ -796,11 +795,9 @@ components/log/esp_log_private.h components/log/host_test/log_test/main/log_test.cpp components/log/log_linux.c components/lwip/apps/ping/ping.c -components/lwip/apps/sntp/sntp.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 From 25cbcd6a1c4ec225c60386e76d99a5d1d694bb52 Mon Sep 17 00:00:00 2001 From: Wang Zi Yan Date: Tue, 10 Jan 2023 12:13:59 +0800 Subject: [PATCH 2/5] docs: CN translation for system_time.rst (v5.0) --- docs/en/api-reference/system/system_time.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/api-reference/system/system_time.rst b/docs/en/api-reference/system/system_time.rst index d7f3e27c4e..587d19155a 100644 --- a/docs/en/api-reference/system/system_time.rst +++ b/docs/en/api-reference/system/system_time.rst @@ -41,9 +41,9 @@ The RTC timer has the following clock sources: - ``Internal {IDF_TARGET_RTC_CLK_FRE} RC oscillator`` (default): Features the lowest Deep-sleep current consumption and no dependence on any external components. However, the frequency stability of this clock source is affected by temperature fluctuations, so time may drift in both Deep-sleep and Light-sleep modes. :not esp32c2: - ``External 32 kHz crystal``: Requires a 32 kHz crystal to be connected to the {IDF_TARGET_EXT_CRYSTAL_PIN} pins. This source provides a better frequency stability at the expense of a slightly higher (by 1 μA) Deep-sleep current consumption. - + - ``External 32 kHz oscillator at {IDF_TARGET_EXT_OSC_PIN} pin``: Allows using 32 kHz clock generated by an external circuit. The external clock signal must be connected to the {IDF_TARGET_EXT_OSC_PIN} pin. The amplitude should be less than 1.2 V for sine wave signal and less than 1 V for square wave signal. Common mode voltage should be in the range of 0.1 < Vcm < 0.5xVamp, where Vamp stands for signal amplitude. In this case, the {IDF_TARGET_EXT_OSC_PIN} pin cannot be used as a GPIO pin. - + - ``Internal {IDF_TARGET_INT_OSC_FRE} oscillator, divided by 256 ({IDF_TARGET_INT_OSC_FRE_DIVIDED})``: Provides better frequency stability than the ``Internal {IDF_TARGET_RTC_CLK_FRE} RC oscillator`` at the expense of a higher (by 5 μA) Deep-sleep current consumption. It also does not require external components. The choice depends on your requirements for system time accuracy and power consumption in sleep modes. To modify the RTC clock source, set :ref:`CONFIG_RTC_CLK_SRC` in project configuration. From 42594bffe4460458ee4e54071512bac5ae03c107 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 25 Jan 2023 08:47:23 +0100 Subject: [PATCH 3/5] lwip/sntp: Fix esp_sntp_ API races (v5.0) Some of the esp_sntp_...() APIs that wrap lwip's SNTP module use tcpip_callback() to execute the lwip functionality in the correct state (either with locked TCP/IP core, or within the TCP/IP thread). tcpip_callback() however doesn't wait for completion of the callback, which doesn't prevent from using the stack variables after destroy if used as a parameter. Introduced in a71fa82. Fixed by using of tcpip_api_call() instead of the tcpip_callback(). Closes https://github.com/espressif/esp-idf/issues/10611 --- components/lwip/apps/sntp/sntp.c | 50 +++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/components/lwip/apps/sntp/sntp.c b/components/lwip/apps/sntp/sntp.c index ab30d89a62..354e2c19fb 100644 --- a/components/lwip/apps/sntp/sntp.c +++ b/components/lwip/apps/sntp/sntp.c @@ -10,13 +10,20 @@ #include #include "esp_log.h" #include "esp_sntp.h" -#include "lwip/tcpip.h" + +#include "lwip/priv/tcpip_priv.h" +#include "esp_macros.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"); +#define SNTP_ERROR(func, message) do { \ + err_t err = func; \ + LWIP_ERROR(message, err == ERR_OK, ); \ + } while (0) + 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; @@ -113,7 +120,7 @@ static void sntp_do_restart(void *ctx) bool sntp_restart(void) { if (sntp_enabled()) { - tcpip_callback(sntp_do_restart, NULL); + SNTP_ERROR(tcpip_callback(sntp_do_restart, NULL), "sntp_restart: tcpip_callback() failed"); return true; } return false; @@ -136,13 +143,13 @@ void sntp_get_system_time(uint32_t *sec, uint32_t *us) static void do_setoperatingmode(void *ctx) { - esp_sntp_operatingmode_t operating_mode = (esp_sntp_operatingmode_t)ctx; - sntp_setoperatingmode(operating_mode); + sntp_setoperatingmode((intptr_t)ctx); } void esp_sntp_setoperatingmode(esp_sntp_operatingmode_t operating_mode) { - tcpip_callback(do_setoperatingmode, (void*)operating_mode); + SNTP_ERROR(tcpip_callback(do_setoperatingmode, (void*)operating_mode), + "esp_sntp_setoperatingmode: tcpip_callback() failed"); } static void do_init(void *ctx) @@ -152,7 +159,7 @@ static void do_init(void *ctx) void esp_sntp_init(void) { - tcpip_callback(do_init, NULL); + SNTP_ERROR(tcpip_callback(do_init, NULL), "esp_sntp_init: tcpip_callback() failed"); } static void do_stop(void *ctx) @@ -162,47 +169,51 @@ static void do_stop(void *ctx) void esp_sntp_stop(void) { - tcpip_callback(do_stop, NULL); + SNTP_ERROR(tcpip_callback(do_stop, NULL), "esp_sntp_stop: tcpip_callback() failed"); } -struct do_setserver { +struct tcpip_setserver { + struct tcpip_api_call_data call; u8_t idx; const ip_addr_t *addr; }; -static void do_setserver(void *ctx) +static err_t do_setserver(struct tcpip_api_call_data *msg) { - struct do_setserver *params = ctx; + struct tcpip_setserver *params = __containerof(msg, struct tcpip_setserver, call); sntp_setserver(params->idx, params->addr); + return ERR_OK; } void esp_sntp_setserver(u8_t idx, const ip_addr_t *addr) { - struct do_setserver params = { + struct tcpip_setserver params = { .idx = idx, .addr = addr }; - tcpip_callback(do_setserver, ¶ms); + SNTP_ERROR(tcpip_api_call(do_setserver, ¶ms.call), "esp_sntp_setserver :tcpip_api_call() failed"); } -struct do_setservername { +struct tcpip_setservername { + struct tcpip_api_call_data call; u8_t idx; const char *server; }; -static void do_setservername(void *ctx) +static err_t do_setservername(struct tcpip_api_call_data *msg) { - struct do_setservername *params = ctx; + struct tcpip_setservername *params = __containerof(msg, struct tcpip_setservername, call); sntp_setservername(params->idx, params->server); + return ERR_OK; } void esp_sntp_setservername(u8_t idx, const char *server) { - struct do_setservername params = { + struct tcpip_setservername params = { .idx = idx, .server = server }; - tcpip_callback(do_setservername, ¶ms); + SNTP_ERROR(tcpip_api_call(do_setservername, ¶ms.call), "esp_sntp_setservername :tcpip_api_call() failed"); } const char *esp_sntp_getservername(u8_t idx) @@ -218,13 +229,12 @@ const ip_addr_t* esp_sntp_getserver(u8_t 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); + sntp_servermode_dhcp((intptr_t)ctx); } void esp_sntp_servermode_dhcp(bool enable) { - tcpip_callback(do_servermode_dhcp, (void*)enable); + SNTP_ERROR(tcpip_callback(do_servermode_dhcp, (void*)enable), "esp_sntp_servermode_dhcp: tcpip_callback() failed"); } #endif /* LWIP_DHCP_GET_NTP_SRV */ From 285362e8d6b01d15b960fa13b12296669f9c2d79 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 22 Feb 2023 15:47:12 +0100 Subject: [PATCH 4/5] lwip: Add missing esp_sntp_enabled() --- components/lwip/apps/sntp/sntp.c | 5 +++++ components/lwip/include/apps/esp_sntp.h | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/components/lwip/apps/sntp/sntp.c b/components/lwip/apps/sntp/sntp.c index 354e2c19fb..1240115ecd 100644 --- a/components/lwip/apps/sntp/sntp.c +++ b/components/lwip/apps/sntp/sntp.c @@ -238,3 +238,8 @@ void esp_sntp_servermode_dhcp(bool enable) } #endif /* LWIP_DHCP_GET_NTP_SRV */ + +bool esp_sntp_enabled(void) +{ + return sntp_enabled(); +} diff --git a/components/lwip/include/apps/esp_sntp.h b/components/lwip/include/apps/esp_sntp.h index d968befefc..801e9f351a 100644 --- a/components/lwip/include/apps/esp_sntp.h +++ b/components/lwip/include/apps/esp_sntp.h @@ -205,6 +205,12 @@ const char *esp_sntp_getservername(u8_t idx); */ const ip_addr_t* esp_sntp_getserver(u8_t idx); +/** + * @brief Checks if sntp is enabled + * @return true if sntp module is enabled + */ +bool esp_sntp_enabled(void); + #if LWIP_DHCP_GET_NTP_SRV /** * @brief Enable acquiring SNTP server from DHCP From a18d019fc9be035baa5737b4e394722b1883b4f5 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 13 Mar 2023 19:09:21 +0100 Subject: [PATCH 5/5] lwip: Fix lwiopts macro expansion and dhcps-test Minor issue in lwipopts.h in macro expansion in parameters (cosmetic change: it expands correctly but doesn't pass the expected argument) Fix lwip thread safety issue in tests: dhcp server should be started and stopped only in lwip context/thread. Without this fix, the test would fail if `CONFIG_LWIP_CHECK_THREAD_SAFETY=y` Adds CONFIG_LWIP_TCPIP_CORE_LOCKING=y to some mqtt example tests (the same configs as used in v5.1) --- components/lwip/port/esp32/include/lwipopts.h | 4 +- components/lwip/test/test_lwip_apps.c | 96 +++++++++++-------- 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 + 6 files changed, 64 insertions(+), 42 deletions(-) diff --git a/components/lwip/port/esp32/include/lwipopts.h b/components/lwip/port/esp32/include/lwipopts.h index 21c757a6f0..cd6ab9ab00 100644 --- a/components/lwip/port/esp32/include/lwipopts.h +++ b/components/lwip/port/esp32/include/lwipopts.h @@ -1208,9 +1208,9 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min) #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) +#define LWIP_DONE_SOCK(sock) done_socket(sock) #else -#define LWIP_DONE_SOCK(s) ((void)1) +#define LWIP_DONE_SOCK(sock) ((void)1) #endif /* LWIP_NETCONN_FULLDUPLEX */ #define LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, err) \ diff --git a/components/lwip/test/test_lwip_apps.c b/components/lwip/test/test_lwip_apps.c index ec00247eeb..1b2bec278c 100644 --- a/components/lwip/test/test_lwip_apps.c +++ b/components/lwip/test/test_lwip_apps.c @@ -10,6 +10,7 @@ #include "lwip/inet.h" #include "lwip/netdb.h" #include "lwip/sockets.h" +#include "lwip/tcpip.h" #include "ping/ping_sock.h" #include "dhcpserver/dhcpserver.h" #include "dhcpserver/dhcpserver_options.h" @@ -125,12 +126,18 @@ TEST_CASE("dhcp server init/deinit", "[lwip][leaks=0]") dhcps_delete(dhcps); } -TEST_CASE("dhcp server start/stop on localhost", "[lwip]") -{ - test_case_uses_tcpip(); - struct netif *netif; - dhcps_t *dhcps; +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) +{ + struct netif *netif; + struct dhcps_api *api = ctx; NETIF_FOREACH(netif) { if (netif->name[0] == 'l' && netif->name[1] == 'o') { @@ -139,40 +146,49 @@ TEST_CASE("dhcp server start/stop on localhost", "[lwip]") } 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_delete(dhcps); - - //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); - - //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); - - // Class A: IP: 127.0.0.1, with inaccurate Mask: 255.248.255.0 - // expect dhcps_start() to fail - dhcps = dhcps_new(); - IP4_ADDR(&netmask, 255,248,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_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); +} + +static void dhcps_test_net_classes(uint32_t ip, uint32_t mask, bool pass) +{ + + 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_CASE("dhcp server start/stop on localhost", "[lwip]") +{ + 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 inaccurate Mask: 255.248.255.0 + // expect dhcps_start() to fail + dhcps_test_net_classes(0x7f000001, 0xFFF8FF00, false); } diff --git a/examples/protocols/mqtt/ssl/sdkconfig.ci b/examples/protocols/mqtt/ssl/sdkconfig.ci index 3271d9678e..e8d4a52f63 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 28ce9ac93d..acf084a9e4 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 2f8e425e46..eebcafdead 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 f355614e4f..c8e8ef94a4 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