From 4c98f575e7263ad53cbd7564fa3babf574a390da Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 13 Aug 2015 17:10:38 +1000 Subject: [PATCH 1/4] dhcpserver: Initial DHCP server support, hands out leases but doesn't expire them --- extras/dhcpserver/component.mk | 11 + extras/dhcpserver/dhcpserver.c | 279 +++++++++++++++++++++++++ extras/dhcpserver/include/dhcpserver.h | 34 +++ 3 files changed, 324 insertions(+) create mode 100644 extras/dhcpserver/component.mk create mode 100644 extras/dhcpserver/dhcpserver.c create mode 100644 extras/dhcpserver/include/dhcpserver.h diff --git a/extras/dhcpserver/component.mk b/extras/dhcpserver/component.mk new file mode 100644 index 0000000..79a6dc9 --- /dev/null +++ b/extras/dhcpserver/component.mk @@ -0,0 +1,11 @@ +# Component makefile for extras/dhcpserver + +#error IWASERROR + +INC_DIRS += $(ROOT)extras/dhcpserver/include + +# args for passing into compile rule generation +extras/dhcpserver_INC_DIR = $(ROOT)extras/dhcpserver +extras/dhcpserver_SRC_DIR = $(ROOT)extras/dhcpserver + +$(eval $(call component_compile_rules,extras/dhcpserver)) diff --git a/extras/dhcpserver/dhcpserver.c b/extras/dhcpserver/dhcpserver.c new file mode 100644 index 0000000..106a9bd --- /dev/null +++ b/extras/dhcpserver/dhcpserver.c @@ -0,0 +1,279 @@ +/* Very basic LWIP & FreeRTOS-based DHCP server + + Based on RFC2131 http://www.ietf.org/rfc/rfc2131.txt + ... although not fully RFC compliant yet. + */ +#include + +#include +#include + +#include +#include +#include +#include + +#include "dhcpserver.h" + +typedef struct { + uint8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + uint32_t expires; +} dhcp_lease_t; + +typedef struct { + struct netconn *nc; + dhcp_lease_t leases[DHCPSERVER_MAXCLIENTS]; + struct netif *server_if; +} server_state_t; + +/* Handlers for various kinds of incoming DHCP messages */ +static void handle_dhcp_discover(server_state_t *state, struct dhcp_msg *received); +static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg); + +/* Utility functions */ +static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length); +static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value); +static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len); +static dhcp_lease_t *find_lease_slot(dhcp_lease_t *leases, uint8_t *hwaddr); + +static void dhcpserver_task(void *pxParameter) +{ + server_state_t state = { + /* TODO: allow server interface to be specified as argument to dhcpserver_start() */ + .server_if = netif_list, + }; + + state.nc = netconn_new (NETCONN_UDP); + if(!state.nc) { + printf("OTA TFTP: Failed to allocate socket.\r\n"); + return; + } + + /* Seems in LWIP we need to bind to IP_ADDR_ANY to receive broadcasts. + + No way I can find to either bind only on a particular interface (server_if), + or to filter incoming broadcasts to only accept those on a single interface, + when the REQUEST arrives the from address is 0.0.0.0 and to is 255.255.255.255, + and the pbuf doesn't know about the interface it came in on... :/ + */ + netconn_bind(state.nc, IP_ADDR_ANY, DHCP_SERVER_PORT); + + while(1) + { + struct netbuf *netbuf; + struct dhcp_msg received = { 0 }; + err_t err = netconn_recv(state.nc, &netbuf); + if(err != ERR_OK) { + printf("DHCP Server Error: Failed to receive DHCP packet. err=%d\r\n", err); + continue; + } + + ip_addr_t received_ip; + u16_t port; + netconn_addr(state.nc, &received_ip, &port); + + if(netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) { + /* too short to be a valid DHCP client message */ + netbuf_delete(netbuf); + continue; + } + if(netbuf_len(netbuf) >= sizeof(struct dhcp_msg)) { + printf("DHCP Server Warning: Client sent more options than we know how to parse. len=%d\r\n", netbuf_len(netbuf)); + } + + //netconn_connect(nc, netbuf_fromaddr(netbuf), netbuf_fromport(netbuf)); + netbuf_copy(netbuf, &received, sizeof(struct dhcp_msg)); + netbuf_delete(netbuf); + + uint8_t *message_type = find_dhcp_option(&received, DHCP_OPTION_MESSAGE_TYPE, + DHCP_OPTION_MESSAGE_TYPE_LEN, NULL); + if(!message_type) { + printf("DHCP Server Error: No message type field found"); + continue; + } + switch(*message_type) { + case DHCP_DISCOVER: + handle_dhcp_discover(&state, &received); + break; + case DHCP_REQUEST: + handle_dhcp_request(&state, &received); + break; + default: + printf("DHCP Server Error: Unsupported message type %d\r\n", *message_type); + break; + } + } +} + +static void handle_dhcp_discover(server_state_t *state, struct dhcp_msg *dhcpmsg) +{ + if(dhcpmsg->htype != DHCP_HTYPE_ETH) + return; + if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) + return; + + dhcp_lease_t *freelease = find_lease_slot(state->leases, dhcpmsg->chaddr); + if(!freelease) { + printf("DHCP Server: All leases taken.\r\n"); + return; /* Nothing available, so do nothing */ + } + + /* Reuse the DISCOVER buffer for the OFFER response */ + dhcpmsg->op = DHCP_BOOTREPLY; + bzero(dhcpmsg->options, DHCP_OPTIONS_LEN); + + DHCPSERVER_FIRST_CLIENT_IP(&(dhcpmsg->yiaddr)); + ip4_addr4(&(dhcpmsg->yiaddr)) += (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); + opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0); + + printf("Sending discover response...\r\n"); + struct netbuf *netbuf = netbuf_new(); + netbuf_alloc(netbuf, sizeof(struct dhcp_msg)); + netbuf_take(netbuf, dhcpmsg, sizeof(struct dhcp_msg)); + netconn_sendto(state->nc, netbuf, IP_ADDR_BROADCAST, 68); + netbuf_delete(netbuf); +} + +static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) +{ + if(dhcpmsg->htype != DHCP_HTYPE_ETH) + return; + if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) + return; + + ip_addr_t requested_ip; + uint8_t *requested_ip_opt = find_dhcp_option(dhcpmsg, DHCP_OPTION_REQUESTED_IP, 4, NULL); + if(requested_ip_opt) { + memcpy(&requested_ip.addr, requested_ip_opt, 4); + } else if(ip_addr_cmp(&requested_ip, IP_ADDR_ANY)) { + ip_addr_copy(requested_ip, dhcpmsg->ciaddr); + } else { + printf("DHCP Server Error: No requested IP\r\n"); + return; + } + ip_addr_t first_client_ip; + DHCPSERVER_FIRST_CLIENT_IP(&first_client_ip); + + /* Test the first 4 octets match */ + if(ip4_addr1(&requested_ip) != ip4_addr1(&first_client_ip) + || ip4_addr2(&requested_ip) != ip4_addr2(&first_client_ip) + || ip4_addr3(&requested_ip) != ip4_addr3(&first_client_ip)) { + printf("DHCP Server Error: 0x%08lx Not an allowed IP\r\n", requested_ip.addr); + return; + } + /* Test the last octet is in the MAXCLIENTS range */ + int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&first_client_ip); + if(octet_offs < 0 || octet_offs >= DHCPSERVER_MAXCLIENTS) { + printf("DHCP Server Error: Address out of range\r\n"); + return; + } + + dhcp_lease_t *requested_lease = state->leases + octet_offs; + if(requested_lease->expires != 0 && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen)) + { + printf("DHCP Server Error: Lease for address already taken\r\n"); + return; + } + + memcpy(requested_lease->hwaddr, dhcpmsg->chaddr, dhcpmsg->hlen); + printf("DHCP lease addr 0x%08lx assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", requested_ip.addr, 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 = 1; + + /* Reuse the REQUEST message as the ACK message */ + dhcpmsg->op = DHCP_BOOTREPLY; + bzero(dhcpmsg->options, DHCP_OPTIONS_LEN); + + ip_addr_copy(dhcpmsg->yiaddr, requested_ip); + + uint8_t *opt = (uint8_t *)&dhcpmsg->options; + opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_ACK); + uint32_t expiry = htonl(DHCPSERVER_LEASE_TIME); + 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_END, NULL, 0); + + struct netbuf *netbuf = netbuf_new(); + netbuf_alloc(netbuf, sizeof(struct dhcp_msg)); + netbuf_take(netbuf, dhcpmsg, sizeof(struct dhcp_msg)); + netconn_sendto(state->nc, netbuf, IP_ADDR_BROADCAST, 68); + netbuf_delete(netbuf); +} + +static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length) +{ + uint8_t *start = (uint8_t *)&msg->options; + uint8_t *msg_end = (uint8_t *)msg + sizeof(struct dhcp_msg); + + for(uint8_t *p = start; p < msg_end-2;) { + uint8_t type = *p++; + uint8_t len = *p++; + if(type == DHCP_OPTION_END) + return NULL; + if(p+len >= msg_end) + break; /* We've overrun our valid DHCP message size, or this isn't a valid option */ + if(type == option_num) { + if(len < min_length) + break; + if(length) + *length = len; + return p; /* start of actual option data */ + } + p += len; + } + return NULL; /* Not found */ +} + +static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value) +{ + *opt++ = type; + *opt++ = 1; + *opt++ = value; + return opt; +} + +static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len) +{ + *opt++ = type; + if(len) { + *opt++ = len; + memcpy(opt, value, len); + } + return opt+len; +} + +/* Find a free DHCP lease, or a lease already assigned to 'hwaddr' */ +static dhcp_lease_t *find_lease_slot(dhcp_lease_t *leases, uint8_t *hwaddr) +{ + dhcp_lease_t *empty_lease = NULL; + for(int i = 0; i < DHCPSERVER_MAXCLIENTS; i++) { + if(leases->expires == 0 && !empty_lease) + empty_lease = &leases[i]; + else if (memcmp(hwaddr, leases[i].hwaddr, 6) == 0) + return &leases[i]; + + } + return empty_lease; +} + +static xTaskHandle dhcpserver_task_handle; + +void dhcpserver_start(void) +{ + xTaskCreate(dhcpserver_task, (signed char *)"DHCPServer", 768, NULL, 8, &dhcpserver_task_handle); +} + +void dhcpserver_stop(void) +{ + if(dhcpserver_task_handle) { + vTaskDelete(dhcpserver_task_handle); + dhcpserver_task_handle = NULL; + } +} diff --git a/extras/dhcpserver/include/dhcpserver.h b/extras/dhcpserver/include/dhcpserver.h new file mode 100644 index 0000000..5219b49 --- /dev/null +++ b/extras/dhcpserver/include/dhcpserver.h @@ -0,0 +1,34 @@ +/* Very basic LWIP & FreeRTOS-based DHCP server + + */ +#ifndef _DHCPSERVER_H +#define _DHCPSERVER_H + +#ifndef DHCPSERVER_MAXCLIENTS +#define DHCPSERVER_MAXCLIENTS 4 +#endif + +/* First client IP to hand out. + + IP assignment routine is very simple - Fourth octet in IP will be incremented + from this value to (value+DHCPSERVER_MAXCLIENTS-1). +*/ +#ifndef DHCPSERVER_FIRST_CLIENT_IP +#define DHCPSERVER_FIRST_CLIENT_IP(DST) IP4_ADDR(DST, 192, 168, 3, 5) +#endif + +#ifndef DHCPSERVER_LEASE_TIME +#define DHCPSERVER_LEASE_TIME 30 +#endif + +/* Start DHCP server. + + Static IP of server should already be set and network interface enabled. +*/ +void dhcpserver_start(void); + +/* Stop DHCP server. + */ +void dhcpserver_stop(void); + +#endif From 9fc223b3c28a18078248abb8b563eedfb6e14935 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 24 Aug 2015 16:13:24 +1000 Subject: [PATCH 2/4] dhcpserver: Add expiry, DHCPNAK packets --- extras/dhcpserver/dhcpserver.c | 47 +++++++++++++++++++++++++- extras/dhcpserver/include/dhcpserver.h | 2 +- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/extras/dhcpserver/dhcpserver.c b/extras/dhcpserver/dhcpserver.c index 106a9bd..d56fef2 100644 --- a/extras/dhcpserver/dhcpserver.c +++ b/extras/dhcpserver/dhcpserver.c @@ -29,6 +29,9 @@ typedef struct { /* Handlers for various kinds of incoming DHCP messages */ static void handle_dhcp_discover(server_state_t *state, struct dhcp_msg *received); static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg); +static void handle_dhcp_release(server_state_t *state, struct dhcp_msg *dhcpmsg); + +static void send_dhcp_nak(server_state_t *state, struct dhcp_msg *dhcpmsg); /* Utility functions */ static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length); @@ -62,12 +65,22 @@ static void dhcpserver_task(void *pxParameter) { struct netbuf *netbuf; struct dhcp_msg received = { 0 }; + + /* Receive a DHCP packet */ err_t err = netconn_recv(state.nc, &netbuf); if(err != ERR_OK) { printf("DHCP Server Error: Failed to receive DHCP packet. err=%d\r\n", err); continue; } + /* expire any leases that have passed */ + uint32_t now = xTaskGetTickCount(); + for(int i = 0; i < DHCPSERVER_MAXCLIENTS; i++) { + uint32_t expires = state.leases[i].expires; + if(expires && expires < now) + state.leases[i].expires = 0; + } + ip_addr_t received_ip; u16_t port; netconn_addr(state.nc, &received_ip, &port); @@ -98,6 +111,8 @@ static void dhcpserver_task(void *pxParameter) case DHCP_REQUEST: handle_dhcp_request(&state, &received); break; + case DHCP_RELEASE: + handle_dhcp_release(&state, &received); default: printf("DHCP Server Error: Unsupported message type %d\r\n", *message_type); break; @@ -155,6 +170,7 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) ip_addr_copy(requested_ip, dhcpmsg->ciaddr); } else { printf("DHCP Server Error: No requested IP\r\n"); + send_dhcp_nak(state, dhcpmsg); return; } ip_addr_t first_client_ip; @@ -165,12 +181,14 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) || ip4_addr2(&requested_ip) != ip4_addr2(&first_client_ip) || ip4_addr3(&requested_ip) != ip4_addr3(&first_client_ip)) { printf("DHCP Server Error: 0x%08lx Not an allowed IP\r\n", requested_ip.addr); + send_dhcp_nak(state, dhcpmsg); return; } /* Test the last octet is in the MAXCLIENTS range */ int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&first_client_ip); if(octet_offs < 0 || octet_offs >= DHCPSERVER_MAXCLIENTS) { printf("DHCP Server Error: Address out of range\r\n"); + send_dhcp_nak(state, dhcpmsg); return; } @@ -178,6 +196,7 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) if(requested_lease->expires != 0 && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen)) { printf("DHCP Server Error: Lease for address already taken\r\n"); + send_dhcp_nak(state, dhcpmsg); return; } @@ -185,7 +204,7 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) printf("DHCP lease addr 0x%08lx assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", requested_ip.addr, 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 = 1; + requested_lease->expires = DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ; /* Reuse the REQUEST message as the ACK message */ dhcpmsg->op = DHCP_BOOTREPLY; @@ -207,6 +226,32 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) netbuf_delete(netbuf); } +static void handle_dhcp_release(server_state_t *state, struct dhcp_msg *dhcpmsg) +{ + dhcp_lease_t *lease = find_lease_slot(state->leases, dhcpmsg->chaddr); + if(lease) { + lease->expires = 0; + } +} + +static void send_dhcp_nak(server_state_t *state, struct dhcp_msg *dhcpmsg) +{ + /* Reuse 'dhcpmsg' for the NAK */ + dhcpmsg->op = DHCP_BOOTREPLY; + bzero(dhcpmsg->options, DHCP_OPTIONS_LEN); + + uint8_t *opt = (uint8_t *)&dhcpmsg->options; + opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_NAK); + opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4); + opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0); + + struct netbuf *netbuf = netbuf_new(); + netbuf_alloc(netbuf, sizeof(struct dhcp_msg)); + netbuf_take(netbuf, dhcpmsg, sizeof(struct dhcp_msg)); + netconn_sendto(state->nc, netbuf, IP_ADDR_BROADCAST, 68); + netbuf_delete(netbuf); +} + static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length) { uint8_t *start = (uint8_t *)&msg->options; diff --git a/extras/dhcpserver/include/dhcpserver.h b/extras/dhcpserver/include/dhcpserver.h index 5219b49..7d343c0 100644 --- a/extras/dhcpserver/include/dhcpserver.h +++ b/extras/dhcpserver/include/dhcpserver.h @@ -18,7 +18,7 @@ #endif #ifndef DHCPSERVER_LEASE_TIME -#define DHCPSERVER_LEASE_TIME 30 +#define DHCPSERVER_LEASE_TIME 3600 #endif /* Start DHCP server. From 46111bad5255185dc5bc2cbc93eb5916acd7dcf0 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 10 Sep 2015 08:15:33 +1000 Subject: [PATCH 3/4] dhcpserver cleanup, add access_point example DHCP Server & AP mode tested w/ Debian & Android clients --- examples/access_point/Makefile | 5 + examples/access_point/access_point.c | 97 +++++++++++++++ extras/dhcpserver/component.mk | 10 +- extras/dhcpserver/dhcpserver.c | 162 ++++++++++++++----------- extras/dhcpserver/include/dhcpserver.h | 27 ++--- 5 files changed, 211 insertions(+), 90 deletions(-) create mode 100644 examples/access_point/Makefile create mode 100644 examples/access_point/access_point.c diff --git a/examples/access_point/Makefile b/examples/access_point/Makefile new file mode 100644 index 0000000..5a6bc6b --- /dev/null +++ b/examples/access_point/Makefile @@ -0,0 +1,5 @@ +# Makefile for access_point example +PROGRAM=access_point +EXTRA_COMPONENTS=extras/dhcpserver + +include ../../common.mk diff --git a/examples/access_point/access_point.c b/examples/access_point/access_point.c new file mode 100644 index 0000000..7091207 --- /dev/null +++ b/examples/access_point/access_point.c @@ -0,0 +1,97 @@ +/* Very basic example showing usage of access point mode and the DHCP server. + + The ESP in the example runs a telnet server on 172.16.0.1 (port 23) that + outputs some status information if you connect to it, then closes + the connection. + + This example code is in the public domain. +*/ +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define AP_SSID "esp-open-rtos AP" +#define AP_PSK "esp-open-rtos" + +#define TELNET_PORT 23 + +static void telnetTask(void *pvParameters); + +void user_init(void) +{ + sdk_uart_div_modify(0, UART_CLK_FREQ / 115200); + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + + sdk_wifi_set_opmode(SOFTAP_MODE); + struct ip_info ap_ip; + IP4_ADDR(&ap_ip.ip, 172, 16, 0, 1); + IP4_ADDR(&ap_ip.gw, 0, 0, 0, 0); + IP4_ADDR(&ap_ip.netmask, 255, 255, 0, 0); + sdk_wifi_set_ip_info(1, &ap_ip); + + struct sdk_softap_config ap_config = { + .ssid = AP_SSID, + .ssid_hidden = 0, + .channel = 3, + .ssid_len = strlen(AP_SSID), + .authmode = AUTH_WPA_WPA2_PSK, + .password = AP_PSK, + .max_connection = 3, + .beacon_interval = 100, + }; + sdk_wifi_softap_set_config(&ap_config); + + ip_addr_t first_client_ip; + IP4_ADDR(&first_client_ip, 172, 16, 0, 2); + dhcpserver_start(&first_client_ip, 4); + + xTaskCreate(telnetTask, (signed char *)"telnetTask", 512, NULL, 2, NULL); +} + +/* Telnet task listens on port 23, returns some status information and then closes + the connection if you connect to it. +*/ +static void telnetTask(void *pvParameters) +{ + struct netconn *nc = netconn_new (NETCONN_TCP); + if(!nc) { + printf("Status monitor: Failed to allocate socket.\r\n"); + return; + } + netconn_bind(nc, IP_ADDR_ANY, TELNET_PORT); + netconn_listen(nc); + + while(1) { + struct netconn *client = NULL; + err_t err = netconn_accept(nc, &client); + + if ( err != ERR_OK ) { + if(client) + netconn_delete(client); + continue; + } + + ip_addr_t client_addr; + uint16_t port_ignore; + netconn_peer(client, &client_addr, &port_ignore); + + char buf[80]; + snprintf(buf, sizeof(buf), "Uptime %d seconds\r\n", + xTaskGetTickCount()*portTICK_RATE_MS/1000); + netconn_write(client, buf, strlen(buf), NETCONN_COPY); + snprintf(buf, sizeof(buf), "Free heap %d bytes\r\n", (int)xPortGetFreeHeapSize()); + netconn_write(client, buf, strlen(buf), NETCONN_COPY); + snprintf(buf, sizeof(buf), "Your address is %d.%d.%d.%d\r\n\r\n", + ip4_addr1(&client_addr), ip4_addr2(&client_addr), + ip4_addr3(&client_addr), ip4_addr4(&client_addr)); + netconn_write(client, buf, strlen(buf), NETCONN_COPY); + netconn_delete(client); + } +} diff --git a/extras/dhcpserver/component.mk b/extras/dhcpserver/component.mk index 79a6dc9..07da648 100644 --- a/extras/dhcpserver/component.mk +++ b/extras/dhcpserver/component.mk @@ -1,11 +1,9 @@ # Component makefile for extras/dhcpserver -#error IWASERROR - -INC_DIRS += $(ROOT)extras/dhcpserver/include +INC_DIRS += $(dhcpserver_ROOT)include # args for passing into compile rule generation -extras/dhcpserver_INC_DIR = $(ROOT)extras/dhcpserver -extras/dhcpserver_SRC_DIR = $(ROOT)extras/dhcpserver +dhcpserver_INC_DIR = $(dhcpserver_ROOT) +dhcpserver_SRC_DIR = $(dhcpserver_ROOT) -$(eval $(call component_compile_rules,extras/dhcpserver)) +$(eval $(call component_compile_rules,dhcpserver)) diff --git a/extras/dhcpserver/dhcpserver.c b/extras/dhcpserver/dhcpserver.c index d56fef2..6224544 100644 --- a/extras/dhcpserver/dhcpserver.c +++ b/extras/dhcpserver/dhcpserver.c @@ -1,16 +1,34 @@ /* Very basic LWIP & FreeRTOS-based DHCP server - - Based on RFC2131 http://www.ietf.org/rfc/rfc2131.txt - ... although not fully RFC compliant yet. + * + * Based on RFC2131 http://www.ietf.org/rfc/rfc2131.txt + * ... although not fully RFC compliant yet. + * + * TODO + * * Allow binding on a single interface only (for mixed AP/client mode), lwip seems to make it hard to + * listen for or send broadcasts on a specific interface only. + * + * * Probably allocates more memory than it should, it should be possible to reuse netbufs in most cases. + * + * Part of esp-open-rtos + * Copyright (C) 2015 Superhouse Automation Pty Ltd + * BSD Licensed as described in the file LICENSE */ #include #include #include - #include #include + +/* 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 + +_Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 312, "dhcp_msg_t should have extended options size"); + #include #include "dhcpserver.h" @@ -22,16 +40,26 @@ typedef struct { typedef struct { struct netconn *nc; - dhcp_lease_t leases[DHCPSERVER_MAXCLIENTS]; + uint8_t max_leases; + ip_addr_t first_client_addr; struct netif *server_if; + dhcp_lease_t *leases; /* length max_leases */ } server_state_t; -/* Handlers for various kinds of incoming DHCP messages */ -static void handle_dhcp_discover(server_state_t *state, struct dhcp_msg *received); -static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg); -static void handle_dhcp_release(server_state_t *state, struct dhcp_msg *dhcpmsg); +/* Only one DHCP server task can run at once, so we have global state + for it. +*/ +static xTaskHandle dhcpserver_task_handle; +static server_state_t *state; -static void send_dhcp_nak(server_state_t *state, struct dhcp_msg *dhcpmsg); +/* Handlers for various kinds of incoming DHCP messages */ +static void handle_dhcp_discover(struct dhcp_msg *received); +static void handle_dhcp_request(struct dhcp_msg *dhcpmsg); +static void handle_dhcp_release(struct dhcp_msg *dhcpmsg); + +static void send_dhcp_nak(struct dhcp_msg *dhcpmsg); + +static void dhcpserver_task(void *pxParameter); /* Utility functions */ static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length); @@ -39,27 +67,42 @@ static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value); static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len); static dhcp_lease_t *find_lease_slot(dhcp_lease_t *leases, uint8_t *hwaddr); +void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases) +{ + /* Stop any existing running dhcpserver */ + if(dhcpserver_task_handle) + dhcpserver_stop(); + + state = malloc(sizeof(server_state_t)); + state->max_leases = max_leases; + state->leases = calloc(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, (signed char *)"DHCPServer", 768, NULL, 8, &dhcpserver_task_handle); +} + +void dhcpserver_stop(void) +{ + if(dhcpserver_task_handle) { + vTaskDelete(dhcpserver_task_handle); + free(state); + dhcpserver_task_handle = NULL; + } +} + static void dhcpserver_task(void *pxParameter) { - server_state_t state = { - /* TODO: allow server interface to be specified as argument to dhcpserver_start() */ - .server_if = netif_list, - }; + /* netif_list isn't assigned until after user_init completes, which is why we do it inside the task */ + state->server_if = netif_list; /* TODO: Make this configurable */ - state.nc = netconn_new (NETCONN_UDP); - if(!state.nc) { + state->nc = netconn_new (NETCONN_UDP); + if(!state->nc) { printf("OTA TFTP: Failed to allocate socket.\r\n"); return; } - /* Seems in LWIP we need to bind to IP_ADDR_ANY to receive broadcasts. - - No way I can find to either bind only on a particular interface (server_if), - or to filter incoming broadcasts to only accept those on a single interface, - when the REQUEST arrives the from address is 0.0.0.0 and to is 255.255.255.255, - and the pbuf doesn't know about the interface it came in on... :/ - */ - netconn_bind(state.nc, IP_ADDR_ANY, DHCP_SERVER_PORT); + netconn_bind(state->nc, IP_ADDR_ANY, DHCP_SERVER_PORT); while(1) { @@ -67,7 +110,7 @@ static void dhcpserver_task(void *pxParameter) struct dhcp_msg received = { 0 }; /* Receive a DHCP packet */ - err_t err = netconn_recv(state.nc, &netbuf); + err_t err = netconn_recv(state->nc, &netbuf); if(err != ERR_OK) { printf("DHCP Server Error: Failed to receive DHCP packet. err=%d\r\n", err); continue; @@ -75,15 +118,15 @@ static void dhcpserver_task(void *pxParameter) /* expire any leases that have passed */ uint32_t now = xTaskGetTickCount(); - for(int i = 0; i < DHCPSERVER_MAXCLIENTS; i++) { - uint32_t expires = state.leases[i].expires; + 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; + state->leases[i].expires = 0; } ip_addr_t received_ip; u16_t port; - netconn_addr(state.nc, &received_ip, &port); + netconn_addr(state->nc, &received_ip, &port); if(netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) { /* too short to be a valid DHCP client message */ @@ -94,7 +137,6 @@ static void dhcpserver_task(void *pxParameter) printf("DHCP Server Warning: Client sent more options than we know how to parse. len=%d\r\n", netbuf_len(netbuf)); } - //netconn_connect(nc, netbuf_fromaddr(netbuf), netbuf_fromport(netbuf)); netbuf_copy(netbuf, &received, sizeof(struct dhcp_msg)); netbuf_delete(netbuf); @@ -106,13 +148,13 @@ static void dhcpserver_task(void *pxParameter) } switch(*message_type) { case DHCP_DISCOVER: - handle_dhcp_discover(&state, &received); + handle_dhcp_discover(&received); break; case DHCP_REQUEST: - handle_dhcp_request(&state, &received); + handle_dhcp_request(&received); break; case DHCP_RELEASE: - handle_dhcp_release(&state, &received); + handle_dhcp_release(&received); default: printf("DHCP Server Error: Unsupported message type %d\r\n", *message_type); break; @@ -120,7 +162,7 @@ static void dhcpserver_task(void *pxParameter) } } -static void handle_dhcp_discover(server_state_t *state, struct dhcp_msg *dhcpmsg) +static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg) { if(dhcpmsg->htype != DHCP_HTYPE_ETH) return; @@ -137,17 +179,15 @@ static void handle_dhcp_discover(server_state_t *state, struct dhcp_msg *dhcpmsg dhcpmsg->op = DHCP_BOOTREPLY; bzero(dhcpmsg->options, DHCP_OPTIONS_LEN); - DHCPSERVER_FIRST_CLIENT_IP(&(dhcpmsg->yiaddr)); + ip_addr_copy(dhcpmsg->yiaddr, state->first_client_addr); ip4_addr4(&(dhcpmsg->yiaddr)) += (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); opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0); - printf("Sending discover response...\r\n"); struct netbuf *netbuf = netbuf_new(); netbuf_alloc(netbuf, sizeof(struct dhcp_msg)); netbuf_take(netbuf, dhcpmsg, sizeof(struct dhcp_msg)); @@ -155,7 +195,7 @@ static void handle_dhcp_discover(server_state_t *state, struct dhcp_msg *dhcpmsg netbuf_delete(netbuf); } -static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) +static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) { if(dhcpmsg->htype != DHCP_HTYPE_ETH) return; @@ -170,25 +210,23 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) ip_addr_copy(requested_ip, dhcpmsg->ciaddr); } else { printf("DHCP Server Error: No requested IP\r\n"); - send_dhcp_nak(state, dhcpmsg); + send_dhcp_nak(dhcpmsg); return; } - ip_addr_t first_client_ip; - DHCPSERVER_FIRST_CLIENT_IP(&first_client_ip); /* Test the first 4 octets match */ - if(ip4_addr1(&requested_ip) != ip4_addr1(&first_client_ip) - || ip4_addr2(&requested_ip) != ip4_addr2(&first_client_ip) - || ip4_addr3(&requested_ip) != ip4_addr3(&first_client_ip)) { - printf("DHCP Server Error: 0x%08lx Not an allowed IP\r\n", requested_ip.addr); - send_dhcp_nak(state, dhcpmsg); + if(ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr) + || ip4_addr2(&requested_ip) != ip4_addr2(&state->first_client_addr) + || ip4_addr3(&requested_ip) != ip4_addr3(&state->first_client_addr)) { + printf("DHCP Server Error: 0x%08x Not an allowed IP\r\n", requested_ip.addr); + send_dhcp_nak(dhcpmsg); return; } /* Test the last octet is in the MAXCLIENTS range */ - int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&first_client_ip); - if(octet_offs < 0 || octet_offs >= DHCPSERVER_MAXCLIENTS) { + int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&state->first_client_addr); + if(octet_offs < 0 || octet_offs >= state->max_leases) { printf("DHCP Server Error: Address out of range\r\n"); - send_dhcp_nak(state, dhcpmsg); + send_dhcp_nak(dhcpmsg); return; } @@ -196,12 +234,12 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) if(requested_lease->expires != 0 && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen)) { printf("DHCP Server Error: Lease for address already taken\r\n"); - send_dhcp_nak(state, dhcpmsg); + send_dhcp_nak(dhcpmsg); return; } memcpy(requested_lease->hwaddr, dhcpmsg->chaddr, dhcpmsg->hlen); - printf("DHCP lease addr 0x%08lx assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", requested_ip.addr, requested_lease->hwaddr[0], + printf("DHCP lease addr 0x%08x assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", requested_ip.addr, 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; @@ -217,6 +255,7 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) uint32_t expiry = htonl(DHCPSERVER_LEASE_TIME); 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); opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0); struct netbuf *netbuf = netbuf_new(); @@ -226,7 +265,7 @@ static void handle_dhcp_request(server_state_t *state, struct dhcp_msg *dhcpmsg) netbuf_delete(netbuf); } -static void handle_dhcp_release(server_state_t *state, struct dhcp_msg *dhcpmsg) +static void handle_dhcp_release(struct dhcp_msg *dhcpmsg) { dhcp_lease_t *lease = find_lease_slot(state->leases, dhcpmsg->chaddr); if(lease) { @@ -234,7 +273,7 @@ static void handle_dhcp_release(server_state_t *state, struct dhcp_msg *dhcpmsg) } } -static void send_dhcp_nak(server_state_t *state, struct dhcp_msg *dhcpmsg) +static void send_dhcp_nak(struct dhcp_msg *dhcpmsg) { /* Reuse 'dhcpmsg' for the NAK */ dhcpmsg->op = DHCP_BOOTREPLY; @@ -298,7 +337,7 @@ static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, u static dhcp_lease_t *find_lease_slot(dhcp_lease_t *leases, uint8_t *hwaddr) { dhcp_lease_t *empty_lease = NULL; - for(int i = 0; i < DHCPSERVER_MAXCLIENTS; i++) { + for(int i = 0; i < state->max_leases; i++) { if(leases->expires == 0 && !empty_lease) empty_lease = &leases[i]; else if (memcmp(hwaddr, leases[i].hwaddr, 6) == 0) @@ -307,18 +346,3 @@ static dhcp_lease_t *find_lease_slot(dhcp_lease_t *leases, uint8_t *hwaddr) } return empty_lease; } - -static xTaskHandle dhcpserver_task_handle; - -void dhcpserver_start(void) -{ - xTaskCreate(dhcpserver_task, (signed char *)"DHCPServer", 768, NULL, 8, &dhcpserver_task_handle); -} - -void dhcpserver_stop(void) -{ - if(dhcpserver_task_handle) { - vTaskDelete(dhcpserver_task_handle); - dhcpserver_task_handle = NULL; - } -} diff --git a/extras/dhcpserver/include/dhcpserver.h b/extras/dhcpserver/include/dhcpserver.h index 7d343c0..43d0483 100644 --- a/extras/dhcpserver/include/dhcpserver.h +++ b/extras/dhcpserver/include/dhcpserver.h @@ -1,22 +1,15 @@ /* Very basic LWIP & FreeRTOS-based DHCP server - + * + * Header file contains default configuration for the DHCP server. + * + * + * Part of esp-open-rtos + * Copyright (C) 2015 Superhouse Automation Pty Ltd + * BSD Licensed as described in the file LICENSE */ #ifndef _DHCPSERVER_H #define _DHCPSERVER_H -#ifndef DHCPSERVER_MAXCLIENTS -#define DHCPSERVER_MAXCLIENTS 4 -#endif - -/* First client IP to hand out. - - IP assignment routine is very simple - Fourth octet in IP will be incremented - from this value to (value+DHCPSERVER_MAXCLIENTS-1). -*/ -#ifndef DHCPSERVER_FIRST_CLIENT_IP -#define DHCPSERVER_FIRST_CLIENT_IP(DST) IP4_ADDR(DST, 192, 168, 3, 5) -#endif - #ifndef DHCPSERVER_LEASE_TIME #define DHCPSERVER_LEASE_TIME 3600 #endif @@ -24,8 +17,12 @@ /* Start DHCP server. Static IP of server should already be set and network interface enabled. + + first_client_addr is the IP address of the first lease to be handed + to a client. Subsequent lease addresses are calculated by + incrementing the final octet of the IPv4 address, up to max_leases. */ -void dhcpserver_start(void); +void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases); /* Stop DHCP server. */ From a0a23ae23215dc56e533c333b6562273b4ba99d3 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 23 Sep 2015 22:24:25 +1000 Subject: [PATCH 4/4] dhcpserver: Cleanup find_lease routine, fix bug --- extras/dhcpserver/dhcpserver.c | 44 +++++++++++++++++++------- extras/dhcpserver/include/dhcpserver.h | 2 ++ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/extras/dhcpserver/dhcpserver.c b/extras/dhcpserver/dhcpserver.c index 6224544..269b297 100644 --- a/extras/dhcpserver/dhcpserver.c +++ b/extras/dhcpserver/dhcpserver.c @@ -65,7 +65,17 @@ static void dhcpserver_task(void *pxParameter); static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length); static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value); static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len); -static dhcp_lease_t *find_lease_slot(dhcp_lease_t *leases, uint8_t *hwaddr); +static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr); + +/* Copy IP address as dotted decimal to 'dest', must be at least 16 bytes long */ +inline static void sprintf_ipaddr(const ip_addr_t *addr, char *dest) +{ + if(addr == NULL) + sprintf(dest, "NULL"); + else + sprintf(dest, "%d.%d.%d.%d", ip4_addr1(addr), + ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr)); +} void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases) { @@ -146,6 +156,16 @@ static void dhcpserver_task(void *pxParameter) printf("DHCP Server Error: No message type field found"); 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]); + } + switch(*message_type) { case DHCP_DISCOVER: handle_dhcp_discover(&received); @@ -169,7 +189,7 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg) if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) return; - dhcp_lease_t *freelease = find_lease_slot(state->leases, dhcpmsg->chaddr); + dhcp_lease_t *freelease = find_lease_slot(dhcpmsg->chaddr); if(!freelease) { printf("DHCP Server: All leases taken.\r\n"); return; /* Nothing available, so do nothing */ @@ -197,6 +217,7 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg) static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) { + static char ipbuf[16]; if(dhcpmsg->htype != DHCP_HTYPE_ETH) return; if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) @@ -218,7 +239,8 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) if(ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr) || ip4_addr2(&requested_ip) != ip4_addr2(&state->first_client_addr) || ip4_addr3(&requested_ip) != ip4_addr3(&state->first_client_addr)) { - printf("DHCP Server Error: 0x%08x Not an allowed IP\r\n", requested_ip.addr); + sprintf_ipaddr(&requested_ip, ipbuf); + printf("DHCP Server Error: %s not an allowed IP\r\n", ipbuf); send_dhcp_nak(dhcpmsg); return; } @@ -239,7 +261,8 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) } memcpy(requested_lease->hwaddr, dhcpmsg->chaddr, dhcpmsg->hlen); - printf("DHCP lease addr 0x%08x assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", requested_ip.addr, requested_lease->hwaddr[0], + sprintf_ipaddr(&requested_ip, ipbuf); + 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; @@ -267,7 +290,7 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) static void handle_dhcp_release(struct dhcp_msg *dhcpmsg) { - dhcp_lease_t *lease = find_lease_slot(state->leases, dhcpmsg->chaddr); + dhcp_lease_t *lease = find_lease_slot(dhcpmsg->chaddr); if(lease) { lease->expires = 0; } @@ -334,15 +357,14 @@ static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, u } /* Find a free DHCP lease, or a lease already assigned to 'hwaddr' */ -static dhcp_lease_t *find_lease_slot(dhcp_lease_t *leases, uint8_t *hwaddr) +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(leases->expires == 0 && !empty_lease) - empty_lease = &leases[i]; - else if (memcmp(hwaddr, leases[i].hwaddr, 6) == 0) - return &leases[i]; - + if(state->leases[i].expires == 0 && !empty_lease) + empty_lease = &state->leases[i]; + else if (memcmp(hwaddr, state->leases[i].hwaddr, 6) == 0) + return &state->leases[i]; } return empty_lease; } diff --git a/extras/dhcpserver/include/dhcpserver.h b/extras/dhcpserver/include/dhcpserver.h index 43d0483..5548c19 100644 --- a/extras/dhcpserver/include/dhcpserver.h +++ b/extras/dhcpserver/include/dhcpserver.h @@ -24,6 +24,8 @@ */ void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases); +void dhcpserver_get_lease(const ip_addr_t *first_client_addr, uint8_t max_leases); + /* Stop DHCP server. */ void dhcpserver_stop(void);