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