xref: /btstack/3rd-party/lwip/dhcp-server/dhserver.c (revision 88cd67309cc94af545a96dac921d5ef21b3aa56e)
197dc5e69SMatthias Ringwald /*
297dc5e69SMatthias Ringwald  * The MIT License (MIT)
397dc5e69SMatthias Ringwald  *
497dc5e69SMatthias Ringwald  * Copyright (c) 2015 by Sergey Fetisov <[email protected]>
597dc5e69SMatthias Ringwald  *
697dc5e69SMatthias Ringwald  * Permission is hereby granted, free of charge, to any person obtaining a copy
797dc5e69SMatthias Ringwald  * of this software and associated documentation files (the "Software"), to deal
897dc5e69SMatthias Ringwald  * in the Software without restriction, including without limitation the rights
997dc5e69SMatthias Ringwald  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1097dc5e69SMatthias Ringwald  * copies of the Software, and to permit persons to whom the Software is
1197dc5e69SMatthias Ringwald  * furnished to do so, subject to the following conditions:
1297dc5e69SMatthias Ringwald  *
1397dc5e69SMatthias Ringwald  * The above copyright notice and this permission notice shall be included in all
1497dc5e69SMatthias Ringwald  * copies or substantial portions of the Software.
1597dc5e69SMatthias Ringwald  *
1697dc5e69SMatthias Ringwald  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1797dc5e69SMatthias Ringwald  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1897dc5e69SMatthias Ringwald  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1997dc5e69SMatthias Ringwald  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2097dc5e69SMatthias Ringwald  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2197dc5e69SMatthias Ringwald  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2297dc5e69SMatthias Ringwald  * SOFTWARE.
2397dc5e69SMatthias Ringwald  */
2497dc5e69SMatthias Ringwald 
2597dc5e69SMatthias Ringwald #include "dhserver.h"
2697dc5e69SMatthias Ringwald 
2797dc5e69SMatthias Ringwald /* DHCP message type */
2897dc5e69SMatthias Ringwald #define DHCP_DISCOVER       1
2997dc5e69SMatthias Ringwald #define DHCP_OFFER          2
3097dc5e69SMatthias Ringwald #define DHCP_REQUEST        3
3197dc5e69SMatthias Ringwald #define DHCP_DECLINE        4
3297dc5e69SMatthias Ringwald #define DHCP_ACK            5
3397dc5e69SMatthias Ringwald #define DHCP_NAK            6
3497dc5e69SMatthias Ringwald #define DHCP_RELEASE        7
3597dc5e69SMatthias Ringwald #define DHCP_INFORM         8
3697dc5e69SMatthias Ringwald 
3797dc5e69SMatthias Ringwald /* DHCP options */
3897dc5e69SMatthias Ringwald enum DHCP_OPTIONS
3997dc5e69SMatthias Ringwald {
4097dc5e69SMatthias Ringwald 	DHCP_PAD                    = 0,
4197dc5e69SMatthias Ringwald 	DHCP_SUBNETMASK             = 1,
4297dc5e69SMatthias Ringwald 	DHCP_ROUTER                 = 3,
4397dc5e69SMatthias Ringwald 	DHCP_DNSSERVER              = 6,
4497dc5e69SMatthias Ringwald 	DHCP_HOSTNAME               = 12,
4597dc5e69SMatthias Ringwald 	DHCP_DNSDOMAIN              = 15,
4697dc5e69SMatthias Ringwald 	DHCP_MTU                    = 26,
4797dc5e69SMatthias Ringwald 	DHCP_BROADCAST              = 28,
4897dc5e69SMatthias Ringwald 	DHCP_PERFORMROUTERDISC      = 31,
4997dc5e69SMatthias Ringwald 	DHCP_STATICROUTE            = 33,
5097dc5e69SMatthias Ringwald 	DHCP_NISDOMAIN              = 40,
5197dc5e69SMatthias Ringwald 	DHCP_NISSERVER              = 41,
5297dc5e69SMatthias Ringwald 	DHCP_NTPSERVER              = 42,
5397dc5e69SMatthias Ringwald 	DHCP_VENDOR                 = 43,
5497dc5e69SMatthias Ringwald 	DHCP_IPADDRESS              = 50,
5597dc5e69SMatthias Ringwald 	DHCP_LEASETIME              = 51,
5697dc5e69SMatthias Ringwald 	DHCP_OPTIONSOVERLOADED      = 52,
5797dc5e69SMatthias Ringwald 	DHCP_MESSAGETYPE            = 53,
5897dc5e69SMatthias Ringwald 	DHCP_SERVERID               = 54,
5997dc5e69SMatthias Ringwald 	DHCP_PARAMETERREQUESTLIST   = 55,
6097dc5e69SMatthias Ringwald 	DHCP_MESSAGE                = 56,
6197dc5e69SMatthias Ringwald 	DHCP_MAXMESSAGESIZE         = 57,
6297dc5e69SMatthias Ringwald 	DHCP_RENEWALTIME            = 58,
6397dc5e69SMatthias Ringwald 	DHCP_REBINDTIME             = 59,
6497dc5e69SMatthias Ringwald 	DHCP_CLASSID                = 60,
6597dc5e69SMatthias Ringwald 	DHCP_CLIENTID               = 61,
6697dc5e69SMatthias Ringwald 	DHCP_USERCLASS              = 77,  /* RFC 3004 */
6797dc5e69SMatthias Ringwald 	DHCP_FQDN                   = 81,
6897dc5e69SMatthias Ringwald 	DHCP_DNSSEARCH              = 119, /* RFC 3397 */
6997dc5e69SMatthias Ringwald 	DHCP_CSR                    = 121, /* RFC 3442 */
7097dc5e69SMatthias Ringwald 	DHCP_MSCSR                  = 249, /* MS code for RFC 3442 */
7197dc5e69SMatthias Ringwald 	DHCP_END                    = 255
7297dc5e69SMatthias Ringwald };
7397dc5e69SMatthias Ringwald 
7497dc5e69SMatthias Ringwald typedef struct
7597dc5e69SMatthias Ringwald {
7697dc5e69SMatthias Ringwald     uint8_t  dp_op;           /* packet opcode type */
7797dc5e69SMatthias Ringwald     uint8_t  dp_htype;        /* hardware addr type */
7897dc5e69SMatthias Ringwald     uint8_t  dp_hlen;         /* hardware addr length */
7997dc5e69SMatthias Ringwald     uint8_t  dp_hops;         /* gateway hops */
8097dc5e69SMatthias Ringwald     uint32_t dp_xid;          /* transaction ID */
8197dc5e69SMatthias Ringwald     uint16_t dp_secs;         /* seconds since boot began */
8297dc5e69SMatthias Ringwald     uint16_t dp_flags;
8397dc5e69SMatthias Ringwald     uint8_t  dp_ciaddr[4];    /* client IP address */
8497dc5e69SMatthias Ringwald     uint8_t  dp_yiaddr[4];    /* 'your' IP address */
8597dc5e69SMatthias Ringwald     uint8_t  dp_siaddr[4];    /* server IP address */
8697dc5e69SMatthias Ringwald     uint8_t  dp_giaddr[4];    /* gateway IP address */
8797dc5e69SMatthias Ringwald     uint8_t  dp_chaddr[16];   /* client hardware address */
8897dc5e69SMatthias Ringwald     uint8_t  dp_legacy[192];
8997dc5e69SMatthias Ringwald     uint8_t  dp_magic[4];
9097dc5e69SMatthias Ringwald     uint8_t  dp_options[275]; /* options area */
9197dc5e69SMatthias Ringwald } DHCP_TYPE;
9297dc5e69SMatthias Ringwald 
9397dc5e69SMatthias Ringwald DHCP_TYPE dhcp_data;
9497dc5e69SMatthias Ringwald static struct udp_pcb *pcb = NULL;
9597dc5e69SMatthias Ringwald static dhcp_config_t *config = NULL;
9697dc5e69SMatthias Ringwald 
9797dc5e69SMatthias Ringwald char magic_cookie[] = {0x63,0x82,0x53,0x63};
9897dc5e69SMatthias Ringwald 
get_addr32(const uint8_t addr[4])99e3ba2290SPeter Harper static uint32_t get_addr32(const uint8_t addr[4]) {
100e3ba2290SPeter Harper 	return PP_HTONL(LWIP_MAKEU32(addr[0],addr[1],addr[2],addr[3]));
101e3ba2290SPeter Harper }
102e3ba2290SPeter Harper 
set_addr32(uint8_t * dst,uint32_t src)103e3ba2290SPeter Harper static void set_addr32(uint8_t *dst, uint32_t src) {
104e3ba2290SPeter Harper 	memcpy(dst, &src, 4);
105e3ba2290SPeter Harper }
106e3ba2290SPeter Harper 
entry_by_ip(uint32_t ip)10797dc5e69SMatthias Ringwald static dhcp_entry_t *entry_by_ip(uint32_t ip)
10897dc5e69SMatthias Ringwald {
10997dc5e69SMatthias Ringwald 	int i;
11097dc5e69SMatthias Ringwald 	for (i = 0; i < config->num_entry; i++)
111e3ba2290SPeter Harper 		if (get_addr32(config->entries[i].addr) == ip)
11297dc5e69SMatthias Ringwald 			return &config->entries[i];
11397dc5e69SMatthias Ringwald 	return NULL;
11497dc5e69SMatthias Ringwald }
11597dc5e69SMatthias Ringwald 
entry_by_mac(uint8_t * mac)11697dc5e69SMatthias Ringwald static dhcp_entry_t *entry_by_mac(uint8_t *mac)
11797dc5e69SMatthias Ringwald {
11897dc5e69SMatthias Ringwald 	int i;
11997dc5e69SMatthias Ringwald 	for (i = 0; i < config->num_entry; i++)
12097dc5e69SMatthias Ringwald 		if (memcmp(config->entries[i].mac, mac, 6) == 0)
12197dc5e69SMatthias Ringwald 			return &config->entries[i];
12297dc5e69SMatthias Ringwald 	return NULL;
12397dc5e69SMatthias Ringwald }
12497dc5e69SMatthias Ringwald 
is_vacant(dhcp_entry_t * entry)12597dc5e69SMatthias Ringwald static __inline bool is_vacant(dhcp_entry_t *entry)
12697dc5e69SMatthias Ringwald {
12797dc5e69SMatthias Ringwald 	return memcmp("\0\0\0\0\0", entry->mac, 6) == 0;
12897dc5e69SMatthias Ringwald }
12997dc5e69SMatthias Ringwald 
vacant_address(void)130946d87baSMatthias Ringwald static dhcp_entry_t *vacant_address(void)
13197dc5e69SMatthias Ringwald {
13297dc5e69SMatthias Ringwald 	int i;
13397dc5e69SMatthias Ringwald 	for (i = 0; i < config->num_entry; i++)
13497dc5e69SMatthias Ringwald 		if (is_vacant(config->entries + i))
13597dc5e69SMatthias Ringwald 			return config->entries + i;
13697dc5e69SMatthias Ringwald 	return NULL;
13797dc5e69SMatthias Ringwald }
13897dc5e69SMatthias Ringwald 
free_entry(dhcp_entry_t * entry)13997dc5e69SMatthias Ringwald static __inline void free_entry(dhcp_entry_t *entry)
14097dc5e69SMatthias Ringwald {
14197dc5e69SMatthias Ringwald 	memset(entry->mac, 0, 6);
14297dc5e69SMatthias Ringwald }
14397dc5e69SMatthias Ringwald 
find_dhcp_option(uint8_t * attrs,int size,uint8_t attr)14497dc5e69SMatthias Ringwald static uint8_t *find_dhcp_option(uint8_t *attrs, int size, uint8_t attr)
14597dc5e69SMatthias Ringwald {
14697dc5e69SMatthias Ringwald 	int i = 0;
14797dc5e69SMatthias Ringwald 	while ((i + 1) < size)
14897dc5e69SMatthias Ringwald 	{
14997dc5e69SMatthias Ringwald 		int next = i + attrs[i + 1] + 2;
15097dc5e69SMatthias Ringwald 		if (next > size) return NULL;
15197dc5e69SMatthias Ringwald 		if (attrs[i] == attr)
15297dc5e69SMatthias Ringwald 			return attrs + i;
15397dc5e69SMatthias Ringwald 		i = next;
15497dc5e69SMatthias Ringwald 	}
15597dc5e69SMatthias Ringwald 	return NULL;
15697dc5e69SMatthias Ringwald }
15797dc5e69SMatthias Ringwald 
fill_options(void * dest,uint8_t msg_type,const char * domain,uint32_t dns,int lease_time,uint32_t serverid,uint32_t router,uint32_t subnet)15897dc5e69SMatthias Ringwald static int fill_options(void *dest,
15997dc5e69SMatthias Ringwald 	uint8_t msg_type,
16097dc5e69SMatthias Ringwald 	const char *domain,
16197dc5e69SMatthias Ringwald 	uint32_t dns,
16297dc5e69SMatthias Ringwald 	int lease_time,
16397dc5e69SMatthias Ringwald 	uint32_t serverid,
16497dc5e69SMatthias Ringwald 	uint32_t router,
16597dc5e69SMatthias Ringwald 	uint32_t subnet)
16697dc5e69SMatthias Ringwald {
16797dc5e69SMatthias Ringwald 	uint8_t *ptr = (uint8_t *)dest;
16897dc5e69SMatthias Ringwald 	/* ACK message type */
16997dc5e69SMatthias Ringwald 	*ptr++ = 53;
17097dc5e69SMatthias Ringwald 	*ptr++ = 1;
17197dc5e69SMatthias Ringwald 	*ptr++ = msg_type;
17297dc5e69SMatthias Ringwald 
17397dc5e69SMatthias Ringwald 	/* dhcp server identifier */
17497dc5e69SMatthias Ringwald 	*ptr++ = DHCP_SERVERID;
17597dc5e69SMatthias Ringwald 	*ptr++ = 4;
176e3ba2290SPeter Harper 	set_addr32(ptr, serverid);
17797dc5e69SMatthias Ringwald 	ptr += 4;
17897dc5e69SMatthias Ringwald 
17997dc5e69SMatthias Ringwald 	/* lease time */
18097dc5e69SMatthias Ringwald 	*ptr++ = DHCP_LEASETIME;
18197dc5e69SMatthias Ringwald 	*ptr++ = 4;
18297dc5e69SMatthias Ringwald 	*ptr++ = (lease_time >> 24) & 0xFF;
18397dc5e69SMatthias Ringwald 	*ptr++ = (lease_time >> 16) & 0xFF;
18497dc5e69SMatthias Ringwald 	*ptr++ = (lease_time >> 8) & 0xFF;
18597dc5e69SMatthias Ringwald 	*ptr++ = (lease_time >> 0) & 0xFF;
18697dc5e69SMatthias Ringwald 
18797dc5e69SMatthias Ringwald 	/* subnet mask */
18897dc5e69SMatthias Ringwald 	*ptr++ = DHCP_SUBNETMASK;
18997dc5e69SMatthias Ringwald 	*ptr++ = 4;
190e3ba2290SPeter Harper 	set_addr32(ptr, subnet);
19197dc5e69SMatthias Ringwald 	ptr += 4;
19297dc5e69SMatthias Ringwald 
19397dc5e69SMatthias Ringwald 	/* router */
19497dc5e69SMatthias Ringwald 	if (router != 0)
19597dc5e69SMatthias Ringwald 	{
19697dc5e69SMatthias Ringwald 		*ptr++ = DHCP_ROUTER;
19797dc5e69SMatthias Ringwald 		*ptr++ = 4;
198e3ba2290SPeter Harper 		set_addr32(ptr, router);
19997dc5e69SMatthias Ringwald 		ptr += 4;
20097dc5e69SMatthias Ringwald 	}
20197dc5e69SMatthias Ringwald 
20297dc5e69SMatthias Ringwald 	/* domain name */
20397dc5e69SMatthias Ringwald 	if (domain != NULL)
20497dc5e69SMatthias Ringwald 	{
20597dc5e69SMatthias Ringwald 		int len = strlen(domain);
20697dc5e69SMatthias Ringwald 		*ptr++ = DHCP_DNSDOMAIN;
20797dc5e69SMatthias Ringwald 		*ptr++ = len;
20897dc5e69SMatthias Ringwald 		memcpy(ptr, domain, len);
20997dc5e69SMatthias Ringwald 		ptr += len;
21097dc5e69SMatthias Ringwald 	}
21197dc5e69SMatthias Ringwald 
21297dc5e69SMatthias Ringwald 	/* domain name server (DNS) */
21397dc5e69SMatthias Ringwald 	if (dns != 0)
21497dc5e69SMatthias Ringwald 	{
21597dc5e69SMatthias Ringwald 		*ptr++ = DHCP_DNSSERVER;
21697dc5e69SMatthias Ringwald 		*ptr++ = 4;
217e3ba2290SPeter Harper 		set_addr32(ptr, dns);
21897dc5e69SMatthias Ringwald 		ptr += 4;
21997dc5e69SMatthias Ringwald 	}
22097dc5e69SMatthias Ringwald 
22197dc5e69SMatthias Ringwald 	/* end */
22297dc5e69SMatthias Ringwald 	*ptr++ = DHCP_END;
22397dc5e69SMatthias Ringwald 	return ptr - (uint8_t *)dest;
22497dc5e69SMatthias Ringwald }
22597dc5e69SMatthias Ringwald 
udp_recv_proc(void * arg,struct udp_pcb * upcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)22677da83a6SMatthias Ringwald static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
22797dc5e69SMatthias Ringwald {
22897dc5e69SMatthias Ringwald 	(void) arg;
22997dc5e69SMatthias Ringwald 	(void) addr;
23097dc5e69SMatthias Ringwald 
23197dc5e69SMatthias Ringwald 	uint8_t *ptr;
23297dc5e69SMatthias Ringwald 	dhcp_entry_t *entry;
23397dc5e69SMatthias Ringwald 	struct pbuf *pp;
234*88cd6730SPeter Harper 	struct netif *nif;
23597dc5e69SMatthias Ringwald 
23697dc5e69SMatthias Ringwald 	unsigned int n = p->len;
23797dc5e69SMatthias Ringwald 	if (n > sizeof(dhcp_data)) n = sizeof(dhcp_data);
23897dc5e69SMatthias Ringwald 	memcpy(&dhcp_data, p->payload, n);
23997dc5e69SMatthias Ringwald 	switch (dhcp_data.dp_options[2])
24097dc5e69SMatthias Ringwald 	{
24197dc5e69SMatthias Ringwald 		case DHCP_DISCOVER:
24297dc5e69SMatthias Ringwald 			entry = entry_by_mac(dhcp_data.dp_chaddr);
24397dc5e69SMatthias Ringwald 			if (entry == NULL) entry = vacant_address();
24497dc5e69SMatthias Ringwald 			if (entry == NULL) break;
24597dc5e69SMatthias Ringwald 
24697dc5e69SMatthias Ringwald 			dhcp_data.dp_op = 2; /* reply */
24797dc5e69SMatthias Ringwald 			dhcp_data.dp_secs = 0;
24897dc5e69SMatthias Ringwald 			dhcp_data.dp_flags = 0;
249e3ba2290SPeter Harper 			set_addr32(dhcp_data.dp_yiaddr, get_addr32(entry->addr));
25097dc5e69SMatthias Ringwald 			memcpy(dhcp_data.dp_magic, magic_cookie, 4);
25197dc5e69SMatthias Ringwald 
25297dc5e69SMatthias Ringwald 			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));
25397dc5e69SMatthias Ringwald 
25497dc5e69SMatthias Ringwald 			fill_options(dhcp_data.dp_options,
25597dc5e69SMatthias Ringwald 				DHCP_OFFER,
25697dc5e69SMatthias Ringwald 				config->domain,
257e3ba2290SPeter Harper 				get_addr32(config->dns),
25897dc5e69SMatthias Ringwald 				entry->lease,
259e3ba2290SPeter Harper 				get_addr32(config->addr),
260e3ba2290SPeter Harper 				get_addr32(config->addr),
261e3ba2290SPeter Harper 				get_addr32(entry->subnet));
26297dc5e69SMatthias Ringwald 
26397dc5e69SMatthias Ringwald 			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
26497dc5e69SMatthias Ringwald 			if (pp == NULL) break;
26597dc5e69SMatthias Ringwald 			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
266*88cd6730SPeter Harper 			nif = ip_current_input_netif();
267*88cd6730SPeter Harper 			if (nif) {
268*88cd6730SPeter Harper 				udp_sendto_if(upcb, pp, IP_ADDR_BROADCAST, port, nif);
269*88cd6730SPeter Harper 			} else {
27097dc5e69SMatthias Ringwald 				udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
271*88cd6730SPeter Harper 			}
27297dc5e69SMatthias Ringwald 			pbuf_free(pp);
27397dc5e69SMatthias Ringwald 			break;
27497dc5e69SMatthias Ringwald 
27597dc5e69SMatthias Ringwald 		case DHCP_REQUEST:
27697dc5e69SMatthias Ringwald 			/* 1. find requested ipaddr in option list */
27797dc5e69SMatthias Ringwald 			ptr = find_dhcp_option(dhcp_data.dp_options, sizeof(dhcp_data.dp_options), DHCP_IPADDRESS);
27897dc5e69SMatthias Ringwald 			if (ptr == NULL) break;
27997dc5e69SMatthias Ringwald 			if (ptr[1] != 4) break;
28097dc5e69SMatthias Ringwald 			ptr += 2;
28197dc5e69SMatthias Ringwald 
28297dc5e69SMatthias Ringwald 			/* 2. does hw-address registered? */
28397dc5e69SMatthias Ringwald 			entry = entry_by_mac(dhcp_data.dp_chaddr);
28497dc5e69SMatthias Ringwald 			if (entry != NULL) free_entry(entry);
28597dc5e69SMatthias Ringwald 
28697dc5e69SMatthias Ringwald 			/* 3. find requested ipaddr */
287e3ba2290SPeter Harper 			entry = entry_by_ip(get_addr32(ptr));
28897dc5e69SMatthias Ringwald 			if (entry == NULL) break;
28997dc5e69SMatthias Ringwald 			if (!is_vacant(entry)) break;
29097dc5e69SMatthias Ringwald 
29197dc5e69SMatthias Ringwald 			/* 4. fill struct fields */
29297dc5e69SMatthias Ringwald 			memcpy(dhcp_data.dp_yiaddr, ptr, 4);
29397dc5e69SMatthias Ringwald 			dhcp_data.dp_op = 2; /* reply */
29497dc5e69SMatthias Ringwald 			dhcp_data.dp_secs = 0;
29597dc5e69SMatthias Ringwald 			dhcp_data.dp_flags = 0;
29697dc5e69SMatthias Ringwald 			memcpy(dhcp_data.dp_magic, magic_cookie, 4);
29797dc5e69SMatthias Ringwald 
29897dc5e69SMatthias Ringwald 			/* 5. fill options */
29997dc5e69SMatthias Ringwald 			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));
30097dc5e69SMatthias Ringwald 
30197dc5e69SMatthias Ringwald 			fill_options(dhcp_data.dp_options,
30297dc5e69SMatthias Ringwald 				DHCP_ACK,
30397dc5e69SMatthias Ringwald 				config->domain,
304e3ba2290SPeter Harper 				get_addr32(config->dns),
30597dc5e69SMatthias Ringwald 				entry->lease,
306e3ba2290SPeter Harper 				get_addr32(config->addr),
307e3ba2290SPeter Harper 				get_addr32(config->addr),
308e3ba2290SPeter Harper 				get_addr32(entry->subnet));
30997dc5e69SMatthias Ringwald 
31097dc5e69SMatthias Ringwald 			/* 6. send ACK */
31197dc5e69SMatthias Ringwald 			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
31297dc5e69SMatthias Ringwald 			if (pp == NULL) break;
31397dc5e69SMatthias Ringwald 			memcpy(entry->mac, dhcp_data.dp_chaddr, 6);
31497dc5e69SMatthias Ringwald 			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
315*88cd6730SPeter Harper 			nif = ip_current_input_netif();
316*88cd6730SPeter Harper 			if (nif) {
317*88cd6730SPeter Harper 				udp_sendto_if(upcb, pp, IP_ADDR_BROADCAST, port, nif);
318*88cd6730SPeter Harper 			} else {
31997dc5e69SMatthias Ringwald 				udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
320*88cd6730SPeter Harper 			}
32197dc5e69SMatthias Ringwald 			pbuf_free(pp);
32297dc5e69SMatthias Ringwald 			break;
32397dc5e69SMatthias Ringwald 
32497dc5e69SMatthias Ringwald 		default:
32597dc5e69SMatthias Ringwald 				break;
32697dc5e69SMatthias Ringwald 	}
32797dc5e69SMatthias Ringwald 	pbuf_free(p);
32897dc5e69SMatthias Ringwald }
32997dc5e69SMatthias Ringwald 
dhserv_init(dhcp_config_t * c)33097dc5e69SMatthias Ringwald err_t dhserv_init(dhcp_config_t *c)
33197dc5e69SMatthias Ringwald {
33297dc5e69SMatthias Ringwald 	err_t err;
33397dc5e69SMatthias Ringwald 	// udp_init(); already called from lwip_init
33497dc5e69SMatthias Ringwald 	dhserv_free();
33597dc5e69SMatthias Ringwald 	pcb = udp_new();
33697dc5e69SMatthias Ringwald 	if (pcb == NULL)
33797dc5e69SMatthias Ringwald 		return ERR_MEM;
33897dc5e69SMatthias Ringwald 	err = udp_bind(pcb, IP_ADDR_ANY, c->port);
33997dc5e69SMatthias Ringwald 	if (err != ERR_OK)
34097dc5e69SMatthias Ringwald 	{
34197dc5e69SMatthias Ringwald 		dhserv_free();
34297dc5e69SMatthias Ringwald 		return err;
34397dc5e69SMatthias Ringwald 	}
34497dc5e69SMatthias Ringwald 	udp_recv(pcb, udp_recv_proc, NULL);
34597dc5e69SMatthias Ringwald 	config = c;
34697dc5e69SMatthias Ringwald 	return ERR_OK;
34797dc5e69SMatthias Ringwald }
34897dc5e69SMatthias Ringwald 
dhserv_free(void)34997dc5e69SMatthias Ringwald void dhserv_free(void)
35097dc5e69SMatthias Ringwald {
35197dc5e69SMatthias Ringwald 	if (pcb == NULL) return;
35297dc5e69SMatthias Ringwald 	udp_remove(pcb);
35397dc5e69SMatthias Ringwald 	pcb = NULL;
35497dc5e69SMatthias Ringwald }
355