xref: /btstack/3rd-party/lwip/dhcp-server/dhserver.c (revision 97dc5e692c7d94a280158af58036a0efee5b0e56)
1*97dc5e69SMatthias Ringwald /*
2*97dc5e69SMatthias Ringwald  * The MIT License (MIT)
3*97dc5e69SMatthias Ringwald  *
4*97dc5e69SMatthias Ringwald  * Copyright (c) 2015 by Sergey Fetisov <[email protected]>
5*97dc5e69SMatthias Ringwald  *
6*97dc5e69SMatthias Ringwald  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*97dc5e69SMatthias Ringwald  * of this software and associated documentation files (the "Software"), to deal
8*97dc5e69SMatthias Ringwald  * in the Software without restriction, including without limitation the rights
9*97dc5e69SMatthias Ringwald  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10*97dc5e69SMatthias Ringwald  * copies of the Software, and to permit persons to whom the Software is
11*97dc5e69SMatthias Ringwald  * furnished to do so, subject to the following conditions:
12*97dc5e69SMatthias Ringwald  *
13*97dc5e69SMatthias Ringwald  * The above copyright notice and this permission notice shall be included in all
14*97dc5e69SMatthias Ringwald  * copies or substantial portions of the Software.
15*97dc5e69SMatthias Ringwald  *
16*97dc5e69SMatthias Ringwald  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*97dc5e69SMatthias Ringwald  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*97dc5e69SMatthias Ringwald  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*97dc5e69SMatthias Ringwald  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*97dc5e69SMatthias Ringwald  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*97dc5e69SMatthias Ringwald  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*97dc5e69SMatthias Ringwald  * SOFTWARE.
23*97dc5e69SMatthias Ringwald  */
24*97dc5e69SMatthias Ringwald 
25*97dc5e69SMatthias Ringwald #include "dhserver.h"
26*97dc5e69SMatthias Ringwald 
27*97dc5e69SMatthias Ringwald /* DHCP message type */
28*97dc5e69SMatthias Ringwald #define DHCP_DISCOVER       1
29*97dc5e69SMatthias Ringwald #define DHCP_OFFER          2
30*97dc5e69SMatthias Ringwald #define DHCP_REQUEST        3
31*97dc5e69SMatthias Ringwald #define DHCP_DECLINE        4
32*97dc5e69SMatthias Ringwald #define DHCP_ACK            5
33*97dc5e69SMatthias Ringwald #define DHCP_NAK            6
34*97dc5e69SMatthias Ringwald #define DHCP_RELEASE        7
35*97dc5e69SMatthias Ringwald #define DHCP_INFORM         8
36*97dc5e69SMatthias Ringwald 
37*97dc5e69SMatthias Ringwald /* DHCP options */
38*97dc5e69SMatthias Ringwald enum DHCP_OPTIONS
39*97dc5e69SMatthias Ringwald {
40*97dc5e69SMatthias Ringwald 	DHCP_PAD                    = 0,
41*97dc5e69SMatthias Ringwald 	DHCP_SUBNETMASK             = 1,
42*97dc5e69SMatthias Ringwald 	DHCP_ROUTER                 = 3,
43*97dc5e69SMatthias Ringwald 	DHCP_DNSSERVER              = 6,
44*97dc5e69SMatthias Ringwald 	DHCP_HOSTNAME               = 12,
45*97dc5e69SMatthias Ringwald 	DHCP_DNSDOMAIN              = 15,
46*97dc5e69SMatthias Ringwald 	DHCP_MTU                    = 26,
47*97dc5e69SMatthias Ringwald 	DHCP_BROADCAST              = 28,
48*97dc5e69SMatthias Ringwald 	DHCP_PERFORMROUTERDISC      = 31,
49*97dc5e69SMatthias Ringwald 	DHCP_STATICROUTE            = 33,
50*97dc5e69SMatthias Ringwald 	DHCP_NISDOMAIN              = 40,
51*97dc5e69SMatthias Ringwald 	DHCP_NISSERVER              = 41,
52*97dc5e69SMatthias Ringwald 	DHCP_NTPSERVER              = 42,
53*97dc5e69SMatthias Ringwald 	DHCP_VENDOR                 = 43,
54*97dc5e69SMatthias Ringwald 	DHCP_IPADDRESS              = 50,
55*97dc5e69SMatthias Ringwald 	DHCP_LEASETIME              = 51,
56*97dc5e69SMatthias Ringwald 	DHCP_OPTIONSOVERLOADED      = 52,
57*97dc5e69SMatthias Ringwald 	DHCP_MESSAGETYPE            = 53,
58*97dc5e69SMatthias Ringwald 	DHCP_SERVERID               = 54,
59*97dc5e69SMatthias Ringwald 	DHCP_PARAMETERREQUESTLIST   = 55,
60*97dc5e69SMatthias Ringwald 	DHCP_MESSAGE                = 56,
61*97dc5e69SMatthias Ringwald 	DHCP_MAXMESSAGESIZE         = 57,
62*97dc5e69SMatthias Ringwald 	DHCP_RENEWALTIME            = 58,
63*97dc5e69SMatthias Ringwald 	DHCP_REBINDTIME             = 59,
64*97dc5e69SMatthias Ringwald 	DHCP_CLASSID                = 60,
65*97dc5e69SMatthias Ringwald 	DHCP_CLIENTID               = 61,
66*97dc5e69SMatthias Ringwald 	DHCP_USERCLASS              = 77,  /* RFC 3004 */
67*97dc5e69SMatthias Ringwald 	DHCP_FQDN                   = 81,
68*97dc5e69SMatthias Ringwald 	DHCP_DNSSEARCH              = 119, /* RFC 3397 */
69*97dc5e69SMatthias Ringwald 	DHCP_CSR                    = 121, /* RFC 3442 */
70*97dc5e69SMatthias Ringwald 	DHCP_MSCSR                  = 249, /* MS code for RFC 3442 */
71*97dc5e69SMatthias Ringwald 	DHCP_END                    = 255
72*97dc5e69SMatthias Ringwald };
73*97dc5e69SMatthias Ringwald 
74*97dc5e69SMatthias Ringwald typedef struct
75*97dc5e69SMatthias Ringwald {
76*97dc5e69SMatthias Ringwald     uint8_t  dp_op;           /* packet opcode type */
77*97dc5e69SMatthias Ringwald     uint8_t  dp_htype;        /* hardware addr type */
78*97dc5e69SMatthias Ringwald     uint8_t  dp_hlen;         /* hardware addr length */
79*97dc5e69SMatthias Ringwald     uint8_t  dp_hops;         /* gateway hops */
80*97dc5e69SMatthias Ringwald     uint32_t dp_xid;          /* transaction ID */
81*97dc5e69SMatthias Ringwald     uint16_t dp_secs;         /* seconds since boot began */
82*97dc5e69SMatthias Ringwald     uint16_t dp_flags;
83*97dc5e69SMatthias Ringwald     uint8_t  dp_ciaddr[4];    /* client IP address */
84*97dc5e69SMatthias Ringwald     uint8_t  dp_yiaddr[4];    /* 'your' IP address */
85*97dc5e69SMatthias Ringwald     uint8_t  dp_siaddr[4];    /* server IP address */
86*97dc5e69SMatthias Ringwald     uint8_t  dp_giaddr[4];    /* gateway IP address */
87*97dc5e69SMatthias Ringwald     uint8_t  dp_chaddr[16];   /* client hardware address */
88*97dc5e69SMatthias Ringwald     uint8_t  dp_legacy[192];
89*97dc5e69SMatthias Ringwald     uint8_t  dp_magic[4];
90*97dc5e69SMatthias Ringwald     uint8_t  dp_options[275]; /* options area */
91*97dc5e69SMatthias Ringwald } DHCP_TYPE;
92*97dc5e69SMatthias Ringwald 
93*97dc5e69SMatthias Ringwald DHCP_TYPE dhcp_data;
94*97dc5e69SMatthias Ringwald static struct udp_pcb *pcb = NULL;
95*97dc5e69SMatthias Ringwald static dhcp_config_t *config = NULL;
96*97dc5e69SMatthias Ringwald 
97*97dc5e69SMatthias Ringwald char magic_cookie[] = {0x63,0x82,0x53,0x63};
98*97dc5e69SMatthias Ringwald 
99*97dc5e69SMatthias Ringwald static dhcp_entry_t *entry_by_ip(uint32_t ip)
100*97dc5e69SMatthias Ringwald {
101*97dc5e69SMatthias Ringwald 	int i;
102*97dc5e69SMatthias Ringwald 	for (i = 0; i < config->num_entry; i++)
103*97dc5e69SMatthias Ringwald 		if (*(uint32_t *)config->entries[i].addr == ip)
104*97dc5e69SMatthias Ringwald 			return &config->entries[i];
105*97dc5e69SMatthias Ringwald 	return NULL;
106*97dc5e69SMatthias Ringwald }
107*97dc5e69SMatthias Ringwald 
108*97dc5e69SMatthias Ringwald static dhcp_entry_t *entry_by_mac(uint8_t *mac)
109*97dc5e69SMatthias Ringwald {
110*97dc5e69SMatthias Ringwald 	int i;
111*97dc5e69SMatthias Ringwald 	for (i = 0; i < config->num_entry; i++)
112*97dc5e69SMatthias Ringwald 		if (memcmp(config->entries[i].mac, mac, 6) == 0)
113*97dc5e69SMatthias Ringwald 			return &config->entries[i];
114*97dc5e69SMatthias Ringwald 	return NULL;
115*97dc5e69SMatthias Ringwald }
116*97dc5e69SMatthias Ringwald 
117*97dc5e69SMatthias Ringwald static __inline bool is_vacant(dhcp_entry_t *entry)
118*97dc5e69SMatthias Ringwald {
119*97dc5e69SMatthias Ringwald 	return memcmp("\0\0\0\0\0", entry->mac, 6) == 0;
120*97dc5e69SMatthias Ringwald }
121*97dc5e69SMatthias Ringwald 
122*97dc5e69SMatthias Ringwald static dhcp_entry_t *vacant_address()
123*97dc5e69SMatthias Ringwald {
124*97dc5e69SMatthias Ringwald 	int i;
125*97dc5e69SMatthias Ringwald 	for (i = 0; i < config->num_entry; i++)
126*97dc5e69SMatthias Ringwald 		if (is_vacant(config->entries + i))
127*97dc5e69SMatthias Ringwald 			return config->entries + i;
128*97dc5e69SMatthias Ringwald 	return NULL;
129*97dc5e69SMatthias Ringwald }
130*97dc5e69SMatthias Ringwald 
131*97dc5e69SMatthias Ringwald static __inline void free_entry(dhcp_entry_t *entry)
132*97dc5e69SMatthias Ringwald {
133*97dc5e69SMatthias Ringwald 	memset(entry->mac, 0, 6);
134*97dc5e69SMatthias Ringwald }
135*97dc5e69SMatthias Ringwald 
136*97dc5e69SMatthias Ringwald static uint8_t *find_dhcp_option(uint8_t *attrs, int size, uint8_t attr)
137*97dc5e69SMatthias Ringwald {
138*97dc5e69SMatthias Ringwald 	int i = 0;
139*97dc5e69SMatthias Ringwald 	while ((i + 1) < size)
140*97dc5e69SMatthias Ringwald 	{
141*97dc5e69SMatthias Ringwald 		int next = i + attrs[i + 1] + 2;
142*97dc5e69SMatthias Ringwald 		if (next > size) return NULL;
143*97dc5e69SMatthias Ringwald 		if (attrs[i] == attr)
144*97dc5e69SMatthias Ringwald 			return attrs + i;
145*97dc5e69SMatthias Ringwald 		i = next;
146*97dc5e69SMatthias Ringwald 	}
147*97dc5e69SMatthias Ringwald 	return NULL;
148*97dc5e69SMatthias Ringwald }
149*97dc5e69SMatthias Ringwald 
150*97dc5e69SMatthias Ringwald static int fill_options(void *dest,
151*97dc5e69SMatthias Ringwald 	uint8_t msg_type,
152*97dc5e69SMatthias Ringwald 	const char *domain,
153*97dc5e69SMatthias Ringwald 	uint32_t dns,
154*97dc5e69SMatthias Ringwald 	int lease_time,
155*97dc5e69SMatthias Ringwald 	uint32_t serverid,
156*97dc5e69SMatthias Ringwald 	uint32_t router,
157*97dc5e69SMatthias Ringwald 	uint32_t subnet)
158*97dc5e69SMatthias Ringwald {
159*97dc5e69SMatthias Ringwald 	uint8_t *ptr = (uint8_t *)dest;
160*97dc5e69SMatthias Ringwald 	/* ACK message type */
161*97dc5e69SMatthias Ringwald 	*ptr++ = 53;
162*97dc5e69SMatthias Ringwald 	*ptr++ = 1;
163*97dc5e69SMatthias Ringwald 	*ptr++ = msg_type;
164*97dc5e69SMatthias Ringwald 
165*97dc5e69SMatthias Ringwald 	/* dhcp server identifier */
166*97dc5e69SMatthias Ringwald 	*ptr++ = DHCP_SERVERID;
167*97dc5e69SMatthias Ringwald 	*ptr++ = 4;
168*97dc5e69SMatthias Ringwald 	*(uint32_t *)ptr = serverid;
169*97dc5e69SMatthias Ringwald 	ptr += 4;
170*97dc5e69SMatthias Ringwald 
171*97dc5e69SMatthias Ringwald 	/* lease time */
172*97dc5e69SMatthias Ringwald 	*ptr++ = DHCP_LEASETIME;
173*97dc5e69SMatthias Ringwald 	*ptr++ = 4;
174*97dc5e69SMatthias Ringwald 	*ptr++ = (lease_time >> 24) & 0xFF;
175*97dc5e69SMatthias Ringwald 	*ptr++ = (lease_time >> 16) & 0xFF;
176*97dc5e69SMatthias Ringwald 	*ptr++ = (lease_time >> 8) & 0xFF;
177*97dc5e69SMatthias Ringwald 	*ptr++ = (lease_time >> 0) & 0xFF;
178*97dc5e69SMatthias Ringwald 
179*97dc5e69SMatthias Ringwald 	/* subnet mask */
180*97dc5e69SMatthias Ringwald 	*ptr++ = DHCP_SUBNETMASK;
181*97dc5e69SMatthias Ringwald 	*ptr++ = 4;
182*97dc5e69SMatthias Ringwald 	*(uint32_t *)ptr = subnet;
183*97dc5e69SMatthias Ringwald 	ptr += 4;
184*97dc5e69SMatthias Ringwald 
185*97dc5e69SMatthias Ringwald 	/* router */
186*97dc5e69SMatthias Ringwald 	if (router != 0)
187*97dc5e69SMatthias Ringwald 	{
188*97dc5e69SMatthias Ringwald 		*ptr++ = DHCP_ROUTER;
189*97dc5e69SMatthias Ringwald 		*ptr++ = 4;
190*97dc5e69SMatthias Ringwald 		*(uint32_t *)ptr = router;
191*97dc5e69SMatthias Ringwald 		ptr += 4;
192*97dc5e69SMatthias Ringwald 	}
193*97dc5e69SMatthias Ringwald 
194*97dc5e69SMatthias Ringwald 	/* domain name */
195*97dc5e69SMatthias Ringwald 	if (domain != NULL)
196*97dc5e69SMatthias Ringwald 	{
197*97dc5e69SMatthias Ringwald 		int len = strlen(domain);
198*97dc5e69SMatthias Ringwald 		*ptr++ = DHCP_DNSDOMAIN;
199*97dc5e69SMatthias Ringwald 		*ptr++ = len;
200*97dc5e69SMatthias Ringwald 		memcpy(ptr, domain, len);
201*97dc5e69SMatthias Ringwald 		ptr += len;
202*97dc5e69SMatthias Ringwald 	}
203*97dc5e69SMatthias Ringwald 
204*97dc5e69SMatthias Ringwald 	/* domain name server (DNS) */
205*97dc5e69SMatthias Ringwald 	if (dns != 0)
206*97dc5e69SMatthias Ringwald 	{
207*97dc5e69SMatthias Ringwald 		*ptr++ = DHCP_DNSSERVER;
208*97dc5e69SMatthias Ringwald 		*ptr++ = 4;
209*97dc5e69SMatthias Ringwald 		*(uint32_t *)ptr = dns;
210*97dc5e69SMatthias Ringwald 		ptr += 4;
211*97dc5e69SMatthias Ringwald 	}
212*97dc5e69SMatthias Ringwald 
213*97dc5e69SMatthias Ringwald 	/* end */
214*97dc5e69SMatthias Ringwald 	*ptr++ = DHCP_END;
215*97dc5e69SMatthias Ringwald 	return ptr - (uint8_t *)dest;
216*97dc5e69SMatthias Ringwald }
217*97dc5e69SMatthias Ringwald 
218*97dc5e69SMatthias Ringwald static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const struct ip4_addr *addr, u16_t port)
219*97dc5e69SMatthias Ringwald {
220*97dc5e69SMatthias Ringwald 	(void) arg;
221*97dc5e69SMatthias Ringwald 	(void) addr;
222*97dc5e69SMatthias Ringwald 
223*97dc5e69SMatthias Ringwald 	uint8_t *ptr;
224*97dc5e69SMatthias Ringwald 	dhcp_entry_t *entry;
225*97dc5e69SMatthias Ringwald 	struct pbuf *pp;
226*97dc5e69SMatthias Ringwald 
227*97dc5e69SMatthias Ringwald 	unsigned int n = p->len;
228*97dc5e69SMatthias Ringwald 	if (n > sizeof(dhcp_data)) n = sizeof(dhcp_data);
229*97dc5e69SMatthias Ringwald 	memcpy(&dhcp_data, p->payload, n);
230*97dc5e69SMatthias Ringwald 	switch (dhcp_data.dp_options[2])
231*97dc5e69SMatthias Ringwald 	{
232*97dc5e69SMatthias Ringwald 		case DHCP_DISCOVER:
233*97dc5e69SMatthias Ringwald 			entry = entry_by_mac(dhcp_data.dp_chaddr);
234*97dc5e69SMatthias Ringwald 			if (entry == NULL) entry = vacant_address();
235*97dc5e69SMatthias Ringwald 			if (entry == NULL) break;
236*97dc5e69SMatthias Ringwald 
237*97dc5e69SMatthias Ringwald 			dhcp_data.dp_op = 2; /* reply */
238*97dc5e69SMatthias Ringwald 			dhcp_data.dp_secs = 0;
239*97dc5e69SMatthias Ringwald 			dhcp_data.dp_flags = 0;
240*97dc5e69SMatthias Ringwald 			*(uint32_t *)dhcp_data.dp_yiaddr = *(uint32_t *)entry->addr;
241*97dc5e69SMatthias Ringwald 			memcpy(dhcp_data.dp_magic, magic_cookie, 4);
242*97dc5e69SMatthias Ringwald 
243*97dc5e69SMatthias Ringwald 			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));
244*97dc5e69SMatthias Ringwald 
245*97dc5e69SMatthias Ringwald 			fill_options(dhcp_data.dp_options,
246*97dc5e69SMatthias Ringwald 				DHCP_OFFER,
247*97dc5e69SMatthias Ringwald 				config->domain,
248*97dc5e69SMatthias Ringwald 				*(uint32_t *)config->dns,
249*97dc5e69SMatthias Ringwald 				entry->lease,
250*97dc5e69SMatthias Ringwald 				*(uint32_t *)config->addr,
251*97dc5e69SMatthias Ringwald 				*(uint32_t *)config->addr,
252*97dc5e69SMatthias Ringwald 				*(uint32_t *)entry->subnet);
253*97dc5e69SMatthias Ringwald 
254*97dc5e69SMatthias Ringwald 			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
255*97dc5e69SMatthias Ringwald 			if (pp == NULL) break;
256*97dc5e69SMatthias Ringwald 			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
257*97dc5e69SMatthias Ringwald 			udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
258*97dc5e69SMatthias Ringwald 			pbuf_free(pp);
259*97dc5e69SMatthias Ringwald 			break;
260*97dc5e69SMatthias Ringwald 
261*97dc5e69SMatthias Ringwald 		case DHCP_REQUEST:
262*97dc5e69SMatthias Ringwald 			/* 1. find requested ipaddr in option list */
263*97dc5e69SMatthias Ringwald 			ptr = find_dhcp_option(dhcp_data.dp_options, sizeof(dhcp_data.dp_options), DHCP_IPADDRESS);
264*97dc5e69SMatthias Ringwald 			if (ptr == NULL) break;
265*97dc5e69SMatthias Ringwald 			if (ptr[1] != 4) break;
266*97dc5e69SMatthias Ringwald 			ptr += 2;
267*97dc5e69SMatthias Ringwald 
268*97dc5e69SMatthias Ringwald 			/* 2. does hw-address registered? */
269*97dc5e69SMatthias Ringwald 			entry = entry_by_mac(dhcp_data.dp_chaddr);
270*97dc5e69SMatthias Ringwald 			if (entry != NULL) free_entry(entry);
271*97dc5e69SMatthias Ringwald 
272*97dc5e69SMatthias Ringwald 			/* 3. find requested ipaddr */
273*97dc5e69SMatthias Ringwald 			entry = entry_by_ip(*(uint32_t *)ptr);
274*97dc5e69SMatthias Ringwald 			if (entry == NULL) break;
275*97dc5e69SMatthias Ringwald 			if (!is_vacant(entry)) break;
276*97dc5e69SMatthias Ringwald 
277*97dc5e69SMatthias Ringwald 			/* 4. fill struct fields */
278*97dc5e69SMatthias Ringwald 			memcpy(dhcp_data.dp_yiaddr, ptr, 4);
279*97dc5e69SMatthias Ringwald 			dhcp_data.dp_op = 2; /* reply */
280*97dc5e69SMatthias Ringwald 			dhcp_data.dp_secs = 0;
281*97dc5e69SMatthias Ringwald 			dhcp_data.dp_flags = 0;
282*97dc5e69SMatthias Ringwald 			memcpy(dhcp_data.dp_magic, magic_cookie, 4);
283*97dc5e69SMatthias Ringwald 
284*97dc5e69SMatthias Ringwald 			/* 5. fill options */
285*97dc5e69SMatthias Ringwald 			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));
286*97dc5e69SMatthias Ringwald 
287*97dc5e69SMatthias Ringwald 			fill_options(dhcp_data.dp_options,
288*97dc5e69SMatthias Ringwald 				DHCP_ACK,
289*97dc5e69SMatthias Ringwald 				config->domain,
290*97dc5e69SMatthias Ringwald 				*(uint32_t *)config->dns,
291*97dc5e69SMatthias Ringwald 				entry->lease,
292*97dc5e69SMatthias Ringwald 				*(uint32_t *)config->addr,
293*97dc5e69SMatthias Ringwald 				*(uint32_t *)config->addr,
294*97dc5e69SMatthias Ringwald 				*(uint32_t *)entry->subnet);
295*97dc5e69SMatthias Ringwald 
296*97dc5e69SMatthias Ringwald 			/* 6. send ACK */
297*97dc5e69SMatthias Ringwald 			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
298*97dc5e69SMatthias Ringwald 			if (pp == NULL) break;
299*97dc5e69SMatthias Ringwald 			memcpy(entry->mac, dhcp_data.dp_chaddr, 6);
300*97dc5e69SMatthias Ringwald 			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
301*97dc5e69SMatthias Ringwald 			udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
302*97dc5e69SMatthias Ringwald 			pbuf_free(pp);
303*97dc5e69SMatthias Ringwald 			break;
304*97dc5e69SMatthias Ringwald 
305*97dc5e69SMatthias Ringwald 		default:
306*97dc5e69SMatthias Ringwald 				break;
307*97dc5e69SMatthias Ringwald 	}
308*97dc5e69SMatthias Ringwald 	pbuf_free(p);
309*97dc5e69SMatthias Ringwald }
310*97dc5e69SMatthias Ringwald 
311*97dc5e69SMatthias Ringwald err_t dhserv_init(dhcp_config_t *c)
312*97dc5e69SMatthias Ringwald {
313*97dc5e69SMatthias Ringwald 	err_t err;
314*97dc5e69SMatthias Ringwald 	// udp_init(); already called from lwip_init
315*97dc5e69SMatthias Ringwald 	dhserv_free();
316*97dc5e69SMatthias Ringwald 	pcb = udp_new();
317*97dc5e69SMatthias Ringwald 	if (pcb == NULL)
318*97dc5e69SMatthias Ringwald 		return ERR_MEM;
319*97dc5e69SMatthias Ringwald 	err = udp_bind(pcb, IP_ADDR_ANY, c->port);
320*97dc5e69SMatthias Ringwald 	if (err != ERR_OK)
321*97dc5e69SMatthias Ringwald 	{
322*97dc5e69SMatthias Ringwald 		dhserv_free();
323*97dc5e69SMatthias Ringwald 		return err;
324*97dc5e69SMatthias Ringwald 	}
325*97dc5e69SMatthias Ringwald 	udp_recv(pcb, udp_recv_proc, NULL);
326*97dc5e69SMatthias Ringwald 	config = c;
327*97dc5e69SMatthias Ringwald 	return ERR_OK;
328*97dc5e69SMatthias Ringwald }
329*97dc5e69SMatthias Ringwald 
330*97dc5e69SMatthias Ringwald void dhserv_free(void)
331*97dc5e69SMatthias Ringwald {
332*97dc5e69SMatthias Ringwald 	if (pcb == NULL) return;
333*97dc5e69SMatthias Ringwald 	udp_remove(pcb);
334*97dc5e69SMatthias Ringwald 	pcb = NULL;
335*97dc5e69SMatthias Ringwald }
336