]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/core/dhcp.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / Common / ethernet / lwIP / core / dhcp.c
1 /**\r
2  * @file\r
3  *\r
4  * Dynamic Host Configuration Protocol client\r
5  */\r
6 \r
7 /*\r
8  *\r
9  * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>\r
10  * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.\r
11  * All rights reserved.\r
12  *\r
13  * Redistribution and use in source and binary forms, with or without modification,\r
14  * are permitted provided that the following conditions are met:\r
15  *\r
16  * 1. Redistributions of source code must retain the above copyright notice,\r
17  *    this list of conditions and the following disclaimer.\r
18  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
19  *    this list of conditions and the following disclaimer in the documentation\r
20  *    and/or other materials provided with the distribution.\r
21  * 3. The name of the author may not be used to endorse or promote products\r
22  *    derived from this software without specific prior written permission.\r
23  *\r
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
25  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
27  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
29  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
32  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
33  * OF SUCH DAMAGE.\r
34  *\r
35  * This file is a contribution to the lwIP TCP/IP stack.\r
36  * The Swedish Institute of Computer Science and Adam Dunkels\r
37  * are specifically granted permission to redistribute this\r
38  * source code.\r
39  *\r
40  * Author: Leon Woestenberg <leon.woestenberg@gmx.net>\r
41  *\r
42  * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform\r
43  * with RFC 2131 and RFC 2132.\r
44  *\r
45  * TODO:\r
46  * - Proper parsing of DHCP messages exploiting file/sname field overloading.\r
47  * - Add JavaDoc style documentation (API, internals).\r
48  * - Support for interfaces other than Ethernet (SLIP, PPP, ...)\r
49  *\r
50  * Please coordinate changes and requests with Leon Woestenberg\r
51  * <leon.woestenberg@gmx.net>\r
52  *\r
53  * Integration with your code:\r
54  *\r
55  * In lwip/dhcp.h\r
56  * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)\r
57  * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)\r
58  *\r
59  * Then have your application call dhcp_coarse_tmr() and\r
60  * dhcp_fine_tmr() on the defined intervals.\r
61  *\r
62  * dhcp_start(struct netif *netif);\r
63  * starts a DHCP client instance which configures the interface by\r
64  * obtaining an IP address lease and maintaining it.\r
65  *\r
66  * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)\r
67  * to remove the DHCP client.\r
68  *\r
69  */\r
70  \r
71 #include <string.h>\r
72  \r
73 #include "lwip/stats.h"\r
74 #include "lwip/mem.h"\r
75 #include "lwip/udp.h"\r
76 #include "lwip/ip_addr.h"\r
77 #include "lwip/netif.h"\r
78 #include "lwip/inet.h"\r
79 #include "netif/etharp.h"\r
80 \r
81 #include "lwip/sys.h"\r
82 #include "lwip/opt.h"\r
83 #include "lwip/dhcp.h"\r
84 \r
85 #if LWIP_DHCP /* don't build if not configured for use in lwipopt.h */\r
86 \r
87 /** global transaction identifier, must be\r
88  *  unique for each DHCP request. We simply increment, starting\r
89  *  with this value (easy to match with a packet analyzer) */\r
90 static u32_t xid = 0xABCD0000;\r
91 \r
92 /** DHCP client state machine functions */\r
93 static void dhcp_handle_ack(struct netif *netif);\r
94 static void dhcp_handle_nak(struct netif *netif);\r
95 static void dhcp_handle_offer(struct netif *netif);\r
96 \r
97 static err_t dhcp_discover(struct netif *netif);\r
98 static err_t dhcp_select(struct netif *netif);\r
99 static void dhcp_check(struct netif *netif);\r
100 static void dhcp_bind(struct netif *netif);\r
101 static err_t dhcp_decline(struct netif *netif);\r
102 static err_t dhcp_rebind(struct netif *netif);\r
103 static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);\r
104 \r
105 /** receive, unfold, parse and free incoming messages */\r
106 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);\r
107 static err_t dhcp_unfold_reply(struct dhcp *dhcp);\r
108 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);\r
109 static u8_t dhcp_get_option_byte(u8_t *ptr);\r
110 #if 0\r
111 static u16_t dhcp_get_option_short(u8_t *ptr);\r
112 #endif\r
113 static u32_t dhcp_get_option_long(u8_t *ptr);\r
114 static void dhcp_free_reply(struct dhcp *dhcp);\r
115 \r
116 /** set the DHCP timers */\r
117 static void dhcp_timeout(struct netif *netif);\r
118 static void dhcp_t1_timeout(struct netif *netif);\r
119 static void dhcp_t2_timeout(struct netif *netif);\r
120 \r
121 /** build outgoing messages */\r
122 /** create a DHCP request, fill in common headers */\r
123 static err_t dhcp_create_request(struct netif *netif);\r
124 /** free a DHCP request */\r
125 static void dhcp_delete_request(struct netif *netif);\r
126 /** add a DHCP option (type, then length in bytes) */\r
127 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);\r
128 /** add option values */\r
129 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);\r
130 static void dhcp_option_short(struct dhcp *dhcp, u16_t value);\r
131 static void dhcp_option_long(struct dhcp *dhcp, u32_t value);\r
132 /** always add the DHCP options trailer to end and pad */\r
133 static void dhcp_option_trailer(struct dhcp *dhcp);\r
134 \r
135 /**\r
136  * Back-off the DHCP client (because of a received NAK response).\r
137  *\r
138  * Back-off the DHCP client because of a received NAK. Receiving a\r
139  * NAK means the client asked for something non-sensible, for\r
140  * example when it tries to renew a lease obtained on another network.\r
141  *\r
142  * We back-off and will end up restarting a fresh DHCP negotiation later.\r
143  *\r
144  * @param state pointer to DHCP state structure\r
145  */\r
146 static void dhcp_handle_nak(struct netif *netif) {\r
147   struct dhcp *dhcp = netif->dhcp;\r
148   u16_t msecs = 10 * 1000;\r
149   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", \r
150     (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\r
151   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
152   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_handle_nak(): set request timeout %"U16_F" msecs\n", msecs));\r
153   dhcp_set_state(dhcp, DHCP_BACKING_OFF);\r
154 }\r
155 \r
156 /**\r
157  * Checks if the offered IP address is already in use.\r
158  *\r
159  * It does so by sending an ARP request for the offered address and\r
160  * entering CHECKING state. If no ARP reply is received within a small\r
161  * interval, the address is assumed to be free for use by us.\r
162  */\r
163 static void dhcp_check(struct netif *netif)\r
164 {\r
165   struct dhcp *dhcp = netif->dhcp;\r
166   err_t result;\r
167   u16_t msecs;\r
168   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],\r
169     (s16_t)netif->name[1]));\r
170   /* create an ARP query for the offered IP address, expecting that no host\r
171      responds, as the IP address should not be in use. */\r
172   result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);\r
173   if (result != ERR_OK) {\r
174     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));\r
175   }\r
176   dhcp->tries++;\r
177   msecs = 500;\r
178   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
179   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));\r
180   dhcp_set_state(dhcp, DHCP_CHECKING);\r
181 }\r
182 \r
183 /**\r
184  * Remember the configuration offered by a DHCP server.\r
185  *\r
186  * @param state pointer to DHCP state structure\r
187  */\r
188 static void dhcp_handle_offer(struct netif *netif)\r
189 {\r
190   struct dhcp *dhcp = netif->dhcp;\r
191   /* obtain the server address */\r
192   u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);\r
193   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",\r
194     (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\r
195   if (option_ptr != NULL)\r
196   {\r
197     dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
198     LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));\r
199     /* remember offered address */\r
200     ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);\r
201     LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));\r
202 \r
203     dhcp_select(netif);\r
204   }\r
205 }\r
206 \r
207 /**\r
208  * Select a DHCP server offer out of all offers.\r
209  *\r
210  * Simply select the first offer received.\r
211  *\r
212  * @param netif the netif under DHCP control\r
213  * @return lwIP specific error (see error.h)\r
214  */\r
215 static err_t dhcp_select(struct netif *netif)\r
216 {\r
217   struct dhcp *dhcp = netif->dhcp;\r
218   err_t result;\r
219   u32_t msecs;\r
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));\r
221 \r
222   /* create and initialize the DHCP message header */\r
223   result = dhcp_create_request(netif);\r
224   if (result == ERR_OK)\r
225   {\r
226     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
227     dhcp_option_byte(dhcp, DHCP_REQUEST);\r
228 \r
229     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
230     dhcp_option_short(dhcp, 576);\r
231 \r
232     /* MUST request the offered IP address */\r
233     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
234     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
235 \r
236     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
237     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
238 \r
239     dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);\r
240     dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);\r
241     dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);\r
242     dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);\r
243     dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);\r
244 \r
245     dhcp_option_trailer(dhcp);\r
246     /* shrink the pbuf to the actual content length */\r
247     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
248 \r
249     /* TODO: we really should bind to a specific local interface here\r
250        but we cannot specify an unconfigured netif as it is addressless */\r
251     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
252     /* send broadcast to any DHCP server */\r
253     udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
254     udp_send(dhcp->pcb, dhcp->p_out);\r
255     /* reconnect to any (or to server here?!) */\r
256     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
257     dhcp_delete_request(netif);\r
258     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_select: REQUESTING\n"));\r
259     dhcp_set_state(dhcp, DHCP_REQUESTING);\r
260   } else {\r
261     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));\r
262   }\r
263   dhcp->tries++;\r
264   msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;\r
265   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
266   LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_select(): set request timeout %"U32_F" msecs\n", msecs));\r
267   return result;\r
268 }\r
269 \r
270 /**\r
271  * The DHCP timer that checks for lease renewal/rebind timeouts.\r
272  *\r
273  */\r
274 void dhcp_coarse_tmr()\r
275 {\r
276   struct netif *netif = netif_list;\r
277   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_coarse_tmr()\n"));\r
278   /* iterate through all network interfaces */\r
279   while (netif != NULL) {\r
280     /* only act on DHCP configured interfaces */\r
281     if (netif->dhcp != NULL) {\r
282       /* timer is active (non zero), and triggers (zeroes) now? */\r
283       if (netif->dhcp->t2_timeout-- == 1) {\r
284         LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));\r
285         /* this clients' rebind timeout triggered */\r
286         dhcp_t2_timeout(netif);\r
287       /* timer is active (non zero), and triggers (zeroes) now */\r
288       } else if (netif->dhcp->t1_timeout-- == 1) {\r
289         LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));\r
290         /* this clients' renewal timeout triggered */\r
291         dhcp_t1_timeout(netif);\r
292       }\r
293     }\r
294     /* proceed to next netif */\r
295     netif = netif->next;\r
296   }\r
297 }\r
298 \r
299 /**\r
300  * DHCP transaction timeout handling\r
301  *\r
302  * A DHCP server is expected to respond within a short period of time.\r
303  * This timer checks whether an outstanding DHCP request is timed out.\r
304  * \r
305  */\r
306 void dhcp_fine_tmr()\r
307 {\r
308   struct netif *netif = netif_list;\r
309   /* loop through netif's */\r
310   while (netif != NULL) {\r
311     /* only act on DHCP configured interfaces */\r
312     if (netif->dhcp != NULL) {\r
313       /* timer is active (non zero), and is about to trigger now */      \r
314       if (netif->dhcp->request_timeout > 1) {\r
315         netif->dhcp->request_timeout--;\r
316       }\r
317       else if (netif->dhcp->request_timeout == 1) {\r
318         netif->dhcp->request_timeout--;\r
319         /* { netif->dhcp->request_timeout == 0 } */\r
320         LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));\r
321         /* this clients' request timeout triggered */\r
322         dhcp_timeout(netif);\r
323       }\r
324     }\r
325     /* proceed to next network interface */\r
326     netif = netif->next;\r
327   }\r
328 }\r
329 \r
330 /**\r
331  * A DHCP negotiation transaction, or ARP request, has timed out.\r
332  *\r
333  * The timer that was started with the DHCP or ARP request has\r
334  * timed out, indicating no response was received in time.\r
335  *\r
336  * @param netif the netif under DHCP control\r
337  *\r
338  */\r
339 static void dhcp_timeout(struct netif *netif)\r
340 {\r
341   struct dhcp *dhcp = netif->dhcp;\r
342   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_timeout()\n"));\r
343   /* back-off period has passed, or server selection timed out */\r
344   if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {\r
345     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));\r
346     dhcp_discover(netif);\r
347   /* receiving the requested lease timed out */\r
348   } else if (dhcp->state == DHCP_REQUESTING) {\r
349     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));\r
350     if (dhcp->tries <= 5) {\r
351       dhcp_select(netif);\r
352     } else {\r
353       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));\r
354       dhcp_release(netif);\r
355       dhcp_discover(netif);\r
356     }\r
357   /* received no ARP reply for the offered address (which is good) */\r
358   } else if (dhcp->state == DHCP_CHECKING) {\r
359     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));\r
360     if (dhcp->tries <= 1) {\r
361       dhcp_check(netif);\r
362     /* no ARP replies on the offered address,\r
363        looks like the IP address is indeed free */\r
364     } else {\r
365       /* bind the interface to the offered address */\r
366       dhcp_bind(netif);\r
367     }\r
368   }\r
369   /* did not get response to renew request? */\r
370   else if (dhcp->state == DHCP_RENEWING) {\r
371     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));\r
372     /* just retry renewal */\r
373     /* note that the rebind timer will eventually time-out if renew does not work */\r
374     dhcp_renew(netif);\r
375   /* did not get response to rebind request? */\r
376   } else if (dhcp->state == DHCP_REBINDING) {\r
377     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));\r
378     if (dhcp->tries <= 8) {\r
379       dhcp_rebind(netif);\r
380     } else {\r
381       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));\r
382       dhcp_release(netif);\r
383       dhcp_discover(netif);\r
384     }\r
385   }\r
386 }\r
387 \r
388 /**\r
389  * The renewal period has timed out.\r
390  *\r
391  * @param netif the netif under DHCP control\r
392  */\r
393 static void dhcp_t1_timeout(struct netif *netif)\r
394 {\r
395   struct dhcp *dhcp = netif->dhcp;\r
396   LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_t1_timeout()\n"));\r
397   if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {\r
398     /* just retry to renew - note that the rebind timer (t2) will\r
399      * eventually time-out if renew tries fail. */\r
400     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));\r
401     dhcp_renew(netif);\r
402   }\r
403 }\r
404 \r
405 /**\r
406  * The rebind period has timed out.\r
407  *\r
408  */\r
409 static void dhcp_t2_timeout(struct netif *netif)\r
410 {\r
411   struct dhcp *dhcp = netif->dhcp;\r
412   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout()\n"));\r
413   if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {\r
414     /* just retry to rebind */\r
415     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));\r
416     dhcp_rebind(netif);\r
417   }\r
418 }\r
419 \r
420 /**\r
421  *\r
422  * @param netif the netif under DHCP control\r
423  */\r
424 static void dhcp_handle_ack(struct netif *netif)\r
425 {\r
426   struct dhcp *dhcp = netif->dhcp;\r
427   u8_t *option_ptr;\r
428   /* clear options we might not get from the ACK */\r
429   dhcp->offered_sn_mask.addr = 0;\r
430   dhcp->offered_gw_addr.addr = 0;\r
431   dhcp->offered_bc_addr.addr = 0;\r
432 \r
433   /* lease time given? */\r
434   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);\r
435   if (option_ptr != NULL) {\r
436     /* remember offered lease time */\r
437     dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);\r
438   }\r
439   /* renewal period given? */\r
440   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);\r
441   if (option_ptr != NULL) {\r
442     /* remember given renewal period */\r
443     dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);\r
444   } else {\r
445     /* calculate safe periods for renewal */\r
446     dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;\r
447   }\r
448 \r
449   /* renewal period given? */\r
450   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);\r
451   if (option_ptr != NULL) {\r
452     /* remember given rebind period */\r
453     dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);\r
454   } else {\r
455     /* calculate safe periods for rebinding */\r
456     dhcp->offered_t2_rebind = dhcp->offered_t0_lease;\r
457   }\r
458 \r
459   /* (y)our internet address */\r
460   ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);\r
461 \r
462 /**\r
463  * Patch #1308\r
464  * TODO: we must check if the file field is not overloaded by DHCP options!\r
465  */\r
466 #if 0\r
467   /* boot server address */\r
468   ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);\r
469   /* boot file name */\r
470   if (dhcp->msg_in->file[0]) {\r
471     dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);\r
472     strcpy(dhcp->boot_file_name, dhcp->msg_in->file);\r
473   }\r
474 #endif\r
475 \r
476   /* subnet mask */\r
477   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);\r
478   /* subnet mask given? */\r
479   if (option_ptr != NULL) {\r
480     dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
481   }\r
482 \r
483   /* gateway router */\r
484   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);\r
485   if (option_ptr != NULL) {\r
486     dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
487   }\r
488 \r
489   /* broadcast address */\r
490   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);\r
491   if (option_ptr != NULL) {\r
492     dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
493   }\r
494   \r
495   /* DNS servers */\r
496   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);\r
497   if (option_ptr != NULL) {\r
498     u8_t n;\r
499     dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);\r
500     /* limit to at most DHCP_MAX_DNS DNS servers */\r
501     if (dhcp->dns_count > DHCP_MAX_DNS)\r
502       dhcp->dns_count = DHCP_MAX_DNS;\r
503     for (n = 0; n < dhcp->dns_count; n++) {\r
504       dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));\r
505     }\r
506   }\r
507 }\r
508 \r
509 /**\r
510  * Start DHCP negotiation for a network interface.\r
511  *\r
512  * If no DHCP client instance was attached to this interface,\r
513  * a new client is created first. If a DHCP client instance\r
514  * was already present, it restarts negotiation.\r
515  *\r
516  * @param netif The lwIP network interface\r
517  * @return lwIP error code\r
518  * - ERR_OK - No error\r
519  * - ERR_MEM - Out of memory\r
520  *\r
521  */\r
522 err_t dhcp_start(struct netif *netif)\r
523 {\r
524   struct dhcp *dhcp = netif->dhcp;\r
525   err_t result = ERR_OK;\r
526 \r
527   LWIP_ASSERT("netif != NULL", netif != NULL);\r
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));\r
529   netif->flags &= ~NETIF_FLAG_DHCP;\r
530 \r
531   /* no DHCP client attached yet? */\r
532   if (dhcp == NULL) {\r
533     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));\r
534     dhcp = mem_malloc(sizeof(struct dhcp));\r
535     if (dhcp == NULL) {\r
536       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));\r
537       return ERR_MEM;\r
538     }\r
539     /* store this dhcp client in the netif */\r
540     netif->dhcp = dhcp;\r
541     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));\r
542   /* already has DHCP client attached */\r
543   } else {\r
544     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));\r
545   }\r
546     \r
547   /* clear data structure */\r
548   memset(dhcp, 0, sizeof(struct dhcp));\r
549   /* allocate UDP PCB */\r
550   dhcp->pcb = udp_new();\r
551   if (dhcp->pcb == NULL) {\r
552     LWIP_DEBUGF(DHCP_DEBUG  | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));\r
553     mem_free((void *)dhcp);\r
554     netif->dhcp = dhcp = NULL;\r
555     return ERR_MEM;\r
556   }\r
557   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));\r
558   /* (re)start the DHCP negotiation */\r
559   result = dhcp_discover(netif);\r
560   if (result != ERR_OK) {\r
561     /* free resources allocated above */\r
562     dhcp_stop(netif);\r
563     return ERR_MEM;\r
564   }\r
565   netif->flags |= NETIF_FLAG_DHCP;\r
566   return result;\r
567 }\r
568 \r
569 /**\r
570  * Inform a DHCP server of our manual configuration.\r
571  *\r
572  * This informs DHCP servers of our fixed IP address configuration\r
573  * by sending an INFORM message. It does not involve DHCP address\r
574  * configuration, it is just here to be nice to the network.\r
575  *\r
576  * @param netif The lwIP network interface\r
577  *\r
578  */\r
579 void dhcp_inform(struct netif *netif)\r
580 {\r
581   struct dhcp *dhcp;\r
582   err_t result = ERR_OK;\r
583   dhcp = mem_malloc(sizeof(struct dhcp));\r
584   if (dhcp == NULL) {\r
585     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));\r
586     return;\r
587   }\r
588   netif->dhcp = dhcp;\r
589   memset(dhcp, 0, sizeof(struct dhcp));\r
590 \r
591   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));\r
592   dhcp->pcb = udp_new();\r
593   if (dhcp->pcb == NULL) {\r
594     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));\r
595     mem_free((void *)dhcp);\r
596     return;\r
597   }\r
598   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));\r
599   /* create and initialize the DHCP message header */\r
600   result = dhcp_create_request(netif);\r
601   if (result == ERR_OK) {\r
602 \r
603     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
604     dhcp_option_byte(dhcp, DHCP_INFORM);\r
605 \r
606     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
607     /* TODO: use netif->mtu ?! */\r
608     dhcp_option_short(dhcp, 576);\r
609 \r
610     dhcp_option_trailer(dhcp);\r
611 \r
612     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
613 \r
614     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
615     udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
616     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_inform: INFORMING\n"));\r
617     udp_send(dhcp->pcb, dhcp->p_out);\r
618     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
619     dhcp_delete_request(netif);\r
620   } else {\r
621     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));\r
622   }\r
623 \r
624   if (dhcp != NULL)\r
625   {\r
626     if (dhcp->pcb != NULL) udp_remove(dhcp->pcb);\r
627     dhcp->pcb = NULL;\r
628     mem_free((void *)dhcp);\r
629     netif->dhcp = NULL;\r
630   }\r
631 }\r
632 \r
633 #if DHCP_DOES_ARP_CHECK\r
634 /**\r
635  * Match an ARP reply with the offered IP address.\r
636  *\r
637  * @param addr The IP address we received a reply from\r
638  *\r
639  */\r
640 void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)\r
641 {\r
642   LWIP_ASSERT("netif != NULL", netif != NULL);\r
643   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_arp_reply()\n"));\r
644   /* is a DHCP client doing an ARP check? */\r
645   if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {\r
646     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));\r
647     /* did a host respond with the address we\r
648        were offered by the DHCP server? */\r
649     if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {\r
650       /* we will not accept the offered address */\r
651       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));\r
652       dhcp_decline(netif);\r
653     }\r
654   }\r
655 }\r
656 \r
657 /**\r
658  * Decline an offered lease.\r
659  *\r
660  * Tell the DHCP server we do not accept the offered address.\r
661  * One reason to decline the lease is when we find out the address\r
662  * is already in use by another host (through ARP).\r
663  */\r
664 static err_t dhcp_decline(struct netif *netif)\r
665 {\r
666   struct dhcp *dhcp = netif->dhcp;\r
667   err_t result = ERR_OK;\r
668   u16_t msecs;\r
669   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_decline()\n"));\r
670   dhcp_set_state(dhcp, DHCP_BACKING_OFF);\r
671   /* create and initialize the DHCP message header */\r
672   result = dhcp_create_request(netif);\r
673   if (result == ERR_OK)\r
674   {\r
675     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
676     dhcp_option_byte(dhcp, DHCP_DECLINE);\r
677 \r
678     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
679     dhcp_option_short(dhcp, 576);\r
680 \r
681     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
682     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
683 \r
684     dhcp_option_trailer(dhcp);\r
685     /* resize pbuf to reflect true size of options */\r
686     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
687 \r
688     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
689     /* @todo: should we really connect here? we are performing sendto() */\r
690     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
691     /* per section 4.4.4, broadcast DECLINE messages */\r
692     udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
693     dhcp_delete_request(netif);\r
694     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n"));\r
695   } else {\r
696     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));\r
697   }\r
698   dhcp->tries++;\r
699   msecs = 10*1000;\r
700   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
701    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));\r
702   return result;\r
703 }\r
704 #endif\r
705 \r
706 \r
707 /**\r
708  * Start the DHCP process, discover a DHCP server.\r
709  *\r
710  */\r
711 static err_t dhcp_discover(struct netif *netif)\r
712 {\r
713   struct dhcp *dhcp = netif->dhcp;\r
714   err_t result = ERR_OK;\r
715   u16_t msecs;\r
716   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_discover()\n"));\r
717   ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);\r
718   /* create and initialize the DHCP message header */\r
719   result = dhcp_create_request(netif);\r
720   if (result == ERR_OK)\r
721   {\r
722     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: making request\n"));\r
723     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
724     dhcp_option_byte(dhcp, DHCP_DISCOVER);\r
725 \r
726     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
727     dhcp_option_short(dhcp, 576);\r
728 \r
729     dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);\r
730     dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);\r
731     dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);\r
732     dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);\r
733     dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);\r
734 \r
735     dhcp_option_trailer(dhcp);\r
736 \r
737     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: realloc()ing\n"));\r
738     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
739 \r
740     /* set receive callback function with netif as user data */\r
741     udp_recv(dhcp->pcb, dhcp_recv, netif);\r
742     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
743     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
744     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));\r
745     udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
746     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: deleting()ing\n"));\r
747     dhcp_delete_request(netif);\r
748     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover: SELECTING\n"));\r
749     dhcp_set_state(dhcp, DHCP_SELECTING);\r
750   } else {\r
751     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));\r
752   }\r
753   dhcp->tries++;\r
754   msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;\r
755   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
756   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));\r
757   return result;\r
758 }\r
759 \r
760 \r
761 /**\r
762  * Bind the interface to the offered IP address.\r
763  *\r
764  * @param netif network interface to bind to the offered address\r
765  */\r
766 static void dhcp_bind(struct netif *netif)\r
767 {\r
768   struct dhcp *dhcp = netif->dhcp;\r
769   struct ip_addr sn_mask, gw_addr;\r
770   LWIP_ASSERT("dhcp_bind: netif != NULL", netif != NULL);\r
771   LWIP_ASSERT("dhcp_bind: dhcp != NULL", dhcp != NULL);\r
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));\r
773 \r
774   /* temporary DHCP lease? */\r
775   if (dhcp->offered_t1_renew != 0xffffffffUL) {\r
776     /* set renewal period timer */\r
777     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));\r
778     dhcp->t1_timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;\r
779     if (dhcp->t1_timeout == 0) dhcp->t1_timeout = 1;\r
780     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));\r
781   }\r
782   /* set renewal period timer */\r
783   if (dhcp->offered_t2_rebind != 0xffffffffUL) {\r
784     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));\r
785     dhcp->t2_timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;\r
786     if (dhcp->t2_timeout == 0) dhcp->t2_timeout = 1;\r
787     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));\r
788   }\r
789   /* copy offered network mask */\r
790   ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);\r
791 \r
792   /* subnet mask not given? */\r
793   /* TODO: this is not a valid check. what if the network mask is 0? */\r
794   if (sn_mask.addr == 0) {\r
795     /* choose a safe subnet mask given the network class */\r
796     u8_t first_octet = ip4_addr1(&sn_mask);\r
797     if (first_octet <= 127) sn_mask.addr = htonl(0xff000000);\r
798     else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00);\r
799     else sn_mask.addr = htonl(0xffff0000);\r
800   }\r
801 \r
802   ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);\r
803   /* gateway address not given? */\r
804   if (gw_addr.addr == 0) {\r
805     /* copy network address */\r
806     gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);\r
807     /* use first host address on network as gateway */\r
808     gw_addr.addr |= htonl(0x00000001);\r
809   }\r
810 \r
811   LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));\r
812   netif_set_ipaddr(netif, &dhcp->offered_ip_addr);\r
813   LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));\r
814   netif_set_netmask(netif, &sn_mask);\r
815   LWIP_DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));\r
816   netif_set_gw(netif, &gw_addr);\r
817   /* bring the interface up */\r
818   netif_set_up(netif);\r
819   /* netif is now bound to DHCP leased address */\r
820   dhcp_set_state(dhcp, DHCP_BOUND);\r
821 }\r
822 \r
823 /**\r
824  * Renew an existing DHCP lease at the involved DHCP server.\r
825  *\r
826  * @param netif network interface which must renew its lease\r
827  */\r
828 err_t dhcp_renew(struct netif *netif)\r
829 {\r
830   struct dhcp *dhcp = netif->dhcp;\r
831   err_t result;\r
832   u16_t msecs;\r
833   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_renew()\n"));\r
834   dhcp_set_state(dhcp, DHCP_RENEWING);\r
835 \r
836   /* create and initialize the DHCP message header */\r
837   result = dhcp_create_request(netif);\r
838   if (result == ERR_OK) {\r
839 \r
840     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
841     dhcp_option_byte(dhcp, DHCP_REQUEST);\r
842 \r
843     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
844     /* TODO: use netif->mtu in some way */\r
845     dhcp_option_short(dhcp, 576);\r
846 \r
847 #if 0\r
848     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
849     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
850 #endif\r
851 \r
852 #if 0\r
853     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
854     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
855 #endif\r
856     /* append DHCP message trailer */\r
857     dhcp_option_trailer(dhcp);\r
858 \r
859     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
860 \r
861     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
862     udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);\r
863     udp_send(dhcp->pcb, dhcp->p_out);\r
864     dhcp_delete_request(netif);\r
865 \r
866     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew: RENEWING\n"));\r
867   } else {\r
868     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));\r
869   }\r
870   dhcp->tries++;\r
871   /* back-off on retries, but to a maximum of 20 seconds */\r
872   msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;\r
873   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
874    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));\r
875   return result;\r
876 }\r
877 \r
878 /**\r
879  * Rebind with a DHCP server for an existing DHCP lease.\r
880  *\r
881  * @param netif network interface which must rebind with a DHCP server\r
882  */\r
883 static err_t dhcp_rebind(struct netif *netif)\r
884 {\r
885   struct dhcp *dhcp = netif->dhcp;\r
886   err_t result;\r
887   u16_t msecs;\r
888   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind()\n"));\r
889   dhcp_set_state(dhcp, DHCP_REBINDING);\r
890 \r
891   /* create and initialize the DHCP message header */\r
892   result = dhcp_create_request(netif);\r
893   if (result == ERR_OK)\r
894   {\r
895 \r
896     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
897     dhcp_option_byte(dhcp, DHCP_REQUEST);\r
898 \r
899     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
900     dhcp_option_short(dhcp, 576);\r
901 \r
902 #if 0\r
903     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
904     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
905 \r
906     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
907     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
908 #endif\r
909 \r
910     dhcp_option_trailer(dhcp);\r
911 \r
912     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
913 \r
914     /* set remote IP association to any DHCP server */\r
915     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
916     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
917     /* broadcast to server */\r
918     udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
919     dhcp_delete_request(netif);\r
920     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind: REBINDING\n"));\r
921   } else {\r
922     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));\r
923   }\r
924   dhcp->tries++;\r
925   msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\r
926   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
927    LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));\r
928   return result;\r
929 }\r
930 \r
931 /**\r
932  * Release a DHCP lease.\r
933  *\r
934  * @param netif network interface which must release its lease\r
935  */\r
936 err_t dhcp_release(struct netif *netif)\r
937 {\r
938   struct dhcp *dhcp = netif->dhcp;\r
939   err_t result;\r
940   u16_t msecs;\r
941   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_release()\n"));\r
942 \r
943   /* idle DHCP client */\r
944   dhcp_set_state(dhcp, DHCP_OFF);\r
945   /* clean old DHCP offer */\r
946   dhcp->server_ip_addr.addr = 0;\r
947   dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;\r
948   dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;\r
949   dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;\r
950   dhcp->dns_count = 0;\r
951   \r
952   /* create and initialize the DHCP message header */\r
953   result = dhcp_create_request(netif);\r
954   if (result == ERR_OK) {\r
955     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
956     dhcp_option_byte(dhcp, DHCP_RELEASE);\r
957 \r
958     dhcp_option_trailer(dhcp);\r
959 \r
960     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
961 \r
962     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
963     udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);\r
964     udp_send(dhcp->pcb, dhcp->p_out);\r
965     dhcp_delete_request(netif);\r
966     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));\r
967   } else {\r
968     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));\r
969   }\r
970   dhcp->tries++;\r
971   msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\r
972   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
973   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));\r
974   /* bring the interface down */\r
975   netif_set_down(netif);\r
976   /* remove IP address from interface */\r
977   netif_set_ipaddr(netif, IP_ADDR_ANY);\r
978   netif_set_gw(netif, IP_ADDR_ANY);\r
979   netif_set_netmask(netif, IP_ADDR_ANY);\r
980   \r
981   /* TODO: netif_down(netif); */\r
982   return result;\r
983 }\r
984 /**\r
985  * Remove the DHCP client from the interface.\r
986  *\r
987  * @param netif The network interface to stop DHCP on\r
988  */\r
989 void dhcp_stop(struct netif *netif)\r
990 {\r
991   struct dhcp *dhcp = netif->dhcp;\r
992   LWIP_ASSERT("dhcp_stop: netif != NULL", netif != NULL);\r
993 \r
994   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_stop()\n"));\r
995   /* netif is DHCP configured? */\r
996   if (dhcp != NULL)\r
997   {\r
998     if (dhcp->pcb != NULL)\r
999     {\r
1000       udp_remove(dhcp->pcb);\r
1001       dhcp->pcb = NULL;\r
1002     }\r
1003     if (dhcp->p != NULL)\r
1004     {\r
1005       pbuf_free(dhcp->p);\r
1006       dhcp->p = NULL;\r
1007     }\r
1008     /* free unfolded reply */\r
1009     dhcp_free_reply(dhcp);\r
1010     mem_free((void *)dhcp);\r
1011     netif->dhcp = NULL;\r
1012   }\r
1013 }\r
1014 \r
1015 /*\r
1016  * Set the DHCP state of a DHCP client.\r
1017  *\r
1018  * If the state changed, reset the number of tries.\r
1019  *\r
1020  * TODO: we might also want to reset the timeout here?\r
1021  */\r
1022 static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state)\r
1023 {\r
1024   if (new_state != dhcp->state)\r
1025   {\r
1026     dhcp->state = new_state;\r
1027     dhcp->tries = 0;\r
1028   }\r
1029 }\r
1030 \r
1031 /*\r
1032  * Concatenate an option type and length field to the outgoing\r
1033  * DHCP message.\r
1034  *\r
1035  */\r
1036 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)\r
1037 {\r
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);\r
1039   dhcp->msg_out->options[dhcp->options_out_len++] = option_type;\r
1040   dhcp->msg_out->options[dhcp->options_out_len++] = option_len;\r
1041 }\r
1042 /*\r
1043  * Concatenate a single byte to the outgoing DHCP message.\r
1044  *\r
1045  */\r
1046 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value)\r
1047 {\r
1048   LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
1049   dhcp->msg_out->options[dhcp->options_out_len++] = value;\r
1050 }\r
1051 static void dhcp_option_short(struct dhcp *dhcp, u16_t value)\r
1052 {\r
1053   LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN);\r
1054   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff00U) >> 8;\r
1055   dhcp->msg_out->options[dhcp->options_out_len++] =  value & 0x00ffU;\r
1056 }\r
1057 static void dhcp_option_long(struct dhcp *dhcp, u32_t value)\r
1058 {\r
1059   LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN);\r
1060   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff000000UL) >> 24;\r
1061   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x00ff0000UL) >> 16;\r
1062   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x0000ff00UL) >> 8;\r
1063   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x000000ffUL);\r
1064 }\r
1065 \r
1066 /**\r
1067  * Extract the DHCP message and the DHCP options.\r
1068  *\r
1069  * Extract the DHCP message and the DHCP options, each into a contiguous\r
1070  * piece of memory. As a DHCP message is variable sized by its options,\r
1071  * and also allows overriding some fields for options, the easy approach\r
1072  * is to first unfold the options into a conitguous piece of memory, and\r
1073  * use that further on.\r
1074  *\r
1075  */\r
1076 static err_t dhcp_unfold_reply(struct dhcp *dhcp)\r
1077 {\r
1078   struct pbuf *p = dhcp->p;\r
1079   u8_t *ptr;\r
1080   u16_t i;\r
1081   u16_t j = 0;\r
1082   LWIP_ASSERT("dhcp->p != NULL", dhcp->p != NULL);\r
1083   /* free any left-overs from previous unfolds */\r
1084   dhcp_free_reply(dhcp);\r
1085   /* options present? */\r
1086   if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN))\r
1087   {\r
1088     dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);\r
1089     dhcp->options_in = mem_malloc(dhcp->options_in_len);\r
1090     if (dhcp->options_in == NULL)\r
1091     {\r
1092       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));\r
1093       return ERR_MEM;\r
1094     }\r
1095   }\r
1096   dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);\r
1097   if (dhcp->msg_in == NULL)\r
1098   {\r
1099     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));\r
1100     mem_free((void *)dhcp->options_in);\r
1101     dhcp->options_in = NULL;\r
1102     return ERR_MEM;\r
1103   }\r
1104 \r
1105   ptr = (u8_t *)dhcp->msg_in;\r
1106   /* proceed through struct dhcp_msg */\r
1107   for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++)\r
1108   {\r
1109     *ptr++ = ((u8_t *)p->payload)[j++];\r
1110     /* reached end of pbuf? */\r
1111     if (j == p->len)\r
1112     {\r
1113       /* proceed to next pbuf in chain */\r
1114       p = p->next;\r
1115       j = 0;\r
1116     }\r
1117   }\r
1118   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", i));\r
1119   if (dhcp->options_in != NULL) {\r
1120     ptr = (u8_t *)dhcp->options_in;\r
1121     /* proceed through options */\r
1122     for (i = 0; i < dhcp->options_in_len; i++) {\r
1123       *ptr++ = ((u8_t *)p->payload)[j++];\r
1124       /* reached end of pbuf? */\r
1125       if (j == p->len) {\r
1126         /* proceed to next pbuf in chain */\r
1127         p = p->next;\r
1128         j = 0;\r
1129       }\r
1130     }\r
1131     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", i));\r
1132   }\r
1133   return ERR_OK;\r
1134 }\r
1135 \r
1136 /**\r
1137  * Free the incoming DHCP message including contiguous copy of\r
1138  * its DHCP options.\r
1139  *\r
1140  */\r
1141 static void dhcp_free_reply(struct dhcp *dhcp)\r
1142 {\r
1143   if (dhcp->msg_in != NULL) {\r
1144     mem_free((void *)dhcp->msg_in);\r
1145     dhcp->msg_in = NULL;\r
1146   }\r
1147   if (dhcp->options_in) {\r
1148     mem_free((void *)dhcp->options_in);\r
1149     dhcp->options_in = NULL;\r
1150     dhcp->options_in_len = 0;\r
1151   }\r
1152   LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));\r
1153 }\r
1154 \r
1155 \r
1156 /**\r
1157  * If an incoming DHCP message is in response to us, then trigger the state machine\r
1158  */\r
1159 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)\r
1160 {\r
1161   struct netif *netif = (struct netif *)arg;\r
1162   struct dhcp *dhcp = netif->dhcp;\r
1163   struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;\r
1164   u8_t *options_ptr;\r
1165   u8_t msg_type;\r
1166   u8_t i;\r
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,\r
1168     (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),\r
1169     (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));\r
1170   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));\r
1171   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));\r
1172   /* prevent warnings about unused arguments */\r
1173   (void)pcb; (void)addr; (void)port;\r
1174   dhcp->p = p;\r
1175   /* TODO: check packet length before reading them */\r
1176   if (reply_msg->op != DHCP_BOOTREPLY) {\r
1177     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));\r
1178     pbuf_free(p);\r
1179     dhcp->p = NULL;\r
1180     return;\r
1181   }\r
1182   /* iterate through hardware address and match against DHCP message */\r
1183   for (i = 0; i < netif->hwaddr_len; i++) {\r
1184     if (netif->hwaddr[i] != reply_msg->chaddr[i]) {\r
1185       LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",\r
1186         (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));\r
1187       pbuf_free(p);\r
1188       dhcp->p = NULL;\r
1189       return;\r
1190     }\r
1191   }\r
1192   /* match transaction ID against what we expected */\r
1193   if (ntohl(reply_msg->xid) != dhcp->xid) {\r
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));\r
1195     pbuf_free(p);\r
1196     dhcp->p = NULL;\r
1197     return;\r
1198   }\r
1199   /* option fields could be unfold? */\r
1200   if (dhcp_unfold_reply(dhcp) != ERR_OK) {\r
1201     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));\r
1202     pbuf_free(p);\r
1203     dhcp->p = NULL;\r
1204     return;\r
1205   }\r
1206 \r
1207   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));\r
1208   /* obtain pointer to DHCP message type */\r
1209   options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);\r
1210   if (options_ptr == NULL) {\r
1211     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));\r
1212     pbuf_free(p);\r
1213     dhcp->p = NULL;\r
1214     return;\r
1215   }\r
1216 \r
1217   /* read DHCP message type */\r
1218   msg_type = dhcp_get_option_byte(options_ptr + 2);\r
1219   /* message type is DHCP ACK? */\r
1220   if (msg_type == DHCP_ACK) {\r
1221     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_ACK received\n"));\r
1222     /* in requesting state? */\r
1223     if (dhcp->state == DHCP_REQUESTING) {\r
1224       dhcp_handle_ack(netif);\r
1225       dhcp->request_timeout = 0;\r
1226 #if DHCP_DOES_ARP_CHECK\r
1227       /* check if the acknowledged lease address is already in use */\r
1228       dhcp_check(netif);\r
1229 #else\r
1230       /* bind interface to the acknowledged lease address */\r
1231       dhcp_bind(netif);\r
1232 #endif\r
1233     }\r
1234     /* already bound to the given lease address? */\r
1235     else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {\r
1236       dhcp->request_timeout = 0;\r
1237       dhcp_bind(netif);\r
1238     }\r
1239   }\r
1240   /* received a DHCP_NAK in appropriate state? */\r
1241   else if ((msg_type == DHCP_NAK) &&\r
1242     ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||\r
1243      (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {\r
1244     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_NAK received\n"));\r
1245     dhcp->request_timeout = 0;\r
1246     dhcp_handle_nak(netif);\r
1247   }\r
1248   /* received a DHCP_OFFER in DHCP_SELECTING state? */\r
1249   else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {\r
1250     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));\r
1251     dhcp->request_timeout = 0;\r
1252     /* remember offered lease */\r
1253     dhcp_handle_offer(netif);\r
1254   }\r
1255   pbuf_free(p);\r
1256   dhcp->p = NULL;\r
1257 }\r
1258 \r
1259 \r
1260 static err_t dhcp_create_request(struct netif *netif)\r
1261 {\r
1262   struct dhcp *dhcp = netif->dhcp;\r
1263   u16_t i;\r
1264   LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);\r
1265   LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);\r
1266   dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);\r
1267   if (dhcp->p_out == NULL) {\r
1268     LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));\r
1269     return ERR_MEM;\r
1270   }\r
1271   /* give unique transaction identifier to this request */\r
1272   dhcp->xid = xid++;\r
1273   LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));\r
1274 \r
1275   dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;\r
1276 \r
1277   dhcp->msg_out->op = DHCP_BOOTREQUEST;\r
1278   /* TODO: make link layer independent */\r
1279   dhcp->msg_out->htype = DHCP_HTYPE_ETH;\r
1280   /* TODO: make link layer independent */\r
1281   dhcp->msg_out->hlen = DHCP_HLEN_ETH;\r
1282   dhcp->msg_out->hops = 0;\r
1283   dhcp->msg_out->xid = htonl(dhcp->xid);\r
1284   dhcp->msg_out->secs = 0;\r
1285   dhcp->msg_out->flags = 0;\r
1286   dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;\r
1287   dhcp->msg_out->yiaddr.addr = 0;\r
1288   dhcp->msg_out->siaddr.addr = 0;\r
1289   dhcp->msg_out->giaddr.addr = 0;\r
1290   for (i = 0; i < DHCP_CHADDR_LEN; i++) {\r
1291     /* copy netif hardware address, pad with zeroes */\r
1292     dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;\r
1293   }\r
1294   for (i = 0; i < DHCP_SNAME_LEN; i++) dhcp->msg_out->sname[i] = 0;\r
1295   for (i = 0; i < DHCP_FILE_LEN; i++) dhcp->msg_out->file[i] = 0;\r
1296   dhcp->msg_out->cookie = htonl(0x63825363UL);\r
1297   dhcp->options_out_len = 0;\r
1298   /* fill options field with an incrementing array (for debugging purposes) */\r
1299   for (i = 0; i < DHCP_OPTIONS_LEN; i++) dhcp->msg_out->options[i] = i;\r
1300   return ERR_OK;\r
1301 }\r
1302 \r
1303 static void dhcp_delete_request(struct netif *netif)\r
1304 {\r
1305   struct dhcp *dhcp = netif->dhcp;\r
1306   LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);\r
1307   LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);\r
1308   pbuf_free(dhcp->p_out);\r
1309   dhcp->p_out = NULL;\r
1310   dhcp->msg_out = NULL;\r
1311 }\r
1312 \r
1313 /**\r
1314  * Add a DHCP message trailer\r
1315  *\r
1316  * Adds the END option to the DHCP message, and if\r
1317  * necessary, up to three padding bytes.\r
1318  */\r
1319 \r
1320 static void dhcp_option_trailer(struct dhcp *dhcp)\r
1321 {\r
1322   LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);\r
1323   LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
1324   dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;\r
1325   /* packet is too small, or not 4 byte aligned? */\r
1326   while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {\r
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)); */\r
1328     LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
1329     /* add a fill/padding byte */\r
1330     dhcp->msg_out->options[dhcp->options_out_len++] = 0;\r
1331   }\r
1332 }\r
1333 \r
1334 /**\r
1335  * Find the offset of a DHCP option inside the DHCP message.\r
1336  *\r
1337  * @param client DHCP client\r
1338  * @param option_type\r
1339  *\r
1340  * @return a byte offset into the UDP message where the option was found, or\r
1341  * zero if the given option was not found.\r
1342  */\r
1343 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)\r
1344 {\r
1345   u8_t overload = DHCP_OVERLOAD_NONE;\r
1346 \r
1347   /* options available? */\r
1348   if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {\r
1349     /* start with options field */\r
1350     u8_t *options = (u8_t *)dhcp->options_in;\r
1351     u16_t offset = 0;\r
1352     /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */\r
1353     while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {\r
1354       /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */\r
1355       /* are the sname and/or file field overloaded with options? */\r
1356       if (options[offset] == DHCP_OPTION_OVERLOAD) {\r
1357         LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("overloaded message detected\n"));\r
1358         /* skip option type and length */\r
1359         offset += 2;\r
1360         overload = options[offset++];\r
1361       }\r
1362       /* requested option found */\r
1363       else if (options[offset] == option_type) {\r
1364         LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));\r
1365         return &options[offset];\r
1366       /* skip option */\r
1367       } else {\r
1368          LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));\r
1369         /* skip option type */\r
1370         offset++;\r
1371         /* skip option length, and then length bytes */\r
1372         offset += 1 + options[offset];\r
1373       }\r
1374     }\r
1375     /* is this an overloaded message? */\r
1376     if (overload != DHCP_OVERLOAD_NONE) {\r
1377       u16_t field_len;\r
1378       if (overload == DHCP_OVERLOAD_FILE) {\r
1379         LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded file field\n"));\r
1380         options = (u8_t *)&dhcp->msg_in->file;\r
1381         field_len = DHCP_FILE_LEN;\r
1382       } else if (overload == DHCP_OVERLOAD_SNAME) {\r
1383         LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname field\n"));\r
1384         options = (u8_t *)&dhcp->msg_in->sname;\r
1385         field_len = DHCP_SNAME_LEN;\r
1386       /* TODO: check if else if () is necessary */\r
1387       } else {\r
1388         LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname and file field\n"));\r
1389         options = (u8_t *)&dhcp->msg_in->sname;\r
1390         field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;\r
1391       }\r
1392       offset = 0;\r
1393 \r
1394       /* at least 1 byte to read and no end marker */\r
1395       while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {\r
1396         if (options[offset] == option_type) {\r
1397            LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));\r
1398           return &options[offset];\r
1399         /* skip option */\r
1400         } else {\r
1401           LWIP_DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));\r
1402           /* skip option type */\r
1403           offset++;\r
1404           offset += 1 + options[offset];\r
1405         }\r
1406       }\r
1407     }\r
1408   }\r
1409   return NULL;\r
1410 }\r
1411 \r
1412 /**\r
1413  * Return the byte of DHCP option data.\r
1414  *\r
1415  * @param client DHCP client.\r
1416  * @param ptr pointer obtained by dhcp_get_option_ptr().\r
1417  *\r
1418  * @return byte value at the given address.\r
1419  */\r
1420 static u8_t dhcp_get_option_byte(u8_t *ptr)\r
1421 {\r
1422   LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));\r
1423   return *ptr;\r
1424 }\r
1425 \r
1426 #if 0\r
1427 /**\r
1428  * Return the 16-bit value of DHCP option data.\r
1429  *\r
1430  * @param client DHCP client.\r
1431  * @param ptr pointer obtained by dhcp_get_option_ptr().\r
1432  *\r
1433  * @return byte value at the given address.\r
1434  */\r
1435 static u16_t dhcp_get_option_short(u8_t *ptr)\r
1436 {\r
1437   u16_t value;\r
1438   value = *ptr++ << 8;\r
1439   value |= *ptr;\r
1440   LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));\r
1441   return value;\r
1442 }\r
1443 #endif\r
1444 \r
1445 /**\r
1446  * Return the 32-bit value of DHCP option data.\r
1447  *\r
1448  * @param client DHCP client.\r
1449  * @param ptr pointer obtained by dhcp_get_option_ptr().\r
1450  *\r
1451  * @return byte value at the given address.\r
1452  */\r
1453 static u32_t dhcp_get_option_long(u8_t *ptr)\r
1454 {\r
1455   u32_t value;\r
1456   value = (u32_t)(*ptr++) << 24;\r
1457   value |= (u32_t)(*ptr++) << 16;\r
1458   value |= (u32_t)(*ptr++) << 8;\r
1459   value |= (u32_t)(*ptr++);\r
1460   LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));\r
1461   return value;\r
1462 }\r
1463 \r
1464 #endif /* LWIP_DHCP */\r