diff --git a/components/esp_netif/lwip/esp_netif_lwip.c b/components/esp_netif/lwip/esp_netif_lwip.c index bd7eb48298..8387e361b8 100644 --- a/components/esp_netif/lwip/esp_netif_lwip.c +++ b/components/esp_netif/lwip/esp_netif_lwip.c @@ -1153,26 +1153,14 @@ static esp_err_t esp_netif_start_api(esp_netif_api_msg_t *msg) return ESP_OK; #else LOG_NETIF_DISABLED_AND_DO("DHCP Server", return ESP_ERR_NOT_SUPPORTED); -#endif - } else if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) { -#if CONFIG_LWIP_IPV4 - if (esp_netif->dhcpc_status != ESP_NETIF_DHCP_STARTED) { - if (p_netif != NULL) { - struct dhcp *dhcp_data = NULL; - dhcp_data = netif_dhcp_data(p_netif); - if (dhcp_data == NULL) { - dhcp_data = (struct dhcp *)malloc(sizeof(struct dhcp)); - if (dhcp_data == NULL) { - return ESP_ERR_NO_MEM; - } - dhcp_set_struct(p_netif, dhcp_data); - } - } - } -#else - LOG_NETIF_DISABLED_AND_DO("IPv4's DHCP Client", return ESP_ERR_NOT_SUPPORTED); #endif } +#ifndef CONFIG_LWIP_IPV4 + else if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) { + LOG_NETIF_DISABLED_AND_DO("IPv4's DHCP Client", return ESP_ERR_NOT_SUPPORTED); + } +#endif + // For netifs with (active) DHCP client: we update the default netif after getting a valid IP if (!((esp_netif->flags & ESP_NETIF_DHCP_CLIENT) && esp_netif->dhcpc_status != ESP_NETIF_DHCP_STOPPED)) { esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED); diff --git a/components/esp_netif/lwip/esp_netif_lwip_ppp.c b/components/esp_netif/lwip/esp_netif_lwip_ppp.c index 26e90560e4..41a6ec9cc5 100644 --- a/components/esp_netif/lwip/esp_netif_lwip_ppp.c +++ b/components/esp_netif/lwip/esp_netif_lwip_ppp.c @@ -175,9 +175,9 @@ static void on_ppp_notify_phase(ppp_pcb *pcb, u8_t phase, void *ctx) * * @return uint32_t Length of data successfully sent */ -static uint32_t pppos_low_level_output(ppp_pcb *pcb, uint8_t *data, uint32_t len, void *netif) +static uint32_t pppos_low_level_output(ppp_pcb *pcb, const void *data, uint32_t len, void *netif) { - esp_err_t ret = esp_netif_transmit(netif, data, len); + esp_err_t ret = esp_netif_transmit(netif, (void*)data, len); if (ret == ESP_OK) { return len; } diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 8c55884277..5108e5cca3 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -135,7 +135,13 @@ if(CONFIG_LWIP_ENABLE) "lwip/src/netif/ppp/vj.c") endif() - if(NOT ${target} STREQUAL "linux") + if(CONFIG_LWIP_DHCP_DOES_ARP_CHECK) + list(APPEND srcs "port/acd_dhcp_check.c") + elseif(CONFIG_LWIP_DHCP_DOES_ACD_CHECK) + list(APPEND srcs "lwip/src/core/ipv4/acd.c") + endif() + +if(NOT ${target} STREQUAL "linux") # Support for vfs and linker fragments only for target builds set(linker_fragments linker.lf) if(CONFIG_VFS_SUPPORT_IO) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 4b1cbd1676..4519ac99bd 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -318,13 +318,29 @@ menu "LWIP" Set TCPIP task receive mail box size. Generally bigger value means higher throughput but more memory. The value should be bigger than UDP/TCP mail box size. - config LWIP_DHCP_DOES_ARP_CHECK - bool "DHCP: Perform ARP check on any offered address" - default y + choice LWIP_DHCP_CHECKS_OFFERED_ADDRESS + prompt "Choose how DHCP validates offered IP" + default LWIP_DHCP_DOES_ARP_CHECK depends on LWIP_IPV4 help - Enabling this option performs a check (via ARP request) if the offered IP address - is not already in use by another host on the network. + Choose the preferred way of DHCP client to check if the offered address + is available: + * Using Address Conflict Detection (ACD) module assures that the offered IP address + is properly probed and announced before binding in DHCP. This conforms to RFC5227, + but takes several seconds. + * Using ARP check, we only send two ARP requests to check for replies. This process + lasts 1 - 2 seconds. + * No conflict detection: We directly bind the offered address. + + config LWIP_DHCP_DOES_ARP_CHECK + bool "DHCP provides simple ARP check" + depends on !LWIP_AUTOIP + config LWIP_DHCP_DOES_ACD_CHECK + bool "DHCP provides Address Conflict Detection (ACD)" + config LWIP_DHCP_DOES_NOT_CHECK_OFFERED_IP + bool "DHCP does not detect conflict on the offered IP" + + endchoice config LWIP_DHCP_DISABLE_CLIENT_ID bool "DHCP: Disable Use of HW address as client identification" diff --git a/components/lwip/linker.lf b/components/lwip/linker.lf index 97e60e2d69..53f564cf84 100644 --- a/components/lwip/linker.lf +++ b/components/lwip/linker.lf @@ -112,7 +112,7 @@ entries: tcp_out:tcp_rexmit_rto_prepare (noflash_text) tcp_out:tcp_rexmit (noflash_text) tcp_out:tcp_rexmit_fast (noflash_text) - tcp_out:tcp_output_control_segment (noflash_text) + tcp_out:tcp_output_control_segment_netif (noflash_text) tcp_out:tcp_rst (noflash_text) tcp_out:tcp_send_empty_ack (noflash_text) sys_arch:sys_arch_protect (noflash_text) diff --git a/components/lwip/lwip b/components/lwip/lwip index 0606eed9d8..f150e2321a 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit 0606eed9d8b98a797514fdf6eabb4daf1c8c8cd9 +Subproject commit f150e2321ac09bb0fd35a7fcbc1b116fbf93434e diff --git a/components/lwip/port/acd_dhcp_check.c b/components/lwip/port/acd_dhcp_check.c new file mode 100644 index 0000000000..e29ff984c5 --- /dev/null +++ b/components/lwip/port/acd_dhcp_check.c @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "lwip/opt.h" + +/* don't build if not configured for use in lwipopts.h */ +#if LWIP_IPV4 && DHCP_DOES_ARP_CHECK + +#include "lwip/acd.h" +#include "lwip/dhcp.h" +#include "lwip/prot/dhcp.h" +#include "lwip/timeouts.h" + +#define ACD_DHCP_ARP_REPLY_TIMEOUT_MS 500 + +static void +acd_dhcp_check_timeout_cb(void *arg); + +static void +acd_suspend(struct netif *netif) +{ + struct dhcp *dhcp; + struct acd *acd; + if (netif == NULL || (dhcp = netif_dhcp_data(netif)) == NULL) { + return; + } + acd = &dhcp->acd; + acd->state = ACD_STATE_OFF; + sys_untimeout(acd_dhcp_check_timeout_cb, (void *)netif); +} + +void +acd_remove(struct netif *netif, struct acd *acd) +{ + acd_suspend(netif); + acd->acd_conflict_callback = NULL; +} + +void +acd_netif_ip_addr_changed(struct netif *netif, const ip_addr_t *old_addr, + const ip_addr_t *new_addr) +{ + acd_suspend(netif); +} + +void +acd_network_changed_link_down(struct netif *netif) +{ + acd_suspend(netif); +} + +void +acd_arp_reply(struct netif *netif, struct etharp_hdr *hdr) +{ + struct dhcp *dhcp; + ip4_addr_t sipaddr; + struct eth_addr netifaddr; + struct acd *acd; + if (netif == NULL || (dhcp = netif_dhcp_data(netif)) == NULL) { + return; + } + acd = &dhcp->acd; + // Check that we're looking for ARP reply in ACD_PROBING state and DHCP_CHECKING state + if (hdr->opcode != PP_HTONS(ARP_REPLY) || dhcp->state != DHCP_STATE_CHECKING || + acd->state != ACD_STATE_PROBING || acd->acd_conflict_callback == NULL) { + return; + } + SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN); + IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", + ip4_addr_get_u32(&sipaddr))); + /* did another host (not our mac addr) respond with the address we were offered by the DHCP server? */ + if (ip4_addr_eq(&sipaddr, &dhcp->offered_ip_addr) && + !eth_addr_eq(&netifaddr, &hdr->shwaddr)) { + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, + ("acd_arp_reply(): arp reply matched with offered address, declining\n")); + dhcp->acd.acd_conflict_callback(netif, ACD_DECLINE); + } +} + +err_t +acd_add(struct netif *netif, struct acd *acd, + acd_conflict_callback_t acd_conflict_callback) +{ + acd->acd_conflict_callback = acd_conflict_callback; + return ERR_OK; +} + +static void send_probe_once(struct netif *netif) +{ + struct dhcp *dhcp = netif_dhcp_data(netif); + if (etharp_query(netif, &dhcp->offered_ip_addr, NULL) != ERR_OK) { + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("acd_send_probe_once(): could not perform ARP query\n")); + return; + } + if (dhcp->tries < 255) { + dhcp->tries++; + } + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_send_probe_once(): set request timeout %"U16_F" msecs\n", ACD_DHCP_ARP_REPLY_TIMEOUT_MS)); + sys_timeout(ACD_DHCP_ARP_REPLY_TIMEOUT_MS, acd_dhcp_check_timeout_cb, (void *)netif); +} + +static void +acd_dhcp_check_timeout_cb(void *arg) +{ + struct netif *netif = (struct netif *)arg; + struct dhcp *dhcp; + struct acd *acd; + if (netif == NULL || (dhcp = netif_dhcp_data(netif)) == NULL) { + return; + } + acd = &dhcp->acd; + if (acd->state != ACD_STATE_PROBING || acd->acd_conflict_callback == NULL || dhcp->state != DHCP_STATE_CHECKING) { + return; + } + LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_dhcp_check_timeout_cb(): CHECKING, ARP request timed out\n")); + if (dhcp->tries <= 1) { + send_probe_once(netif); + } else { + // No conflict detected + dhcp->acd.acd_conflict_callback(netif, ACD_IP_OK); + } +} + +err_t +acd_start(struct netif *netif, struct acd *acd, ip4_addr_t ipaddr) +{ + if (netif == NULL || netif_dhcp_data(netif) == NULL) { + return ERR_ARG; + } + acd->state = ACD_STATE_PROBING; + send_probe_once(netif); + return ERR_OK; +} + +#endif /* LWIP_IPV4 && DHCP_DOES_ARP_CHECK */ diff --git a/components/lwip/port/include/lwipopts.h b/components/lwip/port/include/lwipopts.h index b58214c373..15e2c4267b 100644 --- a/components/lwip/port/include/lwipopts.h +++ b/components/lwip/port/include/lwipopts.h @@ -308,12 +308,23 @@ extern "C" { #define LWIP_DHCP 1 /** - * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + * LWIP_DHCP_CHECKS_OFFERED_ADDRESS: + * - Using Address Conflict Detection (ACD) module assures that the offered IP address + * is properly probed and announced before binding in DHCP. This conforms to RFC5227, + * but takes several seconds. + * - Using ARP check, we only send two ARP requests to check for replies. This process + * lasts 1 - 2 seconds. + * - No conflict detection: We directly bind the offered address. */ #ifdef CONFIG_LWIP_DHCP_DOES_ARP_CHECK #define DHCP_DOES_ARP_CHECK 1 +#define LWIP_DHCP_DOES_ACD_CHECK 1 +#elif CONFIG_LWIP_DHCP_DOES_ACD_CHECK +#define DHCP_DOES_ARP_CHECK 0 +#define LWIP_DHCP_DOES_ACD_CHECK 1 #else #define DHCP_DOES_ARP_CHECK 0 +#define LWIP_DHCP_DOES_ACD_CHECK 0 #endif /** @@ -381,7 +392,7 @@ extern "C" { /* Since for embedded devices it's not that hard to miss a discover packet, so lower * the discover and request retry backoff time from (2,4,8,16,32,60,60)s to (500m,1,2,4,4,4,4)s. */ -#define DHCP_REQUEST_TIMEOUT_SEQUENCE(tries) ((uint16_t)(((tries) < 5 ? 1 << (tries) : 16) * 250)) +#define DHCP_REQUEST_BACKOFF_SEQUENCE(state, tries) ((uint16_t)(((tries) < 5 ? 1 << (tries) : 16) * 250)) static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min) { @@ -393,12 +404,12 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min) return timeout; } -#define DHCP_CALC_TIMEOUT_FROM_OFFERED_T0_LEASE(dhcp) \ - timeout_from_offered((dhcp)->offered_t0_lease, 120) -#define DHCP_CALC_TIMEOUT_FROM_OFFERED_T1_RENEW(dhcp) \ - timeout_from_offered((dhcp)->offered_t1_renew, (dhcp)->t0_timeout>>1 /* 50% */ ) -#define DHCP_CALC_TIMEOUT_FROM_OFFERED_T2_REBIND(dhcp) \ - timeout_from_offered((dhcp)->offered_t2_rebind, ((dhcp)->t0_timeout/8)*7 /* 87.5% */ ) +#define DHCP_SET_TIMEOUT_FROM_OFFERED_T0_LEASE(tout, dhcp) do { \ + (tout) = timeout_from_offered((dhcp)->offered_t0_lease, 120); } while(0) +#define DHCP_SET_TIMEOUT_FROM_OFFERED_T1_RENEW(tout, dhcp) do { \ + (tout) = timeout_from_offered((dhcp)->offered_t1_renew, (dhcp)->t0_timeout>>1 /* 50% */ ); } while(0) +#define DHCP_SET_TIMEOUT_FROM_OFFERED_T2_REBIND(tout, dhcp) do { \ + (tout) = timeout_from_offered((dhcp)->offered_t2_rebind, ((dhcp)->t0_timeout/8)*7 /* 87.5% */ ); } while(0) #define LWIP_HOOK_DHCP_PARSE_OPTION(netif, dhcp, state, msg, msg_type, option, len, pbuf, offset) \ do { LWIP_UNUSED_ARG(msg); \ @@ -692,8 +703,12 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min) /** * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname * field. + * LWIP_DHCP_DISCOVER_ADD_HOSTNAME==1: include hostname opt in discover packets. + * If the hostname is not set in the DISCOVER packet, then some servers might issue + * an OFFER with hostname configured and consequently reject the REQUEST with any other hostname. */ #define LWIP_NETIF_HOSTNAME 1 +#define LWIP_DHCP_DISCOVER_ADD_HOSTNAME 1 /** * LWIP_NETIF_API==1: Support netif api (in netifapi.c) diff --git a/components/lwip/port/include/netinet/in.h b/components/lwip/port/include/netinet/in.h index e8f01bf918..2a30cfe781 100644 --- a/components/lwip/port/include/netinet/in.h +++ b/components/lwip/port/include/netinet/in.h @@ -9,6 +9,4 @@ #include "lwip/inet.h" -#define IN6_IS_ADDR_MULTICAST(a) IN_MULTICAST(a) - #endif /* IN_H_ */ diff --git a/components/openthread/lib b/components/openthread/lib index b1d2a662b8..56af58057c 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit b1d2a662b872a73f6de3c581fc3c2c7aaa01ad83 +Subproject commit 56af58057c259405aa90c478e294f6216cc2f6db diff --git a/tools/ci/check_public_headers_exceptions.txt b/tools/ci/check_public_headers_exceptions.txt index 397518950e..84b0202179 100644 --- a/tools/ci/check_public_headers_exceptions.txt +++ b/tools/ci/check_public_headers_exceptions.txt @@ -24,6 +24,8 @@ components/lwip/lwip/src/include/lwip/priv/memp_std.h components/lwip/include/lwip/sockets.h components/lwip/lwip/src/include/lwip/prot/nd6.h components/lwip/lwip/src/include/netif/ppp/ +components/lwip/lwip/src/include/lwip/apps/tftp_server.h +components/lwip/lwip/src/include/lwip/apps/tftp_client.h components/spi_flash/include/spi_flash_chip_issi.h components/spi_flash/include/spi_flash_chip_mxic.h