Backport dhcpserver changes from ourairquality's LwIP2 work

https://github.com/ourairquality/esp-open-rtos/blob/ourairquality/extras/dhcpserver/dhcpserver.c
This commit is contained in:
Sakari Kapanen 2017-08-04 00:38:13 +03:00
parent 9523e872f8
commit b979169e61
2 changed files with 90 additions and 42 deletions

View file

@ -14,17 +14,20 @@
* BSD Licensed as described in the file LICENSE
*/
#include <string.h>
#include <strings.h>
#include <FreeRTOS.h>
#include <task.h>
#include <lwip/netif.h>
#include <lwip/api.h>
#include "esplibs/libmain.h"
/* Grow the size of the lwip dhcp_msg struct's options field, as LWIP
defaults to a 68 octet options field for its DHCP client, and most
full-sized clients send us more than this. */
#define DHCP_OPTIONS_LEN 312
#include <lwip/ip.h>
#include <lwip/dhcp.h>
_Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 312, "dhcp_msg_t should have extended options size");
@ -35,6 +38,7 @@ _Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 3
typedef struct {
uint8_t hwaddr[NETIF_MAX_HWADDR_LEN];
uint8_t active;
uint32_t expires;
} dhcp_lease_t;
@ -44,6 +48,10 @@ typedef struct {
ip_addr_t first_client_addr;
struct netif *server_if;
dhcp_lease_t *leases; /* length max_leases */
/* Optional router */
ip_addr_t router;
/* Optional DNS server */
ip_addr_t dns;
} server_state_t;
/* Only one DHCP server task can run at once, so we have global state
@ -86,10 +94,15 @@ void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases)
state = malloc(sizeof(server_state_t));
state->max_leases = max_leases;
state->leases = calloc(max_leases, sizeof(dhcp_lease_t));
bzero(state->leases, max_leases * sizeof(dhcp_lease_t));
// state->server_if is assigned once the task is running - see comment in dhcpserver_task()
ip_addr_copy(state->first_client_addr, *first_client_addr);
xTaskCreate(dhcpserver_task, "DHCPServer", 768, NULL, 8, &dhcpserver_task_handle);
/* Clear options */
ip_addr_set_zero(&state->router);
ip_addr_set_zero(&state->dns);
xTaskCreate(dhcpserver_task, "DHCP Server", 448, NULL, 2, &dhcpserver_task_handle);
}
void dhcpserver_stop(void)
@ -101,6 +114,16 @@ void dhcpserver_stop(void)
}
}
void dhcpserver_set_router(const ip_addr_t *router)
{
ip_addr_copy(state->router, *router);
}
void dhcpserver_set_dns(const ip_addr_t *dns)
{
ip_addr_copy(state->dns, *dns);
}
static void dhcpserver_task(void *pxParameter)
{
/* netif_list isn't assigned until after user_init completes, which is why we do it inside the task */
@ -129,9 +152,12 @@ static void dhcpserver_task(void *pxParameter)
/* expire any leases that have passed */
uint32_t now = xTaskGetTickCount();
for (int i = 0; i < state->max_leases; i++) {
uint32_t expires = state->leases[i].expires;
if(expires && expires < now)
state->leases[i].expires = 0;
if (state->leases[i].active) {
uint32_t expires = state->leases[i].expires - now;
if (expires >= 0x80000000) {
state->leases[i].active = 0;
}
}
}
ip_addr_t received_ip;
@ -157,13 +183,13 @@ static void dhcpserver_task(void *pxParameter)
continue;
}
printf("State dump. Message type %d\n", *message_type);
for (int i = 0; i < state->max_leases; i++) {
dhcp_lease_t *lease = &state->leases[i];
printf("lease slot %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i, lease->expires, lease->hwaddr[0],
lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
lease->hwaddr[5]);
printf("lease slot %d active %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i,
lease->active, lease->expires - now,
lease->hwaddr[0], lease->hwaddr[1], lease->hwaddr[2],
lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[5]);
}
switch(*message_type) {
@ -199,13 +225,19 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
dhcpmsg->op = DHCP_BOOTREPLY;
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
ip_addr_copy(dhcpmsg->yiaddr, state->first_client_addr);
ip4_addr4(&(dhcpmsg->yiaddr)) += (freelease - state->leases);
dhcpmsg->yiaddr.addr = lwip_htonl(lwip_ntohl(state->first_client_addr.addr) + (freelease - state->leases));
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_OFFER);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
if (!ip_addr_isany(&state->router)) {
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
}
if (!ip_addr_isany(&state->dns)) {
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
}
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
struct netbuf *netbuf = netbuf_new();
@ -253,7 +285,7 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
}
dhcp_lease_t *requested_lease = state->leases + octet_offs;
if(requested_lease->expires != 0 && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
if (requested_lease->active && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
{
printf("DHCP Server Error: Lease for address already taken\r\n");
send_dhcp_nak(dhcpmsg);
@ -265,7 +297,9 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
printf("DHCP lease addr %s assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", ipbuf, requested_lease->hwaddr[0],
requested_lease->hwaddr[1], requested_lease->hwaddr[2], requested_lease->hwaddr[3], requested_lease->hwaddr[4],
requested_lease->hwaddr[5]);
requested_lease->expires = DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
uint32_t now = xTaskGetTickCount();
requested_lease->expires = now + DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
requested_lease->active = 1;
/* Reuse the REQUEST message as the ACK message */
dhcpmsg->op = DHCP_BOOTREPLY;
@ -279,6 +313,13 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_LEASE_TIME, &expiry, 4);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
if (!ip_addr_isany(&state->router)) {
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
}
if (!ip_addr_isany(&state->dns)) {
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
}
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
struct netbuf *netbuf = netbuf_new();
@ -292,6 +333,7 @@ static void handle_dhcp_release(struct dhcp_msg *dhcpmsg)
{
dhcp_lease_t *lease = find_lease_slot(dhcpmsg->chaddr);
if (lease) {
lease->active = 0;
lease->expires = 0;
}
}
@ -361,7 +403,7 @@ static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr)
{
dhcp_lease_t *empty_lease = NULL;
for (int i = 0; i < state->max_leases; i++) {
if(state->leases[i].expires == 0 && !empty_lease)
if (!state->leases[i].active && !empty_lease)
empty_lease = &state->leases[i];
else if (memcmp(hwaddr, state->leases[i].hwaddr, 6) == 0)
return &state->leases[i];

View file

@ -34,6 +34,12 @@ void dhcpserver_get_lease(const ip_addr_t *first_client_addr, uint8_t max_leases
*/
void dhcpserver_stop(void);
/* Set a router address to send as an option. */
void dhcpserver_set_router(const ip_addr_t *router);
/* Set a DNS address to send as an option. */
void dhcpserver_set_dns(const ip_addr_t *dns);
#ifdef __cplusplus
}
#endif