mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-11 17:52:00 +03:00
feat(lwip): dhcp server add support for dhcp inform
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "lwip/dhcp.h"
|
||||
#include "lwip/err.h"
|
||||
@@ -48,6 +49,7 @@
|
||||
#define DHCPACK 5
|
||||
#define DHCPNAK 6
|
||||
#define DHCPRELEASE 7
|
||||
#define DHCPINFORM 8
|
||||
|
||||
#define DHCP_OPTION_PAD 0
|
||||
#define DHCP_OPTION_SUBNET_MASK 1
|
||||
@@ -100,6 +102,7 @@
|
||||
#define DHCPS_STATE_NAK 4
|
||||
#define DHCPS_STATE_IDLE 5
|
||||
#define DHCPS_STATE_RELEASE 6
|
||||
#define DHCPS_STATE_INFORM_ACK 7
|
||||
|
||||
typedef enum {
|
||||
DHCPS_HANDLE_CREATED = 0,
|
||||
@@ -416,7 +419,7 @@ static u8_t *add_msg_type(u8_t *optptr, u8_t type)
|
||||
* Parameters : optptr -- the addr of DHCP message option
|
||||
* Returns : the addr of DHCP message option
|
||||
*******************************************************************************/
|
||||
static u8_t *add_offer_options(dhcps_t *dhcps, u8_t *optptr)
|
||||
static u8_t *add_offer_options(dhcps_t *dhcps, u8_t *optptr, bool include_lease_time)
|
||||
{
|
||||
ip4_addr_t ipadd;
|
||||
|
||||
@@ -426,12 +429,14 @@ static u8_t *add_offer_options(dhcps_t *dhcps, u8_t *optptr)
|
||||
*optptr++ = 4;
|
||||
optptr = dhcps_option_ip(optptr, &dhcps->dhcps_mask);
|
||||
|
||||
*optptr++ = DHCP_OPTION_LEASE_TIME;
|
||||
*optptr++ = 4;
|
||||
*optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 24) & 0xFF;
|
||||
*optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 16) & 0xFF;
|
||||
*optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 8) & 0xFF;
|
||||
*optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 0) & 0xFF;
|
||||
if (include_lease_time) {
|
||||
*optptr++ = DHCP_OPTION_LEASE_TIME;
|
||||
*optptr++ = 4;
|
||||
*optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 24) & 0xFF;
|
||||
*optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 16) & 0xFF;
|
||||
*optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 8) & 0xFF;
|
||||
*optptr++ = ((dhcps->dhcps_lease_time * DHCPS_LEASE_UNIT) >> 0) & 0xFF;
|
||||
}
|
||||
|
||||
*optptr++ = DHCP_OPTION_SERVER_ID;
|
||||
*optptr++ = 4;
|
||||
@@ -512,6 +517,44 @@ static u8_t *add_end(u8_t *optptr)
|
||||
return optptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read DHCP message type (option 53) from the variable-length option area
|
||||
* (starts after the magic cookie at options[4]).
|
||||
*/
|
||||
static u8_t dhcps_get_option_msg_type(u8_t *optptr, u16_t len)
|
||||
{
|
||||
u8_t *end;
|
||||
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
end = optptr + len;
|
||||
|
||||
while (optptr < end) {
|
||||
u8_t code = *optptr;
|
||||
if (code == DHCP_OPTION_END) {
|
||||
break;
|
||||
}
|
||||
if (code == 0) {
|
||||
/* Pad */
|
||||
optptr++;
|
||||
continue;
|
||||
}
|
||||
if (optptr + 1 >= end) {
|
||||
break;
|
||||
}
|
||||
u8_t optlen = optptr[1];
|
||||
if ((optptr + 2 + optlen) > end) {
|
||||
break;
|
||||
}
|
||||
if (code == DHCP_OPTION_MSG_TYPE && optlen >= 1) {
|
||||
return optptr[2];
|
||||
}
|
||||
optptr += (u16_t)optlen + 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : create_msg
|
||||
* Description : create response message
|
||||
@@ -569,7 +612,11 @@ static void dhcps_response_ip_set(dhcps_t *dhcps, struct dhcps_msg *m, ip4_addr_
|
||||
/* 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);
|
||||
/* when 'yiaddr' is zero, means DHCPACK INFO, no need to add static entry */
|
||||
if (!ip4_addr_isany_val(ip4_yiaddr)) {
|
||||
/* add the IP<->MAC as static entry into the arp table. */
|
||||
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
|
||||
@@ -620,7 +667,7 @@ static void send_offer(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
|
||||
create_msg(dhcps, m);
|
||||
|
||||
end = add_msg_type(&m->options[4], DHCPOFFER);
|
||||
end = add_offer_options(dhcps, end);
|
||||
end = add_offer_options(dhcps, end, true);
|
||||
LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPOFFER, &end)
|
||||
end = add_end(end);
|
||||
|
||||
@@ -803,7 +850,7 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
|
||||
create_msg(dhcps, m);
|
||||
|
||||
end = add_msg_type(&m->options[4], DHCPACK);
|
||||
end = add_offer_options(dhcps, end);
|
||||
end = add_offer_options(dhcps, end, true);
|
||||
LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPACK, &end)
|
||||
end = add_end(end);
|
||||
|
||||
@@ -870,6 +917,50 @@ static void send_ack(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : send_ack_inform
|
||||
* Description : DHCPACK response to DHCPINFORM (RFC 2131: yiaddr = 0, no lease time)
|
||||
* Parameters : m -- DHCP message info
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
static void send_ack_inform(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
|
||||
{
|
||||
u8_t *end;
|
||||
struct pbuf *p, *q;
|
||||
u8_t *data;
|
||||
u16_t cnt = 0;
|
||||
u16_t i;
|
||||
create_msg(dhcps, m);
|
||||
memset(m->yiaddr, 0, sizeof(m->yiaddr));
|
||||
|
||||
end = add_msg_type(&m->options[4], DHCPACK);
|
||||
end = add_offer_options(dhcps, end, false);
|
||||
LWIP_HOOK_DHCPS_POST_APPEND_OPTS(dhcps->dhcps_netif, dhcps, DHCPACK, &end)
|
||||
end = add_end(end);
|
||||
|
||||
p = dhcps_pbuf_alloc(len);
|
||||
if (p == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
q = p;
|
||||
while (q != NULL) {
|
||||
data = (u8_t *)q->payload;
|
||||
for (i = 0; i < q->len; i++) {
|
||||
data[i] = ((u8_t *) m)[cnt++];
|
||||
}
|
||||
q = q->next;
|
||||
}
|
||||
|
||||
ip_addr_t ip_temp = IPADDR4_INIT(0x0);
|
||||
dhcps_response_ip_set(dhcps, m, ip_2_ip4(&ip_temp));
|
||||
udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
|
||||
|
||||
if (p->ref != 0) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : parse_options
|
||||
* Description : parse DHCP message options
|
||||
@@ -1002,6 +1093,23 @@ static s16_t parse_msg(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
|
||||
#if DHCPS_DEBUG
|
||||
DHCPS_LOG("dhcps: len = %d\n", len);
|
||||
#endif
|
||||
{
|
||||
u8_t msg_type = dhcps_get_option_msg_type(&m->options[4], (s16_t)len);
|
||||
if (msg_type == DHCPINFORM) {
|
||||
ip4_addr_t ciaddr;
|
||||
memcpy(&ciaddr.addr, m->ciaddr, sizeof(ciaddr.addr));
|
||||
if (ip4_addr_isany(&ciaddr)) {
|
||||
/* RFC 2131: client MUST set ciaddr to its configured address */
|
||||
return 0;
|
||||
}
|
||||
if (!ip4_addr_netcmp(&ciaddr, &dhcps->server_address, &dhcps->dhcps_mask)) {
|
||||
/* No configuration for this client */
|
||||
return 0;
|
||||
}
|
||||
return DHCPS_STATE_INFORM_ACK;
|
||||
}
|
||||
}
|
||||
|
||||
ip4_addr_t addr_tmp;
|
||||
|
||||
struct dhcps_pool *pdhcps_pool = NULL;
|
||||
@@ -1226,6 +1334,13 @@ static void handle_dhcp(void *arg,
|
||||
send_nak(dhcps, pmsg_dhcps, malloc_len);
|
||||
break;
|
||||
|
||||
case DHCPS_STATE_INFORM_ACK://7
|
||||
#if DHCPS_DEBUG
|
||||
DHCPS_LOG("dhcps: handle_dhcp-> DHCPD_STATE_INFORM_ACK\n");
|
||||
#endif
|
||||
send_ack_inform(dhcps, pmsg_dhcps, malloc_len);
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ typedef enum
|
||||
* - MAX_STATION_NUM: Maximum number of clients, set to Kconfig value CONFIG_LWIP_DHCPS_MAX_STATION_NUM
|
||||
* - LWIP_HOOK_DHCPS_POST_STATE: Used to inject user code after parsing DHCP message, not defined
|
||||
* - could be enabled in lwipopts.h or via CC_FLAGS
|
||||
* - parse states include DHCPS_STATE_OFFER (1), ACK (3), NAK (4), INFORM_ACK (7), etc.
|
||||
* - basic usage of the hook to print hex representation of the entire option field is below:
|
||||
* #define LWIP_HOOK_DHCPS_POST_STATE(msg, len, state) \
|
||||
* ({ s16_t ret = state; if (state == DHCPS_STATE_ACK) { ESP_LOG_BUFFER_HEXDUMP("DHCPS",msg->options, 312, ESP_LOG_INFO);} ret; })
|
||||
|
||||
Reference in New Issue
Block a user