fix(lwip): Use ACD light module for simple DHCP-ARP check

This commit is contained in:
David Cermak 2024-05-24 16:45:38 +02:00
parent 720b74026c
commit c098388a2f
4 changed files with 178 additions and 8 deletions

View File

@ -57,7 +57,6 @@ if(CONFIG_LWIP_ENABLE)
"lwip/src/core/ipv4/ip4_napt.c"
"lwip/src/core/ipv4/ip4_addr.c"
"lwip/src/core/ipv4/ip4_frag.c"
"lwip/src/core/ipv4/acd.c"
"lwip/src/core/ipv6/dhcp6.c"
"lwip/src/core/ipv6/ethip6.c"
"lwip/src/core/ipv6/icmp6.c"
@ -136,6 +135,12 @@ if(CONFIG_LWIP_ENABLE)
"lwip/src/netif/ppp/vj.c")
endif()
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)

View File

@ -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"

View File

@ -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 */

View File

@ -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
/**