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