]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/core/dhcp.c
2dabd4f5d3493dd6cd7d9ed58e4c28137b1af66e
[freertos] / Demo / Common / ethernet / lwIP / core / dhcp.c
1 /**
2  * @file
3  *
4  * Dynamic Host Configuration Protocol client
5  */
6
7 /*
8  *
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.
12  *
13  * Redistribution and use in source and binary forms, with or without modification,
14  * are permitted provided that the following conditions are met:
15  *
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.
23  *
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
33  * OF SUCH DAMAGE.
34  *
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
38  * source code.
39  *
40  * Author: Leon Woestenberg <leon.woestenberg@gmx.net>
41  *
42  * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
43  * with RFC 2131 and RFC 2132.
44  *
45  * TODO:
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, ...)
49  *
50  * Please coordinate changes and requests with Leon Woestenberg
51  * <leon.woestenberg@gmx.net>
52  *
53  * Integration with your code:
54  *
55  * In lwip/dhcp.h
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)
58  *
59  * Then have your application call dhcp_coarse_tmr() and
60  * dhcp_fine_tmr() on the defined intervals.
61  *
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.
65  *
66  * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
67  * to remove the DHCP client.
68  *
69  */
70  
71 #include <string.h>
72  
73 #include "lwip/stats.h"
74 #include "lwip/mem.h"
75 #include "lwip/udp.h"
76 #include "lwip/ip_addr.h"
77 #include "lwip/netif.h"
78 #include "lwip/inet.h"
79 #include "netif/etharp.h"
80
81 #include "lwip/sys.h"
82 #include "lwip/opt.h"
83 #include "lwip/dhcp.h"
84
85 #if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */
86
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;
91
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);
96
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);
104
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);
110 #if 0
111 static u16_t dhcp_get_option_short(u8_t *ptr);
112 #endif
113 static u32_t dhcp_get_option_long(u8_t *ptr);
114 static void dhcp_free_reply(struct dhcp *dhcp);
115
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);
120
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);
134
135 /**
136  * Back-off the DHCP client (because of a received NAK response).
137  *
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.
141  *
142  * We back-off and will end up restarting a fresh DHCP negotiation later.
143  *
144  * @param state pointer to DHCP state structure
145  */
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);
154 }
155
156 /**
157  * Checks if the offered IP address is already in use.
158  *
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.
162  */
163 static void dhcp_check(struct netif *netif)
164 {
165   struct dhcp *dhcp = netif->dhcp;
166   err_t result;
167   u16_t msecs;
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"));
175   }
176   dhcp->tries++;
177   msecs = 500;
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);
181 }
182
183 /**
184  * Remember the configuration offered by a DHCP server.
185  *
186  * @param state pointer to DHCP state structure
187  */
188 static void dhcp_handle_offer(struct netif *netif)
189 {
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)
196   {
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));
202
203     dhcp_select(netif);
204   }
205 }
206
207 /**
208  * Select a DHCP server offer out of all offers.
209  *
210  * Simply select the first offer received.
211  *
212  * @param netif the netif under DHCP control
213  * @return lwIP specific error (see error.h)
214  */
215 static err_t dhcp_select(struct netif *netif)
216 {
217   struct dhcp *dhcp = netif->dhcp;
218   err_t result;
219   u32_t msecs;
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));
221
222   /* create and initialize the DHCP message header */
223   result = dhcp_create_request(netif);
224   if (result == ERR_OK)
225   {
226     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
227     dhcp_option_byte(dhcp, DHCP_REQUEST);
228
229     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
230     dhcp_option_short(dhcp, 576);
231
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));
235
236     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
237     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
238
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);
244
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);
248
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);
260   } else {
261     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
262   }
263   dhcp->tries++;
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));
267   return result;
268 }
269
270 /**
271  * The DHCP timer that checks for lease renewal/rebind timeouts.
272  *
273  */
274 void dhcp_coarse_tmr()
275 {
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);
292       }
293     }
294     /* proceed to next netif */
295     netif = netif->next;
296   }
297 }
298
299 /**
300  * DHCP transaction timeout handling
301  *
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.
304  * 
305  */
306 void dhcp_fine_tmr()
307 {
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--;
316       }
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 */
322         dhcp_timeout(netif);
323       }
324     }
325     /* proceed to next network interface */
326     netif = netif->next;
327   }
328 }
329
330 /**
331  * A DHCP negotiation transaction, or ARP request, has timed out.
332  *
333  * The timer that was started with the DHCP or ARP request has
334  * timed out, indicating no response was received in time.
335  *
336  * @param netif the netif under DHCP control
337  *
338  */
339 static void dhcp_timeout(struct netif *netif)
340 {
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) {
351       dhcp_select(netif);
352     } else {
353       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
354       dhcp_release(netif);
355       dhcp_discover(netif);
356     }
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) {
361       dhcp_check(netif);
362     /* no ARP replies on the offered address,
363        looks like the IP address is indeed free */
364     } else {
365       /* bind the interface to the offered address */
366       dhcp_bind(netif);
367     }
368   }
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 */
374     dhcp_renew(netif);
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) {
379       dhcp_rebind(netif);
380     } else {
381       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
382       dhcp_release(netif);
383       dhcp_discover(netif);
384     }
385   }
386 }
387
388 /**
389  * The renewal period has timed out.
390  *
391  * @param netif the netif under DHCP control
392  */
393 static void dhcp_t1_timeout(struct netif *netif)
394 {
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"));
401     dhcp_renew(netif);
402   }
403 }
404
405 /**
406  * The rebind period has timed out.
407  *
408  */
409 static void dhcp_t2_timeout(struct netif *netif)
410 {
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"));
416     dhcp_rebind(netif);
417   }
418 }
419
420 /**
421  *
422  * @param netif the netif under DHCP control
423  */
424 static void dhcp_handle_ack(struct netif *netif)
425 {
426   struct dhcp *dhcp = netif->dhcp;
427   u8_t *option_ptr;
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;
432
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);
438   }
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);
444   } else {
445     /* calculate safe periods for renewal */
446     dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
447   }
448
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);
454   } else {
455     /* calculate safe periods for rebinding */
456     dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
457   }
458
459   /* (y)our internet address */
460   ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);
461
462 /**
463  * Patch #1308
464  * TODO: we must check if the file field is not overloaded by DHCP options!
465  */
466 #if 0
467   /* boot server address */
468   ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);
469   /* boot file name */
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);
473   }
474 #endif
475
476   /* subnet mask */
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]));
481   }
482
483   /* gateway router */
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]));
487   }
488
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]));
493   }
494   
495   /* DNS servers */
496   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);
497   if (option_ptr != NULL) {
498     u8_t n;
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]));
505     }
506   }
507 }
508
509 /**
510  * Start DHCP negotiation for a network interface.
511  *
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.
515  *
516  * @param netif The lwIP network interface
517  * @return lwIP error code
518  * - ERR_OK - No error
519  * - ERR_MEM - Out of memory
520  *
521  */
522 err_t dhcp_start(struct netif *netif)
523 {
524   struct dhcp *dhcp = netif->dhcp;
525   err_t result = ERR_OK;
526
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;
530
531   /* no DHCP client attached yet? */
532   if (dhcp == NULL) {
533     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
534     dhcp = mem_malloc(sizeof(struct dhcp));
535     if (dhcp == NULL) {
536       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
537       return ERR_MEM;
538     }
539     /* store this dhcp client in the netif */
540     netif->dhcp = dhcp;
541     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));
542   /* already has DHCP client attached */
543   } else {
544     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
545   }
546     
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;
555     return ERR_MEM;
556   }
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 */
562     dhcp_stop(netif);
563     return ERR_MEM;
564   }
565   netif->flags |= NETIF_FLAG_DHCP;
566   return result;
567 }
568
569 /**
570  * Inform a DHCP server of our manual configuration.
571  *
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.
575  *
576  * @param netif The lwIP network interface
577  *
578  */
579 void dhcp_inform(struct netif *netif)
580 {
581   struct dhcp *dhcp;
582   err_t result = ERR_OK;
583   dhcp = mem_malloc(sizeof(struct dhcp));
584   if (dhcp == NULL) {
585     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));
586     return;
587   }
588   netif->dhcp = dhcp;
589   memset(dhcp, 0, sizeof(struct dhcp));
590
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);
596     return;
597   }
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) {
602
603     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
604     dhcp_option_byte(dhcp, DHCP_INFORM);
605
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);
609
610     dhcp_option_trailer(dhcp);
611
612     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
613
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);
620   } else {
621     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
622   }
623
624   if (dhcp != NULL)
625   {
626     if (dhcp->pcb != NULL) udp_remove(dhcp->pcb);
627     dhcp->pcb = NULL;
628     mem_free((void *)dhcp);
629     netif->dhcp = NULL;
630   }
631 }
632
633 #if DHCP_DOES_ARP_CHECK
634 /**
635  * Match an ARP reply with the offered IP address.
636  *
637  * @param addr The IP address we received a reply from
638  *
639  */
640 void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
641 {
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"));
652       dhcp_decline(netif);
653     }
654   }
655 }
656
657 /**
658  * Decline an offered lease.
659  *
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).
663  */
664 static err_t dhcp_decline(struct netif *netif)
665 {
666   struct dhcp *dhcp = netif->dhcp;
667   err_t result = ERR_OK;
668   u16_t msecs;
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)
674   {
675     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
676     dhcp_option_byte(dhcp, DHCP_DECLINE);
677
678     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
679     dhcp_option_short(dhcp, 576);
680
681     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
682     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
683
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);
687
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"));
695   } else {
696     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));
697   }
698   dhcp->tries++;
699   msecs = 10*1000;
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));
702   return result;
703 }
704 #endif
705
706
707 /**
708  * Start the DHCP process, discover a DHCP server.
709  *
710  */
711 static err_t dhcp_discover(struct netif *netif)
712 {
713   struct dhcp *dhcp = netif->dhcp;
714   err_t result = ERR_OK;
715   u16_t msecs;
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)
721   {
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);
725
726     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
727     dhcp_option_short(dhcp, 576);
728
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);
734
735     dhcp_option_trailer(dhcp);
736
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);
739
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);
750   } else {
751     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
752   }
753   dhcp->tries++;
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));
757   return result;
758 }
759
760
761 /**
762  * Bind the interface to the offered IP address.
763  *
764  * @param netif network interface to bind to the offered address
765  */
766 static void dhcp_bind(struct netif *netif)
767 {
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));
773
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));
781   }
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));
788   }
789   /* copy offered network mask */
790   ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);
791
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);
800   }
801
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);
809   }
810
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 */
818   netif_set_up(netif);
819   /* netif is now bound to DHCP leased address */
820   dhcp_set_state(dhcp, DHCP_BOUND);
821 }
822
823 /**
824  * Renew an existing DHCP lease at the involved DHCP server.
825  *
826  * @param netif network interface which must renew its lease
827  */
828 err_t dhcp_renew(struct netif *netif)
829 {
830   struct dhcp *dhcp = netif->dhcp;
831   err_t result;
832   u16_t msecs;
833   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_renew()\n"));
834   dhcp_set_state(dhcp, DHCP_RENEWING);
835
836   /* create and initialize the DHCP message header */
837   result = dhcp_create_request(netif);
838   if (result == ERR_OK) {
839
840     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
841     dhcp_option_byte(dhcp, DHCP_REQUEST);
842
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);
846
847 #if 0
848     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
849     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
850 #endif
851
852 #if 0
853     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
854     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
855 #endif
856     /* append DHCP message trailer */
857     dhcp_option_trailer(dhcp);
858
859     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
860
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);
865
866     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew: RENEWING\n"));
867   } else {
868     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));
869   }
870   dhcp->tries++;
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));
875   return result;
876 }
877
878 /**
879  * Rebind with a DHCP server for an existing DHCP lease.
880  *
881  * @param netif network interface which must rebind with a DHCP server
882  */
883 static err_t dhcp_rebind(struct netif *netif)
884 {
885   struct dhcp *dhcp = netif->dhcp;
886   err_t result;
887   u16_t msecs;
888   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind()\n"));
889   dhcp_set_state(dhcp, DHCP_REBINDING);
890
891   /* create and initialize the DHCP message header */
892   result = dhcp_create_request(netif);
893   if (result == ERR_OK)
894   {
895
896     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
897     dhcp_option_byte(dhcp, DHCP_REQUEST);
898
899     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
900     dhcp_option_short(dhcp, 576);
901
902 #if 0
903     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
904     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
905
906     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
907     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
908 #endif
909
910     dhcp_option_trailer(dhcp);
911
912     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
913
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"));
921   } else {
922     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));
923   }
924   dhcp->tries++;
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));
928   return result;
929 }
930
931 /**
932  * Release a DHCP lease.
933  *
934  * @param netif network interface which must release its lease
935  */
936 err_t dhcp_release(struct netif *netif)
937 {
938   struct dhcp *dhcp = netif->dhcp;
939   err_t result;
940   u16_t msecs;
941   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_release()\n"));
942
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;
950   dhcp->dns_count = 0;
951   
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);
957
958     dhcp_option_trailer(dhcp);
959
960     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
961
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"));
967   } else {
968     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));
969   }
970   dhcp->tries++;
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);
980   
981   /* TODO: netif_down(netif); */
982   return result;
983 }
984 /**
985  * Remove the DHCP client from the interface.
986  *
987  * @param netif The network interface to stop DHCP on
988  */
989 void dhcp_stop(struct netif *netif)
990 {
991   struct dhcp *dhcp = netif->dhcp;
992   LWIP_ASSERT("dhcp_stop: netif != NULL", netif != NULL);
993
994   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_stop()\n"));
995   /* netif is DHCP configured? */
996   if (dhcp != NULL)
997   {
998     if (dhcp->pcb != NULL)
999     {
1000       udp_remove(dhcp->pcb);
1001       dhcp->pcb = NULL;
1002     }
1003     if (dhcp->p != NULL)
1004     {
1005       pbuf_free(dhcp->p);
1006       dhcp->p = NULL;
1007     }
1008     /* free unfolded reply */
1009     dhcp_free_reply(dhcp);
1010     mem_free((void *)dhcp);
1011     netif->dhcp = NULL;
1012   }
1013 }
1014
1015 /*
1016  * Set the DHCP state of a DHCP client.
1017  *
1018  * If the state changed, reset the number of tries.
1019  *
1020  * TODO: we might also want to reset the timeout here?
1021  */
1022 static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
1023 {
1024   if (new_state != dhcp->state)
1025   {
1026     dhcp->state = new_state;
1027     dhcp->tries = 0;
1028   }
1029 }
1030
1031 /*
1032  * Concatenate an option type and length field to the outgoing
1033  * DHCP message.
1034  *
1035  */
1036 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
1037 {
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;
1041 }
1042 /*
1043  * Concatenate a single byte to the outgoing DHCP message.
1044  *
1045  */
1046 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value)
1047 {
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;
1050 }
1051 static void dhcp_option_short(struct dhcp *dhcp, u16_t value)
1052 {
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;
1056 }
1057 static void dhcp_option_long(struct dhcp *dhcp, u32_t value)
1058 {
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);
1064 }
1065
1066 /**
1067  * Extract the DHCP message and the DHCP options.
1068  *
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.
1074  *
1075  */
1076 static err_t dhcp_unfold_reply(struct dhcp *dhcp)
1077 {
1078   struct pbuf *p = dhcp->p;
1079   u8_t *ptr;
1080   u16_t i;
1081   u16_t j = 0;
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))
1087   {
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)
1091     {
1092       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
1093       return ERR_MEM;
1094     }
1095   }
1096   dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
1097   if (dhcp->msg_in == NULL)
1098   {
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;
1102     return ERR_MEM;
1103   }
1104
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++)
1108   {
1109     *ptr++ = ((u8_t *)p->payload)[j++];
1110     /* reached end of pbuf? */
1111     if (j == p->len)
1112     {
1113       /* proceed to next pbuf in chain */
1114       p = p->next;
1115       j = 0;
1116     }
1117   }
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? */
1125       if (j == p->len) {
1126         /* proceed to next pbuf in chain */
1127         p = p->next;
1128         j = 0;
1129       }
1130     }
1131     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", i));
1132   }
1133   return ERR_OK;
1134 }
1135
1136 /**
1137  * Free the incoming DHCP message including contiguous copy of
1138  * its DHCP options.
1139  *
1140  */
1141 static void dhcp_free_reply(struct dhcp *dhcp)
1142 {
1143   if (dhcp->msg_in != NULL) {
1144     mem_free((void *)dhcp->msg_in);
1145     dhcp->msg_in = NULL;
1146   }
1147   if (dhcp->options_in) {
1148     mem_free((void *)dhcp->options_in);
1149     dhcp->options_in = NULL;
1150     dhcp->options_in_len = 0;
1151   }
1152   LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));
1153 }
1154
1155
1156 /**
1157  * If an incoming DHCP message is in response to us, then trigger the state machine
1158  */
1159 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
1160 {
1161   struct netif *netif = (struct netif *)arg;
1162   struct dhcp *dhcp = netif->dhcp;
1163   struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
1164   u8_t *options_ptr;
1165   u8_t msg_type;
1166   u8_t i;
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;
1174   dhcp->p = p;
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));
1178     pbuf_free(p);
1179     dhcp->p = NULL;
1180     return;
1181   }
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]));
1187       pbuf_free(p);
1188       dhcp->p = NULL;
1189       return;
1190     }
1191   }
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));
1195     pbuf_free(p);
1196     dhcp->p = NULL;
1197     return;
1198   }
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"));
1202     pbuf_free(p);
1203     dhcp->p = NULL;
1204     return;
1205   }
1206
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"));
1212     pbuf_free(p);
1213     dhcp->p = NULL;
1214     return;
1215   }
1216
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 */
1228       dhcp_check(netif);
1229 #else
1230       /* bind interface to the acknowledged lease address */
1231       dhcp_bind(netif);
1232 #endif
1233     }
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;
1237       dhcp_bind(netif);
1238     }
1239   }
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);
1247   }
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);
1254   }
1255   pbuf_free(p);
1256   dhcp->p = NULL;
1257 }
1258
1259
1260 static err_t dhcp_create_request(struct netif *netif)
1261 {
1262   struct dhcp *dhcp = netif->dhcp;
1263   u16_t i;
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"));
1269     return ERR_MEM;
1270   }
1271   /* give unique transaction identifier to this request */
1272   dhcp->xid = xid++;
1273   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));
1274
1275   dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
1276
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*/;
1293   }
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;
1300   return ERR_OK;
1301 }
1302
1303 static void dhcp_delete_request(struct netif *netif)
1304 {
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);
1309   dhcp->p_out = NULL;
1310   dhcp->msg_out = NULL;
1311 }
1312
1313 /**
1314  * Add a DHCP message trailer
1315  *
1316  * Adds the END option to the DHCP message, and if
1317  * necessary, up to three padding bytes.
1318  */
1319
1320 static void dhcp_option_trailer(struct dhcp *dhcp)
1321 {
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;
1331   }
1332 }
1333
1334 /**
1335  * Find the offset of a DHCP option inside the DHCP message.
1336  *
1337  * @param client DHCP client
1338  * @param option_type
1339  *
1340  * @return a byte offset into the UDP message where the option was found, or
1341  * zero if the given option was not found.
1342  */
1343 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
1344 {
1345   u8_t overload = DHCP_OVERLOAD_NONE;
1346
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;
1351     u16_t offset = 0;
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 */
1359         offset += 2;
1360         overload = options[offset++];
1361       }
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];
1366       /* skip option */
1367       } else {
1368          LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));
1369         /* skip option type */
1370         offset++;
1371         /* skip option length, and then length bytes */
1372         offset += 1 + options[offset];
1373       }
1374     }
1375     /* is this an overloaded message? */
1376     if (overload != DHCP_OVERLOAD_NONE) {
1377       u16_t field_len;
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 */
1387       } else {
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;
1391       }
1392       offset = 0;
1393
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];
1399         /* skip option */
1400         } else {
1401           LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));
1402           /* skip option type */
1403           offset++;
1404           offset += 1 + options[offset];
1405         }
1406       }
1407     }
1408   }
1409   return NULL;
1410 }
1411
1412 /**
1413  * Return the byte of DHCP option data.
1414  *
1415  * @param client DHCP client.
1416  * @param ptr pointer obtained by dhcp_get_option_ptr().
1417  *
1418  * @return byte value at the given address.
1419  */
1420 static u8_t dhcp_get_option_byte(u8_t *ptr)
1421 {
1422   LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));
1423   return *ptr;
1424 }
1425
1426 #if 0
1427 /**
1428  * Return the 16-bit value of DHCP option data.
1429  *
1430  * @param client DHCP client.
1431  * @param ptr pointer obtained by dhcp_get_option_ptr().
1432  *
1433  * @return byte value at the given address.
1434  */
1435 static u16_t dhcp_get_option_short(u8_t *ptr)
1436 {
1437   u16_t value;
1438   value = *ptr++ << 8;
1439   value |= *ptr;
1440   LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));
1441   return value;
1442 }
1443 #endif
1444
1445 /**
1446  * Return the 32-bit value of DHCP option data.
1447  *
1448  * @param client DHCP client.
1449  * @param ptr pointer obtained by dhcp_get_option_ptr().
1450  *
1451  * @return byte value at the given address.
1452  */
1453 static u32_t dhcp_get_option_long(u8_t *ptr)
1454 {
1455   u32_t value;
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));
1461   return value;
1462 }
1463
1464 #endif /* LWIP_DHCP */