From 04ea82474047bd51a72bea4fd9811a69b58ffa02 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Thu, 20 Oct 2022 17:28:28 +0800 Subject: [PATCH] fix(lwip): Modify the DHCP offer and DHCP ack from broadcast to unicast --- components/lwip/Kconfig | 8 ++ components/lwip/apps/dhcpserver/dhcpserver.c | 114 +++++++++++++++---- components/lwip/port/include/lwipopts.h | 6 + 3 files changed, 105 insertions(+), 23 deletions(-) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index cb8f86bd4b..dc8e3cf621 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -387,6 +387,14 @@ menu "LWIP" After this number is exceeded, DHCP server removes of the oldest device from it's address pool, without notification. + config LWIP_DHCPS_STATIC_ENTRIES + bool "Enable ARP static entries" + default y + depends on LWIP_DHCPS + help + Enabling this option allows DHCP server to support temporary static ARP entries + for DHCP Client. This will help the DHCP server to send the DHCP OFFER and DHCP ACK using IP unicast. + endmenu # DHCPS menuconfig LWIP_AUTOIP diff --git a/components/lwip/apps/dhcpserver/dhcpserver.c b/components/lwip/apps/dhcpserver/dhcpserver.c index 349c33e391..112bdf070b 100644 --- a/components/lwip/apps/dhcpserver/dhcpserver.c +++ b/components/lwip/apps/dhcpserver/dhcpserver.c @@ -13,6 +13,8 @@ #include "lwip/mem.h" #include "lwip/ip_addr.h" #include "lwip/timeouts.h" +#include "lwip/etharp.h" +#include "lwip/prot/ethernet.h" #include "dhcpserver/dhcpserver.h" #include "dhcpserver/dhcpserver_options.h" @@ -28,6 +30,7 @@ #endif #define BOOTP_BROADCAST 0x8000 +#define BROADCAST_BIT_IS_SET(flag) (flag & BOOTP_BROADCAST) #define DHCP_REQUEST 1 #define DHCP_REPLY 2 @@ -508,35 +511,67 @@ static void create_msg(dhcps_t *dhcps, struct dhcps_msg *m) client.addr = *((uint32_t *) &dhcps->client_address); m->op = DHCP_REPLY; - m->htype = DHCP_HTYPE_ETHERNET; - m->hlen = 6; - m->hops = 0; -// os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid)); - m->secs = 0; +#if !ETHARP_SUPPORT_STATIC_ENTRIES + /* If the DHCP server does not support sending unicast message to the client, + * need to set the 'flags' field to broadcast */ m->flags = htons(BOOTP_BROADCAST); +#endif memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr)); - - memset((char *) m->ciaddr, 0, sizeof(m->ciaddr)); - - memset((char *) m->siaddr, 0, sizeof(m->siaddr)); - - memset((char *) m->giaddr, 0, sizeof(m->giaddr)); - - memset((char *) m->sname, 0, sizeof(m->sname)); - - memset((char *) m->file, 0, sizeof(m->file)); - - memset((char *) m->options, 0, sizeof(m->options)); - - u32_t magic_cookie_temp = magic_cookie; - - memcpy((char *) m->options, &magic_cookie_temp, sizeof(magic_cookie_temp)); + memcpy((char *) m->options, &magic_cookie, sizeof(magic_cookie)); } +/****************************************************************************** + * FunctionName : dhcps_response_ip_set + * Description : set the ip address for sending to the DHCP client + * Parameters : m -- DHCP message info + * ip4_out -- ip address for sending + * Returns : none +*******************************************************************************/ +static void dhcps_response_ip_set(dhcps_t *dhcps, struct dhcps_msg *m, ip4_addr_t *ip4_out) +{ +#if ETHARP_SUPPORT_STATIC_ENTRIES + ip4_addr_t ip4_giaddr; + ip4_addr_t ip4_ciaddr; + ip4_addr_t ip4_yiaddr; + + struct eth_addr chaddr; + memcpy(chaddr.addr, m->chaddr, sizeof(chaddr.addr)); + memcpy((char *)&ip4_giaddr.addr, (char *)m->giaddr, sizeof(m->giaddr)); + memcpy((char *)&ip4_ciaddr.addr, (char *)m->ciaddr, sizeof(m->ciaddr)); + memcpy((char *)&ip4_yiaddr.addr, (char *)m->yiaddr, sizeof(m->yiaddr)); + + if (!ip4_addr_isany_val(ip4_giaddr)) { + /* If the 'giaddr' field is non-zero, send return message to the address in 'giaddr'. (RFC 2131)*/ + ip4_addr_set(ip4_out, &ip4_giaddr); + /* add the IP<->MAC as static entry into the arp table. */ + etharp_add_static_entry(&ip4_giaddr, &chaddr); + } else { + if (!ip4_addr_isany_val(ip4_ciaddr)) { + /* If the 'giaddr' field is zero and the 'ciaddr' is nonzero, + * the server unicasts DHCPOFFER and DHCPACK message to the address in 'ciaddr'*/ + ip4_addr_set(ip4_out, &ip4_ciaddr); + etharp_add_static_entry(&ip4_ciaddr, &chaddr); + } else if (!BROADCAST_BIT_IS_SET(htons(m->flags))) { + /* If the 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is not set, + * the server unicasts DHCPOFFER and DHCPACK message to the client's hardware address and + * 'yiaddr' address. */ + ip4_addr_set(ip4_out, &ip4_yiaddr); + etharp_add_static_entry(&ip4_yiaddr, &chaddr); + } else { + /* The server broadcast DHCPOFFER and DHCPACK message to 0xffffffff*/ + ip4_addr_set(ip4_out, &dhcps->broadcast_dhcps); + } + } +#else + ip4_addr_set(ip4_out, &dhcps->broadcast_dhcps); +#endif +} + + struct pbuf * dhcps_pbuf_alloc(u16_t len) { u16_t mlen = sizeof(struct dhcps_msg); @@ -614,7 +649,7 @@ static void send_offer(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) } ip_addr_t ip_temp = IPADDR4_INIT(0x0); - ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps); + dhcps_response_ip_set(dhcps, m, ip_2_ip4(&ip_temp)); #if DHCPS_DEBUG SendOffer_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n", SendOffer_err_t); @@ -622,6 +657,11 @@ static void send_offer(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); #endif +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* remove the IP<->MAC from the arp table. */ + etharp_remove_static_entry(ip_2_ip4(&ip_temp)); +#endif + if (p->ref != 0) { #if DHCPS_DEBUG DHCPS_LOG("udhcp: send_offer>>free pbuf\n"); @@ -692,7 +732,25 @@ static void send_nak(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) } ip_addr_t ip_temp = IPADDR4_INIT(0x0); + +#if ETHARP_SUPPORT_STATIC_ENTRIES + ip4_addr_t ip4_giaddr; + struct eth_addr chaddr; + memcpy(chaddr.addr, m->chaddr, sizeof(chaddr.addr)); + memcpy((char *)&ip4_giaddr.addr, (char *)m->giaddr, sizeof(m->giaddr)); + + if (!ip4_addr_isany_val(ip4_giaddr)) { + ip4_addr_set(ip_2_ip4(&ip_temp), &ip4_giaddr); + /* add the IP<->MAC as static entry into the arp table. */ + etharp_add_static_entry(&ip4_giaddr, &chaddr); + } else { + /* when 'giaddr' is zero, the server broadcasts any DHCPNAK message to 0xffffffff. (RFC 2131)*/ + ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps); + } +#else ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps); +#endif + #if DHCPS_DEBUG SendNak_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); DHCPS_LOG("dhcps: send_nak>>udp_sendto result %x\n", SendNak_err_t); @@ -700,6 +758,11 @@ static void send_nak(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); #endif +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* remove the IP<->MAC from the arp table. */ + etharp_remove_static_entry(ip_2_ip4(&ip_temp)); +#endif + if (p->ref != 0) { #if DHCPS_DEBUG DHCPS_LOG("udhcp: send_nak>>free pbuf\n"); @@ -769,12 +832,17 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) } ip_addr_t ip_temp = IPADDR4_INIT(0x0); - ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps); + dhcps_response_ip_set(dhcps, m, ip_2_ip4(&ip_temp)); SendAck_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT); #if DHCPS_DEBUG DHCPS_LOG("dhcps: send_ack>>udp_sendto result %x\n", SendAck_err_t); #endif +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* remove the IP<->MAC from the arp table. */ + etharp_remove_static_entry(ip_2_ip4(&ip_temp)); +#endif + if (SendAck_err_t == ERR_OK) { dhcps->dhcps_cb(dhcps->dhcps_cb_arg, m->yiaddr, m->chaddr); } diff --git a/components/lwip/port/include/lwipopts.h b/components/lwip/port/include/lwipopts.h index 183b7be80a..12615a7c73 100644 --- a/components/lwip/port/include/lwipopts.h +++ b/components/lwip/port/include/lwipopts.h @@ -162,6 +162,12 @@ extern "C" { */ #define ARP_QUEUEING 1 +#ifdef CONFIG_LWIP_DHCPS_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 1 +#else +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + /* -------------------------------- ---------- IP options ----------