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