4 * Dynamic Host Configuration Protocol client
9 * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>
10 * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or without modification,
14 * are permitted provided that the following conditions are met:
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * 3. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 * This file is a contribution to the lwIP TCP/IP stack.
36 * The Swedish Institute of Computer Science and Adam Dunkels
37 * are specifically granted permission to redistribute this
40 * Author: Leon Woestenberg <leon.woestenberg@gmx.net>
42 * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
43 * with RFC 2131 and RFC 2132.
46 * - Proper parsing of DHCP messages exploiting file/sname field overloading.
47 * - Add JavaDoc style documentation (API, internals).
48 * - Support for interfaces other than Ethernet (SLIP, PPP, ...)
50 * Please coordinate changes and requests with Leon Woestenberg
51 * <leon.woestenberg@gmx.net>
53 * Integration with your code:
56 * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
57 * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
59 * Then have your application call dhcp_coarse_tmr() and
60 * dhcp_fine_tmr() on the defined intervals.
62 * dhcp_start(struct netif *netif);
63 * starts a DHCP client instance which configures the interface by
64 * obtaining an IP address lease and maintaining it.
66 * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
67 * to remove the DHCP client.
73 #include "lwip/stats.h"
76 #include "lwip/ip_addr.h"
77 #include "lwip/netif.h"
78 #include "lwip/inet.h"
79 #include "netif/etharp.h"
83 #include "lwip/dhcp.h"
85 #if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */
87 /** global transaction identifier, must be
88 * unique for each DHCP request. We simply increment, starting
89 * with this value (easy to match with a packet analyzer) */
90 static u32_t xid = 0xABCD0000;
92 /** DHCP client state machine functions */
93 static void dhcp_handle_ack(struct netif *netif);
94 static void dhcp_handle_nak(struct netif *netif);
95 static void dhcp_handle_offer(struct netif *netif);
97 static err_t dhcp_discover(struct netif *netif);
98 static err_t dhcp_select(struct netif *netif);
99 static void dhcp_check(struct netif *netif);
100 static void dhcp_bind(struct netif *netif);
101 static err_t dhcp_decline(struct netif *netif);
102 static err_t dhcp_rebind(struct netif *netif);
103 static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);
105 /** receive, unfold, parse and free incoming messages */
106 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
107 static err_t dhcp_unfold_reply(struct dhcp *dhcp);
108 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);
109 static u8_t dhcp_get_option_byte(u8_t *ptr);
111 static u16_t dhcp_get_option_short(u8_t *ptr);
113 static u32_t dhcp_get_option_long(u8_t *ptr);
114 static void dhcp_free_reply(struct dhcp *dhcp);
116 /** set the DHCP timers */
117 static void dhcp_timeout(struct netif *netif);
118 static void dhcp_t1_timeout(struct netif *netif);
119 static void dhcp_t2_timeout(struct netif *netif);
121 /** build outgoing messages */
122 /** create a DHCP request, fill in common headers */
123 static err_t dhcp_create_request(struct netif *netif);
124 /** free a DHCP request */
125 static void dhcp_delete_request(struct netif *netif);
126 /** add a DHCP option (type, then length in bytes) */
127 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
128 /** add option values */
129 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
130 static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
131 static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
132 /** always add the DHCP options trailer to end and pad */
133 static void dhcp_option_trailer(struct dhcp *dhcp);
136 * Back-off the DHCP client (because of a received NAK response).
138 * Back-off the DHCP client because of a received NAK. Receiving a
139 * NAK means the client asked for something non-sensible, for
140 * example when it tries to renew a lease obtained on another network.
142 * We back-off and will end up restarting a fresh DHCP negotiation later.
144 * @param state pointer to DHCP state structure
146 static void dhcp_handle_nak(struct netif *netif) {
147 struct dhcp *dhcp = netif->dhcp;
148 u16_t msecs = 10 * 1000;
149 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",
150 (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
151 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
152 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_handle_nak(): set request timeout %"U16_F" msecs\n", msecs));
153 dhcp_set_state(dhcp, DHCP_BACKING_OFF);
157 * Checks if the offered IP address is already in use.
159 * It does so by sending an ARP request for the offered address and
160 * entering CHECKING state. If no ARP reply is received within a small
161 * interval, the address is assumed to be free for use by us.
163 static void dhcp_check(struct netif *netif)
165 struct dhcp *dhcp = netif->dhcp;
168 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
169 (s16_t)netif->name[1]));
170 /* create an ARP query for the offered IP address, expecting that no host
171 responds, as the IP address should not be in use. */
172 result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
173 if (result != ERR_OK) {
174 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));
178 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
179 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
180 dhcp_set_state(dhcp, DHCP_CHECKING);
184 * Remember the configuration offered by a DHCP server.
186 * @param state pointer to DHCP state structure
188 static void dhcp_handle_offer(struct netif *netif)
190 struct dhcp *dhcp = netif->dhcp;
191 /* obtain the server address */
192 u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);
193 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
194 (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
195 if (option_ptr != NULL)
197 dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
198 LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));
199 /* remember offered address */
200 ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);
201 LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
208 * Select a DHCP server offer out of all offers.
210 * Simply select the first offer received.
212 * @param netif the netif under DHCP control
213 * @return lwIP specific error (see error.h)
215 static err_t dhcp_select(struct netif *netif)
217 struct dhcp *dhcp = netif->dhcp;
220 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
222 /* create and initialize the DHCP message header */
223 result = dhcp_create_request(netif);
224 if (result == ERR_OK)
226 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
227 dhcp_option_byte(dhcp, DHCP_REQUEST);
229 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
230 dhcp_option_short(dhcp, 576);
232 /* MUST request the offered IP address */
233 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
234 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
236 dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
237 dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
239 dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
240 dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
241 dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
242 dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
243 dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
245 dhcp_option_trailer(dhcp);
246 /* shrink the pbuf to the actual content length */
247 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
249 /* TODO: we really should bind to a specific local interface here
250 but we cannot specify an unconfigured netif as it is addressless */
251 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
252 /* send broadcast to any DHCP server */
253 udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
254 udp_send(dhcp->pcb, dhcp->p_out);
255 /* reconnect to any (or to server here?!) */
256 udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
257 dhcp_delete_request(netif);
258 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_select: REQUESTING\n"));
259 dhcp_set_state(dhcp, DHCP_REQUESTING);
261 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
264 msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;
265 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
266 LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_select(): set request timeout %"U32_F" msecs\n", msecs));
271 * The DHCP timer that checks for lease renewal/rebind timeouts.
274 void dhcp_coarse_tmr()
276 struct netif *netif = netif_list;
277 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_coarse_tmr()\n"));
278 /* iterate through all network interfaces */
279 while (netif != NULL) {
280 /* only act on DHCP configured interfaces */
281 if (netif->dhcp != NULL) {
282 /* timer is active (non zero), and triggers (zeroes) now? */
283 if (netif->dhcp->t2_timeout-- == 1) {
284 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
285 /* this clients' rebind timeout triggered */
286 dhcp_t2_timeout(netif);
287 /* timer is active (non zero), and triggers (zeroes) now */
288 } else if (netif->dhcp->t1_timeout-- == 1) {
289 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
290 /* this clients' renewal timeout triggered */
291 dhcp_t1_timeout(netif);
294 /* proceed to next netif */
300 * DHCP transaction timeout handling
302 * A DHCP server is expected to respond within a short period of time.
303 * This timer checks whether an outstanding DHCP request is timed out.
308 struct netif *netif = netif_list;
309 /* loop through netif's */
310 while (netif != NULL) {
311 /* only act on DHCP configured interfaces */
312 if (netif->dhcp != NULL) {
313 /* timer is active (non zero), and is about to trigger now */
314 if (netif->dhcp->request_timeout > 1) {
315 netif->dhcp->request_timeout--;
317 else if (netif->dhcp->request_timeout == 1) {
318 netif->dhcp->request_timeout--;
319 /* { netif->dhcp->request_timeout == 0 } */
320 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
321 /* this clients' request timeout triggered */
325 /* proceed to next network interface */
331 * A DHCP negotiation transaction, or ARP request, has timed out.
333 * The timer that was started with the DHCP or ARP request has
334 * timed out, indicating no response was received in time.
336 * @param netif the netif under DHCP control
339 static void dhcp_timeout(struct netif *netif)
341 struct dhcp *dhcp = netif->dhcp;
342 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_timeout()\n"));
343 /* back-off period has passed, or server selection timed out */
344 if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
345 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
346 dhcp_discover(netif);
347 /* receiving the requested lease timed out */
348 } else if (dhcp->state == DHCP_REQUESTING) {
349 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
350 if (dhcp->tries <= 5) {
353 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
355 dhcp_discover(netif);
357 /* received no ARP reply for the offered address (which is good) */
358 } else if (dhcp->state == DHCP_CHECKING) {
359 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
360 if (dhcp->tries <= 1) {
362 /* no ARP replies on the offered address,
363 looks like the IP address is indeed free */
365 /* bind the interface to the offered address */
369 /* did not get response to renew request? */
370 else if (dhcp->state == DHCP_RENEWING) {
371 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));
372 /* just retry renewal */
373 /* note that the rebind timer will eventually time-out if renew does not work */
375 /* did not get response to rebind request? */
376 } else if (dhcp->state == DHCP_REBINDING) {
377 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));
378 if (dhcp->tries <= 8) {
381 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
383 dhcp_discover(netif);
389 * The renewal period has timed out.
391 * @param netif the netif under DHCP control
393 static void dhcp_t1_timeout(struct netif *netif)
395 struct dhcp *dhcp = netif->dhcp;
396 LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_t1_timeout()\n"));
397 if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
398 /* just retry to renew - note that the rebind timer (t2) will
399 * eventually time-out if renew tries fail. */
400 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));
406 * The rebind period has timed out.
409 static void dhcp_t2_timeout(struct netif *netif)
411 struct dhcp *dhcp = netif->dhcp;
412 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout()\n"));
413 if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
414 /* just retry to rebind */
415 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));
422 * @param netif the netif under DHCP control
424 static void dhcp_handle_ack(struct netif *netif)
426 struct dhcp *dhcp = netif->dhcp;
428 /* clear options we might not get from the ACK */
429 dhcp->offered_sn_mask.addr = 0;
430 dhcp->offered_gw_addr.addr = 0;
431 dhcp->offered_bc_addr.addr = 0;
433 /* lease time given? */
434 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);
435 if (option_ptr != NULL) {
436 /* remember offered lease time */
437 dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);
439 /* renewal period given? */
440 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);
441 if (option_ptr != NULL) {
442 /* remember given renewal period */
443 dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);
445 /* calculate safe periods for renewal */
446 dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
449 /* renewal period given? */
450 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);
451 if (option_ptr != NULL) {
452 /* remember given rebind period */
453 dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);
455 /* calculate safe periods for rebinding */
456 dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
459 /* (y)our internet address */
460 ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);
464 * TODO: we must check if the file field is not overloaded by DHCP options!
467 /* boot server address */
468 ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);
470 if (dhcp->msg_in->file[0]) {
471 dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);
472 strcpy(dhcp->boot_file_name, dhcp->msg_in->file);
477 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);
478 /* subnet mask given? */
479 if (option_ptr != NULL) {
480 dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
484 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);
485 if (option_ptr != NULL) {
486 dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
489 /* broadcast address */
490 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);
491 if (option_ptr != NULL) {
492 dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
496 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);
497 if (option_ptr != NULL) {
499 dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);
500 /* limit to at most DHCP_MAX_DNS DNS servers */
501 if (dhcp->dns_count > DHCP_MAX_DNS)
502 dhcp->dns_count = DHCP_MAX_DNS;
503 for (n = 0; n < dhcp->dns_count; n++) {
504 dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));
510 * Start DHCP negotiation for a network interface.
512 * If no DHCP client instance was attached to this interface,
513 * a new client is created first. If a DHCP client instance
514 * was already present, it restarts negotiation.
516 * @param netif The lwIP network interface
517 * @return lwIP error code
518 * - ERR_OK - No error
519 * - ERR_MEM - Out of memory
522 err_t dhcp_start(struct netif *netif)
524 struct dhcp *dhcp = netif->dhcp;
525 err_t result = ERR_OK;
527 LWIP_ASSERT("netif != NULL", netif != NULL);
528 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
529 netif->flags &= ~NETIF_FLAG_DHCP;
531 /* no DHCP client attached yet? */
533 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
534 dhcp = mem_malloc(sizeof(struct dhcp));
536 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
539 /* store this dhcp client in the netif */
541 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));
542 /* already has DHCP client attached */
544 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
547 /* clear data structure */
548 memset(dhcp, 0, sizeof(struct dhcp));
549 /* allocate UDP PCB */
550 dhcp->pcb = udp_new();
551 if (dhcp->pcb == NULL) {
552 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
553 mem_free((void *)dhcp);
554 netif->dhcp = dhcp = NULL;
557 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
558 /* (re)start the DHCP negotiation */
559 result = dhcp_discover(netif);
560 if (result != ERR_OK) {
561 /* free resources allocated above */
565 netif->flags |= NETIF_FLAG_DHCP;
570 * Inform a DHCP server of our manual configuration.
572 * This informs DHCP servers of our fixed IP address configuration
573 * by sending an INFORM message. It does not involve DHCP address
574 * configuration, it is just here to be nice to the network.
576 * @param netif The lwIP network interface
579 void dhcp_inform(struct netif *netif)
582 err_t result = ERR_OK;
583 dhcp = mem_malloc(sizeof(struct dhcp));
585 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));
589 memset(dhcp, 0, sizeof(struct dhcp));
591 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));
592 dhcp->pcb = udp_new();
593 if (dhcp->pcb == NULL) {
594 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));
595 mem_free((void *)dhcp);
598 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
599 /* create and initialize the DHCP message header */
600 result = dhcp_create_request(netif);
601 if (result == ERR_OK) {
603 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
604 dhcp_option_byte(dhcp, DHCP_INFORM);
606 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
607 /* TODO: use netif->mtu ?! */
608 dhcp_option_short(dhcp, 576);
610 dhcp_option_trailer(dhcp);
612 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
614 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
615 udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
616 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_inform: INFORMING\n"));
617 udp_send(dhcp->pcb, dhcp->p_out);
618 udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
619 dhcp_delete_request(netif);
621 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
626 if (dhcp->pcb != NULL) udp_remove(dhcp->pcb);
628 mem_free((void *)dhcp);
633 #if DHCP_DOES_ARP_CHECK
635 * Match an ARP reply with the offered IP address.
637 * @param addr The IP address we received a reply from
640 void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
642 LWIP_ASSERT("netif != NULL", netif != NULL);
643 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_arp_reply()\n"));
644 /* is a DHCP client doing an ARP check? */
645 if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {
646 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));
647 /* did a host respond with the address we
648 were offered by the DHCP server? */
649 if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
650 /* we will not accept the offered address */
651 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
658 * Decline an offered lease.
660 * Tell the DHCP server we do not accept the offered address.
661 * One reason to decline the lease is when we find out the address
662 * is already in use by another host (through ARP).
664 static err_t dhcp_decline(struct netif *netif)
666 struct dhcp *dhcp = netif->dhcp;
667 err_t result = ERR_OK;
669 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_decline()\n"));
670 dhcp_set_state(dhcp, DHCP_BACKING_OFF);
671 /* create and initialize the DHCP message header */
672 result = dhcp_create_request(netif);
673 if (result == ERR_OK)
675 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
676 dhcp_option_byte(dhcp, DHCP_DECLINE);
678 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
679 dhcp_option_short(dhcp, 576);
681 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
682 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
684 dhcp_option_trailer(dhcp);
685 /* resize pbuf to reflect true size of options */
686 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
688 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
689 /* @todo: should we really connect here? we are performing sendto() */
690 udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
691 /* per section 4.4.4, broadcast DECLINE messages */
692 udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
693 dhcp_delete_request(netif);
694 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
696 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));
700 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
701 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));
708 * Start the DHCP process, discover a DHCP server.
711 static err_t dhcp_discover(struct netif *netif)
713 struct dhcp *dhcp = netif->dhcp;
714 err_t result = ERR_OK;
716 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_discover()\n"));
717 ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
718 /* create and initialize the DHCP message header */
719 result = dhcp_create_request(netif);
720 if (result == ERR_OK)
722 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: making request\n"));
723 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
724 dhcp_option_byte(dhcp, DHCP_DISCOVER);
726 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
727 dhcp_option_short(dhcp, 576);
729 dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
730 dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
731 dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
732 dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
733 dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
735 dhcp_option_trailer(dhcp);
737 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
738 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
740 /* set receive callback function with netif as user data */
741 udp_recv(dhcp->pcb, dhcp_recv, netif);
742 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
743 udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
744 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
745 udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
746 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
747 dhcp_delete_request(netif);
748 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover: SELECTING\n"));
749 dhcp_set_state(dhcp, DHCP_SELECTING);
751 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
754 msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;
755 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
756 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));
762 * Bind the interface to the offered IP address.
764 * @param netif network interface to bind to the offered address
766 static void dhcp_bind(struct netif *netif)
768 struct dhcp *dhcp = netif->dhcp;
769 struct ip_addr sn_mask, gw_addr;
770 LWIP_ASSERT("dhcp_bind: netif != NULL", netif != NULL);
771 LWIP_ASSERT("dhcp_bind: dhcp != NULL", dhcp != NULL);
772 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
774 /* temporary DHCP lease? */
775 if (dhcp->offered_t1_renew != 0xffffffffUL) {
776 /* set renewal period timer */
777 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));
778 dhcp->t1_timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
779 if (dhcp->t1_timeout == 0) dhcp->t1_timeout = 1;
780 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));
782 /* set renewal period timer */
783 if (dhcp->offered_t2_rebind != 0xffffffffUL) {
784 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));
785 dhcp->t2_timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
786 if (dhcp->t2_timeout == 0) dhcp->t2_timeout = 1;
787 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));
789 /* copy offered network mask */
790 ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);
792 /* subnet mask not given? */
793 /* TODO: this is not a valid check. what if the network mask is 0? */
794 if (sn_mask.addr == 0) {
795 /* choose a safe subnet mask given the network class */
796 u8_t first_octet = ip4_addr1(&sn_mask);
797 if (first_octet <= 127) sn_mask.addr = htonl(0xff000000);
798 else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00);
799 else sn_mask.addr = htonl(0xffff0000);
802 ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);
803 /* gateway address not given? */
804 if (gw_addr.addr == 0) {
805 /* copy network address */
806 gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);
807 /* use first host address on network as gateway */
808 gw_addr.addr |= htonl(0x00000001);
811 LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
812 netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
813 LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));
814 netif_set_netmask(netif, &sn_mask);
815 LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));
816 netif_set_gw(netif, &gw_addr);
817 /* bring the interface up */
819 /* netif is now bound to DHCP leased address */
820 dhcp_set_state(dhcp, DHCP_BOUND);
824 * Renew an existing DHCP lease at the involved DHCP server.
826 * @param netif network interface which must renew its lease
828 err_t dhcp_renew(struct netif *netif)
830 struct dhcp *dhcp = netif->dhcp;
833 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_renew()\n"));
834 dhcp_set_state(dhcp, DHCP_RENEWING);
836 /* create and initialize the DHCP message header */
837 result = dhcp_create_request(netif);
838 if (result == ERR_OK) {
840 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
841 dhcp_option_byte(dhcp, DHCP_REQUEST);
843 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
844 /* TODO: use netif->mtu in some way */
845 dhcp_option_short(dhcp, 576);
848 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
849 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
853 dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
854 dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
856 /* append DHCP message trailer */
857 dhcp_option_trailer(dhcp);
859 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
861 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
862 udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
863 udp_send(dhcp->pcb, dhcp->p_out);
864 dhcp_delete_request(netif);
866 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew: RENEWING\n"));
868 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));
871 /* back-off on retries, but to a maximum of 20 seconds */
872 msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;
873 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
874 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));
879 * Rebind with a DHCP server for an existing DHCP lease.
881 * @param netif network interface which must rebind with a DHCP server
883 static err_t dhcp_rebind(struct netif *netif)
885 struct dhcp *dhcp = netif->dhcp;
888 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind()\n"));
889 dhcp_set_state(dhcp, DHCP_REBINDING);
891 /* create and initialize the DHCP message header */
892 result = dhcp_create_request(netif);
893 if (result == ERR_OK)
896 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
897 dhcp_option_byte(dhcp, DHCP_REQUEST);
899 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
900 dhcp_option_short(dhcp, 576);
903 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
904 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
906 dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
907 dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
910 dhcp_option_trailer(dhcp);
912 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
914 /* set remote IP association to any DHCP server */
915 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
916 udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
917 /* broadcast to server */
918 udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
919 dhcp_delete_request(netif);
920 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind: REBINDING\n"));
922 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));
925 msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
926 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
927 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));
932 * Release a DHCP lease.
934 * @param netif network interface which must release its lease
936 err_t dhcp_release(struct netif *netif)
938 struct dhcp *dhcp = netif->dhcp;
941 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_release()\n"));
943 /* idle DHCP client */
944 dhcp_set_state(dhcp, DHCP_OFF);
945 /* clean old DHCP offer */
946 dhcp->server_ip_addr.addr = 0;
947 dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;
948 dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;
949 dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
952 /* create and initialize the DHCP message header */
953 result = dhcp_create_request(netif);
954 if (result == ERR_OK) {
955 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
956 dhcp_option_byte(dhcp, DHCP_RELEASE);
958 dhcp_option_trailer(dhcp);
960 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
962 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
963 udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
964 udp_send(dhcp->pcb, dhcp->p_out);
965 dhcp_delete_request(netif);
966 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
968 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));
971 msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
972 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
973 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));
974 /* bring the interface down */
975 netif_set_down(netif);
976 /* remove IP address from interface */
977 netif_set_ipaddr(netif, IP_ADDR_ANY);
978 netif_set_gw(netif, IP_ADDR_ANY);
979 netif_set_netmask(netif, IP_ADDR_ANY);
981 /* TODO: netif_down(netif); */
985 * Remove the DHCP client from the interface.
987 * @param netif The network interface to stop DHCP on
989 void dhcp_stop(struct netif *netif)
991 struct dhcp *dhcp = netif->dhcp;
992 LWIP_ASSERT("dhcp_stop: netif != NULL", netif != NULL);
994 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_stop()\n"));
995 /* netif is DHCP configured? */
998 if (dhcp->pcb != NULL)
1000 udp_remove(dhcp->pcb);
1003 if (dhcp->p != NULL)
1008 /* free unfolded reply */
1009 dhcp_free_reply(dhcp);
1010 mem_free((void *)dhcp);
1016 * Set the DHCP state of a DHCP client.
1018 * If the state changed, reset the number of tries.
1020 * TODO: we might also want to reset the timeout here?
1022 static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
1024 if (new_state != dhcp->state)
1026 dhcp->state = new_state;
1032 * Concatenate an option type and length field to the outgoing
1036 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
1038 LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN);
1039 dhcp->msg_out->options[dhcp->options_out_len++] = option_type;
1040 dhcp->msg_out->options[dhcp->options_out_len++] = option_len;
1043 * Concatenate a single byte to the outgoing DHCP message.
1046 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value)
1048 LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);
1049 dhcp->msg_out->options[dhcp->options_out_len++] = value;
1051 static void dhcp_option_short(struct dhcp *dhcp, u16_t value)
1053 LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN);
1054 dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff00U) >> 8;
1055 dhcp->msg_out->options[dhcp->options_out_len++] = value & 0x00ffU;
1057 static void dhcp_option_long(struct dhcp *dhcp, u32_t value)
1059 LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN);
1060 dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff000000UL) >> 24;
1061 dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x00ff0000UL) >> 16;
1062 dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x0000ff00UL) >> 8;
1063 dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x000000ffUL);
1067 * Extract the DHCP message and the DHCP options.
1069 * Extract the DHCP message and the DHCP options, each into a contiguous
1070 * piece of memory. As a DHCP message is variable sized by its options,
1071 * and also allows overriding some fields for options, the easy approach
1072 * is to first unfold the options into a conitguous piece of memory, and
1073 * use that further on.
1076 static err_t dhcp_unfold_reply(struct dhcp *dhcp)
1078 struct pbuf *p = dhcp->p;
1082 LWIP_ASSERT("dhcp->p != NULL", dhcp->p != NULL);
1083 /* free any left-overs from previous unfolds */
1084 dhcp_free_reply(dhcp);
1085 /* options present? */
1086 if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN))
1088 dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
1089 dhcp->options_in = mem_malloc(dhcp->options_in_len);
1090 if (dhcp->options_in == NULL)
1092 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
1096 dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
1097 if (dhcp->msg_in == NULL)
1099 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));
1100 mem_free((void *)dhcp->options_in);
1101 dhcp->options_in = NULL;
1105 ptr = (u8_t *)dhcp->msg_in;
1106 /* proceed through struct dhcp_msg */
1107 for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++)
1109 *ptr++ = ((u8_t *)p->payload)[j++];
1110 /* reached end of pbuf? */
1113 /* proceed to next pbuf in chain */
1118 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", i));
1119 if (dhcp->options_in != NULL) {
1120 ptr = (u8_t *)dhcp->options_in;
1121 /* proceed through options */
1122 for (i = 0; i < dhcp->options_in_len; i++) {
1123 *ptr++ = ((u8_t *)p->payload)[j++];
1124 /* reached end of pbuf? */
1126 /* proceed to next pbuf in chain */
1131 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", i));
1137 * Free the incoming DHCP message including contiguous copy of
1141 static void dhcp_free_reply(struct dhcp *dhcp)
1143 if (dhcp->msg_in != NULL) {
1144 mem_free((void *)dhcp->msg_in);
1145 dhcp->msg_in = NULL;
1147 if (dhcp->options_in) {
1148 mem_free((void *)dhcp->options_in);
1149 dhcp->options_in = NULL;
1150 dhcp->options_in_len = 0;
1152 LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));
1157 * If an incoming DHCP message is in response to us, then trigger the state machine
1159 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
1161 struct netif *netif = (struct netif *)arg;
1162 struct dhcp *dhcp = netif->dhcp;
1163 struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
1167 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
1168 (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),
1169 (u16_t)(ntohl(addr->addr) >> 8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));
1170 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
1171 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
1172 /* prevent warnings about unused arguments */
1173 (void)pcb; (void)addr; (void)port;
1175 /* TODO: check packet length before reading them */
1176 if (reply_msg->op != DHCP_BOOTREPLY) {
1177 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
1182 /* iterate through hardware address and match against DHCP message */
1183 for (i = 0; i < netif->hwaddr_len; i++) {
1184 if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
1185 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
1186 (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
1192 /* match transaction ID against what we expected */
1193 if (ntohl(reply_msg->xid) != dhcp->xid) {
1194 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
1199 /* option fields could be unfold? */
1200 if (dhcp_unfold_reply(dhcp) != ERR_OK) {
1201 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));
1207 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
1208 /* obtain pointer to DHCP message type */
1209 options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);
1210 if (options_ptr == NULL) {
1211 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
1217 /* read DHCP message type */
1218 msg_type = dhcp_get_option_byte(options_ptr + 2);
1219 /* message type is DHCP ACK? */
1220 if (msg_type == DHCP_ACK) {
1221 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_ACK received\n"));
1222 /* in requesting state? */
1223 if (dhcp->state == DHCP_REQUESTING) {
1224 dhcp_handle_ack(netif);
1225 dhcp->request_timeout = 0;
1226 #if DHCP_DOES_ARP_CHECK
1227 /* check if the acknowledged lease address is already in use */
1230 /* bind interface to the acknowledged lease address */
1234 /* already bound to the given lease address? */
1235 else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
1236 dhcp->request_timeout = 0;
1240 /* received a DHCP_NAK in appropriate state? */
1241 else if ((msg_type == DHCP_NAK) &&
1242 ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
1243 (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) {
1244 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_NAK received\n"));
1245 dhcp->request_timeout = 0;
1246 dhcp_handle_nak(netif);
1248 /* received a DHCP_OFFER in DHCP_SELECTING state? */
1249 else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
1250 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
1251 dhcp->request_timeout = 0;
1252 /* remember offered lease */
1253 dhcp_handle_offer(netif);
1260 static err_t dhcp_create_request(struct netif *netif)
1262 struct dhcp *dhcp = netif->dhcp;
1264 LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);
1265 LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
1266 dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
1267 if (dhcp->p_out == NULL) {
1268 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));
1271 /* give unique transaction identifier to this request */
1273 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));
1275 dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
1277 dhcp->msg_out->op = DHCP_BOOTREQUEST;
1278 /* TODO: make link layer independent */
1279 dhcp->msg_out->htype = DHCP_HTYPE_ETH;
1280 /* TODO: make link layer independent */
1281 dhcp->msg_out->hlen = DHCP_HLEN_ETH;
1282 dhcp->msg_out->hops = 0;
1283 dhcp->msg_out->xid = htonl(dhcp->xid);
1284 dhcp->msg_out->secs = 0;
1285 dhcp->msg_out->flags = 0;
1286 dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;
1287 dhcp->msg_out->yiaddr.addr = 0;
1288 dhcp->msg_out->siaddr.addr = 0;
1289 dhcp->msg_out->giaddr.addr = 0;
1290 for (i = 0; i < DHCP_CHADDR_LEN; i++) {
1291 /* copy netif hardware address, pad with zeroes */
1292 dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
1294 for (i = 0; i < DHCP_SNAME_LEN; i++) dhcp->msg_out->sname[i] = 0;
1295 for (i = 0; i < DHCP_FILE_LEN; i++) dhcp->msg_out->file[i] = 0;
1296 dhcp->msg_out->cookie = htonl(0x63825363UL);
1297 dhcp->options_out_len = 0;
1298 /* fill options field with an incrementing array (for debugging purposes) */
1299 for (i = 0; i < DHCP_OPTIONS_LEN; i++) dhcp->msg_out->options[i] = i;
1303 static void dhcp_delete_request(struct netif *netif)
1305 struct dhcp *dhcp = netif->dhcp;
1306 LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
1307 LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
1308 pbuf_free(dhcp->p_out);
1310 dhcp->msg_out = NULL;
1314 * Add a DHCP message trailer
1316 * Adds the END option to the DHCP message, and if
1317 * necessary, up to three padding bytes.
1320 static void dhcp_option_trailer(struct dhcp *dhcp)
1322 LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
1323 LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
1324 dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
1325 /* packet is too small, or not 4 byte aligned? */
1326 while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
1327 /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
1328 LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
1329 /* add a fill/padding byte */
1330 dhcp->msg_out->options[dhcp->options_out_len++] = 0;
1335 * Find the offset of a DHCP option inside the DHCP message.
1337 * @param client DHCP client
1338 * @param option_type
1340 * @return a byte offset into the UDP message where the option was found, or
1341 * zero if the given option was not found.
1343 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
1345 u8_t overload = DHCP_OVERLOAD_NONE;
1347 /* options available? */
1348 if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {
1349 /* start with options field */
1350 u8_t *options = (u8_t *)dhcp->options_in;
1352 /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
1353 while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {
1354 /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
1355 /* are the sname and/or file field overloaded with options? */
1356 if (options[offset] == DHCP_OPTION_OVERLOAD) {
1357 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("overloaded message detected\n"));
1358 /* skip option type and length */
1360 overload = options[offset++];
1362 /* requested option found */
1363 else if (options[offset] == option_type) {
1364 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));
1365 return &options[offset];
1368 LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));
1369 /* skip option type */
1371 /* skip option length, and then length bytes */
1372 offset += 1 + options[offset];
1375 /* is this an overloaded message? */
1376 if (overload != DHCP_OVERLOAD_NONE) {
1378 if (overload == DHCP_OVERLOAD_FILE) {
1379 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded file field\n"));
1380 options = (u8_t *)&dhcp->msg_in->file;
1381 field_len = DHCP_FILE_LEN;
1382 } else if (overload == DHCP_OVERLOAD_SNAME) {
1383 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname field\n"));
1384 options = (u8_t *)&dhcp->msg_in->sname;
1385 field_len = DHCP_SNAME_LEN;
1386 /* TODO: check if else if () is necessary */
1388 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname and file field\n"));
1389 options = (u8_t *)&dhcp->msg_in->sname;
1390 field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;
1394 /* at least 1 byte to read and no end marker */
1395 while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {
1396 if (options[offset] == option_type) {
1397 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));
1398 return &options[offset];
1401 LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));
1402 /* skip option type */
1404 offset += 1 + options[offset];
1413 * Return the byte of DHCP option data.
1415 * @param client DHCP client.
1416 * @param ptr pointer obtained by dhcp_get_option_ptr().
1418 * @return byte value at the given address.
1420 static u8_t dhcp_get_option_byte(u8_t *ptr)
1422 LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));
1428 * Return the 16-bit value of DHCP option data.
1430 * @param client DHCP client.
1431 * @param ptr pointer obtained by dhcp_get_option_ptr().
1433 * @return byte value at the given address.
1435 static u16_t dhcp_get_option_short(u8_t *ptr)
1438 value = *ptr++ << 8;
1440 LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));
1446 * Return the 32-bit value of DHCP option data.
1448 * @param client DHCP client.
1449 * @param ptr pointer obtained by dhcp_get_option_ptr().
1451 * @return byte value at the given address.
1453 static u32_t dhcp_get_option_long(u8_t *ptr)
1456 value = (u32_t)(*ptr++) << 24;
1457 value |= (u32_t)(*ptr++) << 16;
1458 value |= (u32_t)(*ptr++) << 8;
1459 value |= (u32_t)(*ptr++);
1460 LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));
1464 #endif /* LWIP_DHCP */