Просмотр исходного кода

fix(lwip): Modify the DHCP offer and DHCP ack from broadcast to unicast

zhangyanjiao 3 лет назад
Родитель
Сommit
04ea824740

+ 8 - 0
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

+ 90 - 22
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));
+    memcpy((char *) m->options, &magic_cookie, sizeof(magic_cookie));
+}
 
-    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));
+/******************************************************************************
+ * 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);
     }

+ 6 - 0
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 ----------