ReactOS 0.4.16-dev-1165-g40721f4
dhcp6.c
Go to the documentation of this file.
1
27/*
28 * Copyright (c) 2018 Simon Goldschmidt
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without modification,
32 * are permitted provided that the following conditions are met:
33 *
34 * 1. Redistributions of source code must retain the above copyright notice,
35 * this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright notice,
37 * this list of conditions and the following disclaimer in the documentation
38 * and/or other materials provided with the distribution.
39 * 3. The name of the author may not be used to endorse or promote products
40 * derived from this software without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
43 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
44 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
45 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
46 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
47 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
48 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
49 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
50 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
51 * OF SUCH DAMAGE.
52 *
53 * This file is part of the lwIP TCP/IP stack.
54 *
55 * Author: Simon Goldschmidt <goldsimon@gmx.de>
56 */
57
58#include "lwip/opt.h"
59
60#if LWIP_IPV6 && LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
61
62#include "lwip/dhcp6.h"
63#include "lwip/prot/dhcp6.h"
64#include "lwip/def.h"
65#include "lwip/udp.h"
66#include "lwip/dns.h"
67
68#include <string.h>
69
70#ifdef LWIP_HOOK_FILENAME
71#include LWIP_HOOK_FILENAME
72#endif
73#ifndef LWIP_HOOK_DHCP6_APPEND_OPTIONS
74#define LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, state, msg, msg_type, options_len_ptr, max_len)
75#endif
76#ifndef LWIP_HOOK_DHCP6_PARSE_OPTION
77#define LWIP_HOOK_DHCP6_PARSE_OPTION(netif, dhcp6, state, msg, msg_type, option, len, pbuf, offset) do { LWIP_UNUSED_ARG(msg); } while(0)
78#endif
79
80#if LWIP_DNS && LWIP_DHCP6_MAX_DNS_SERVERS
81#if DNS_MAX_SERVERS > LWIP_DHCP6_MAX_DNS_SERVERS
82#define LWIP_DHCP6_PROVIDE_DNS_SERVERS LWIP_DHCP6_MAX_DNS_SERVERS
83#else
84#define LWIP_DHCP6_PROVIDE_DNS_SERVERS DNS_MAX_SERVERS
85#endif
86#else
87#define LWIP_DHCP6_PROVIDE_DNS_SERVERS 0
88#endif
89
90
96enum dhcp6_option_idx {
97 DHCP6_OPTION_IDX_CLI_ID = 0,
98 DHCP6_OPTION_IDX_SERVER_ID,
99#if LWIP_DHCP6_PROVIDE_DNS_SERVERS
100 DHCP6_OPTION_IDX_DNS_SERVER,
101 DHCP6_OPTION_IDX_DOMAIN_LIST,
102#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
103#if LWIP_DHCP6_GET_NTP_SRV
104 DHCP6_OPTION_IDX_NTP_SERVER,
105#endif /* LWIP_DHCP_GET_NTP_SRV */
106 DHCP6_OPTION_IDX_MAX
107};
108
109struct dhcp6_option_info {
110 u8_t option_given;
111 u16_t val_start;
112 u16_t val_length;
113};
114
116struct dhcp6_option_info dhcp6_rx_options[DHCP6_OPTION_IDX_MAX];
117
118#define dhcp6_option_given(dhcp6, idx) (dhcp6_rx_options[idx].option_given != 0)
119#define dhcp6_got_option(dhcp6, idx) (dhcp6_rx_options[idx].option_given = 1)
120#define dhcp6_clear_option(dhcp6, idx) (dhcp6_rx_options[idx].option_given = 0)
121#define dhcp6_clear_all_options(dhcp6) (memset(dhcp6_rx_options, 0, sizeof(dhcp6_rx_options)))
122#define dhcp6_get_option_start(dhcp6, idx) (dhcp6_rx_options[idx].val_start)
123#define dhcp6_get_option_length(dhcp6, idx) (dhcp6_rx_options[idx].val_length)
124#define dhcp6_set_option(dhcp6, idx, start, len) do { dhcp6_rx_options[idx].val_start = (start); dhcp6_rx_options[idx].val_length = (len); }while(0)
125
126
127const ip_addr_t dhcp6_All_DHCP6_Relay_Agents_and_Servers = IPADDR6_INIT_HOST(0xFF020000, 0, 0, 0x00010002);
128const ip_addr_t dhcp6_All_DHCP6_Servers = IPADDR6_INIT_HOST(0xFF020000, 0, 0, 0x00010003);
129
130static struct udp_pcb *dhcp6_pcb;
131static u8_t dhcp6_pcb_refcount;
132
133
134/* receive, unfold, parse and free incoming messages */
135static void dhcp6_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
136
138static err_t
139dhcp6_inc_pcb_refcount(void)
140{
141 if (dhcp6_pcb_refcount == 0) {
142 LWIP_ASSERT("dhcp6_inc_pcb_refcount(): memory leak", dhcp6_pcb == NULL);
143
144 /* allocate UDP PCB */
145 dhcp6_pcb = udp_new_ip6();
146
147 if (dhcp6_pcb == NULL) {
148 return ERR_MEM;
149 }
150
151 ip_set_option(dhcp6_pcb, SOF_BROADCAST);
152
153 /* set up local and remote port for the pcb -> listen on all interfaces on all src/dest IPs */
154 udp_bind(dhcp6_pcb, IP6_ADDR_ANY, DHCP6_CLIENT_PORT);
155 udp_recv(dhcp6_pcb, dhcp6_recv, NULL);
156 }
157
158 dhcp6_pcb_refcount++;
159
160 return ERR_OK;
161}
162
164static void
165dhcp6_dec_pcb_refcount(void)
166{
167 LWIP_ASSERT("dhcp6_pcb_refcount(): refcount error", (dhcp6_pcb_refcount > 0));
168 dhcp6_pcb_refcount--;
169
170 if (dhcp6_pcb_refcount == 0) {
171 udp_remove(dhcp6_pcb);
172 dhcp6_pcb = NULL;
173 }
174}
175
184void
185dhcp6_set_struct(struct netif *netif, struct dhcp6 *dhcp6)
186{
187 LWIP_ASSERT("netif != NULL", netif != NULL);
188 LWIP_ASSERT("dhcp6 != NULL", dhcp6 != NULL);
189 LWIP_ASSERT("netif already has a struct dhcp6 set", netif_dhcp6_data(netif) == NULL);
190
191 /* clear data structure */
192 memset(dhcp6, 0, sizeof(struct dhcp6));
193 /* dhcp6_set_state(&dhcp, DHCP6_STATE_OFF); */
194 netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, dhcp6);
195}
196
206void dhcp6_cleanup(struct netif *netif)
207{
208 LWIP_ASSERT("netif != NULL", netif != NULL);
209
210 if (netif_dhcp6_data(netif) != NULL) {
211 mem_free(netif_dhcp6_data(netif));
212 netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL);
213 }
214}
215
216static struct dhcp6*
217dhcp6_get_struct(struct netif *netif, const char *dbg_requester)
218{
219 struct dhcp6 *dhcp6 = netif_dhcp6_data(netif);
220 if (dhcp6 == NULL) {
221 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: mallocing new DHCPv6 client\n", dbg_requester));
222 dhcp6 = (struct dhcp6 *)mem_malloc(sizeof(struct dhcp6));
223 if (dhcp6 == NULL) {
224 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: could not allocate dhcp6\n", dbg_requester));
225 return NULL;
226 }
227
228 /* clear data structure, this implies DHCP6_STATE_OFF */
229 memset(dhcp6, 0, sizeof(struct dhcp6));
230 /* store this dhcp6 client in the netif */
231 netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, dhcp6);
232 } else {
233 /* already has DHCP6 client attached */
234 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("%s: using existing DHCPv6 client\n", dbg_requester));
235 }
236
237 if (!dhcp6->pcb_allocated) {
238 if (dhcp6_inc_pcb_refcount() != ERR_OK) { /* ensure DHCP6 PCB is allocated */
239 mem_free(dhcp6);
240 netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP6, NULL);
241 return NULL;
242 }
243 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("%s: allocated dhcp6\n", dbg_requester));
244 dhcp6->pcb_allocated = 1;
245 }
246 return dhcp6;
247}
248
249/*
250 * Set the DHCPv6 state
251 * If the state changed, reset the number of tries.
252 */
253static void
254dhcp6_set_state(struct dhcp6 *dhcp6, u8_t new_state, const char *dbg_caller)
255{
256 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("DHCPv6 state: %d -> %d (%s)\n",
257 dhcp6->state, new_state, dbg_caller));
258 if (new_state != dhcp6->state) {
259 dhcp6->state = new_state;
260 dhcp6->tries = 0;
261 dhcp6->request_timeout = 0;
262 }
263}
264
265static int
266dhcp6_stateless_enabled(struct dhcp6 *dhcp6)
267{
268 if ((dhcp6->state == DHCP6_STATE_STATELESS_IDLE) ||
269 (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG)) {
270 return 1;
271 }
272 return 0;
273}
274
275/*static int
276dhcp6_stateful_enabled(struct dhcp6 *dhcp6)
277{
278 if (dhcp6->state == DHCP6_STATE_OFF) {
279 return 0;
280 }
281 if (dhcp6_stateless_enabled(dhcp6)) {
282 return 0;
283 }
284 return 1;
285}*/
286
298err_t
299dhcp6_enable_stateful(struct netif *netif)
300{
302 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("stateful dhcp6 not implemented yet\n"));
303 return ERR_VAL;
304}
305
315err_t
316dhcp6_enable_stateless(struct netif *netif)
317{
318 struct dhcp6 *dhcp6;
319
320 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_enable_stateless(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
321
322 dhcp6 = dhcp6_get_struct(netif, "dhcp6_enable_stateless()");
323 if (dhcp6 == NULL) {
324 return ERR_MEM;
325 }
326 if (dhcp6_stateless_enabled(dhcp6)) {
327 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 already enabled\n"));
328 return ERR_OK;
329 } else if (dhcp6->state != DHCP6_STATE_OFF) {
330 /* stateful running */
331 /* @todo: stop stateful once it is implemented */
332 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): switching from stateful to stateless DHCPv6\n"));
333 }
334 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_enable_stateless(): stateless DHCPv6 enabled\n"));
335 dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_enable_stateless");
336 return ERR_OK;
337}
338
345void
346dhcp6_disable(struct netif *netif)
347{
348 struct dhcp6 *dhcp6;
349
350 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_disable(netif=%p) %c%c%"U16_F"\n", (void *)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
351
352 dhcp6 = netif_dhcp6_data(netif);
353 if (dhcp6 != NULL) {
354 if (dhcp6->state != DHCP6_STATE_OFF) {
355 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_disable(): DHCPv6 disabled (old state: %s)\n",
356 (dhcp6_stateless_enabled(dhcp6) ? "stateless" : "stateful")));
357 dhcp6_set_state(dhcp6, DHCP6_STATE_OFF, "dhcp6_disable");
358 if (dhcp6->pcb_allocated != 0) {
359 dhcp6_dec_pcb_refcount(); /* free DHCPv6 PCB if not needed any more */
360 dhcp6->pcb_allocated = 0;
361 }
362 }
363 }
364}
365
376static struct pbuf *
377dhcp6_create_msg(struct netif *netif, struct dhcp6 *dhcp6, u8_t message_type,
378 u16_t opt_len_alloc, u16_t *options_out_len)
379{
380 struct pbuf *p_out;
381 struct dhcp6_msg *msg_out;
382
383 LWIP_ERROR("dhcp6_create_msg: netif != NULL", (netif != NULL), return NULL;);
384 LWIP_ERROR("dhcp6_create_msg: dhcp6 != NULL", (dhcp6 != NULL), return NULL;);
385 p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp6_msg) + opt_len_alloc, PBUF_RAM);
386 if (p_out == NULL) {
388 ("dhcp6_create_msg(): could not allocate pbuf\n"));
389 return NULL;
390 }
391 LWIP_ASSERT("dhcp6_create_msg: check that first pbuf can hold struct dhcp6_msg",
392 (p_out->len >= sizeof(struct dhcp6_msg) + opt_len_alloc));
393
394 /* @todo: limit new xid for certain message types? */
395 /* reuse transaction identifier in retransmissions */
396 if (dhcp6->tries == 0) {
397 dhcp6->xid = LWIP_RAND() & 0xFFFFFF;
398 }
399
401 ("transaction id xid(%"X32_F")\n", dhcp6->xid));
402
403 msg_out = (struct dhcp6_msg *)p_out->payload;
404 memset(msg_out, 0, sizeof(struct dhcp6_msg) + opt_len_alloc);
405
406 msg_out->msgtype = message_type;
407 msg_out->transaction_id[0] = (u8_t)(dhcp6->xid >> 16);
408 msg_out->transaction_id[1] = (u8_t)(dhcp6->xid >> 8);
409 msg_out->transaction_id[2] = (u8_t)dhcp6->xid;
410 *options_out_len = 0;
411 return p_out;
412}
413
414static u16_t
415dhcp6_option_short(u16_t options_out_len, u8_t *options, u16_t value)
416{
417 options[options_out_len++] = (u8_t)((value & 0xff00U) >> 8);
418 options[options_out_len++] = (u8_t) (value & 0x00ffU);
419 return options_out_len;
420}
421
422static u16_t
423dhcp6_option_optionrequest(u16_t options_out_len, u8_t *options, const u16_t *req_options,
424 u16_t num_req_options, u16_t max_len)
425{
426 size_t i;
427 u16_t ret;
428
429 LWIP_ASSERT("dhcp6_option_optionrequest: options_out_len + sizeof(struct dhcp6_msg) + addlen <= max_len",
430 sizeof(struct dhcp6_msg) + options_out_len + 4U + (2U * num_req_options) <= max_len);
431 LWIP_UNUSED_ARG(max_len);
432
433 ret = dhcp6_option_short(options_out_len, options, DHCP6_OPTION_ORO);
434 ret = dhcp6_option_short(ret, options, 2 * num_req_options);
435 for (i = 0; i < num_req_options; i++) {
436 ret = dhcp6_option_short(ret, options, req_options[i]);
437 }
438 return ret;
439}
440
441/* All options are added, shrink the pbuf to the required size */
442static void
443dhcp6_msg_finalize(u16_t options_out_len, struct pbuf *p_out)
444{
445 /* shrink the pbuf to the actual content length */
446 pbuf_realloc(p_out, (u16_t)(sizeof(struct dhcp6_msg) + options_out_len));
447}
448
449
450#if LWIP_IPV6_DHCP6_STATELESS
451static void
452dhcp6_information_request(struct netif *netif, struct dhcp6 *dhcp6)
453{
454 const u16_t requested_options[] = {
455#if LWIP_DHCP6_PROVIDE_DNS_SERVERS
458#endif
459#if LWIP_DHCP6_GET_NTP_SRV
461#endif
462 };
463
464 u16_t msecs;
465 struct pbuf *p_out;
466 u16_t options_out_len;
467 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_information_request()\n"));
468 /* create and initialize the DHCP message header */
469 p_out = dhcp6_create_msg(netif, dhcp6, DHCP6_INFOREQUEST, 4 + sizeof(requested_options), &options_out_len);
470 if (p_out != NULL) {
471 err_t err;
472 struct dhcp6_msg *msg_out = (struct dhcp6_msg *)p_out->payload;
473 u8_t *options = (u8_t *)(msg_out + 1);
474 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_information_request: making request\n"));
475
476 options_out_len = dhcp6_option_optionrequest(options_out_len, options, requested_options,
477 LWIP_ARRAYSIZE(requested_options), p_out->len);
478 LWIP_HOOK_DHCP6_APPEND_OPTIONS(netif, dhcp6, DHCP6_STATE_REQUESTING_CONFIG, msg_out,
479 DHCP6_INFOREQUEST, options_out_len, p_out->len);
480 dhcp6_msg_finalize(options_out_len, p_out);
481
482 err = udp_sendto_if(dhcp6_pcb, p_out, &dhcp6_All_DHCP6_Relay_Agents_and_Servers, DHCP6_SERVER_PORT, netif);
483 pbuf_free(p_out);
484 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_information_request: INFOREQUESTING -> %d\n", (int)err));
486 } else {
487 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp6_information_request: could not allocate DHCP6 request\n"));
488 }
489 dhcp6_set_state(dhcp6, DHCP6_STATE_REQUESTING_CONFIG, "dhcp6_information_request");
490 if (dhcp6->tries < 255) {
491 dhcp6->tries++;
492 }
493 msecs = (u16_t)((dhcp6->tries < 6 ? 1 << dhcp6->tries : 60) * 1000);
494 dhcp6->request_timeout = (u16_t)((msecs + DHCP6_TIMER_MSECS - 1) / DHCP6_TIMER_MSECS);
495 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_information_request(): set request timeout %"U16_F" msecs\n", msecs));
496}
497
498static err_t
499dhcp6_request_config(struct netif *netif, struct dhcp6 *dhcp6)
500{
501 /* stateless mode enabled and no request running? */
502 if (dhcp6->state == DHCP6_STATE_STATELESS_IDLE) {
503 /* send Information-request and wait for answer; setup receive timeout */
504 dhcp6_information_request(netif, dhcp6);
505 }
506
507 return ERR_OK;
508}
509
510static void
511dhcp6_abort_config_request(struct dhcp6 *dhcp6)
512{
513 if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) {
514 /* abort running request */
515 dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_abort_config_request");
516 }
517}
518
519/* Handle a REPLY to INFOREQUEST
520 * This parses DNS and NTP server addresses from the reply.
521 */
522static void
523dhcp6_handle_config_reply(struct netif *netif, struct pbuf *p_msg_in)
524{
525 struct dhcp6 *dhcp6 = netif_dhcp6_data(netif);
526
527 LWIP_UNUSED_ARG(dhcp6);
528 LWIP_UNUSED_ARG(p_msg_in);
529
530#if LWIP_DHCP6_PROVIDE_DNS_SERVERS
531 if (dhcp6_option_given(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER)) {
532 ip_addr_t dns_addr;
533 ip6_addr_t *dns_addr6;
534 u16_t op_start = dhcp6_get_option_start(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER);
535 u16_t op_len = dhcp6_get_option_length(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER);
536 u16_t idx;
537 u8_t n;
538
539 ip_addr_set_zero_ip6(&dns_addr);
540 dns_addr6 = ip_2_ip6(&dns_addr);
541 for (n = 0, idx = op_start; (idx < op_start + op_len) && (n < LWIP_DHCP6_PROVIDE_DNS_SERVERS);
542 n++, idx += sizeof(struct ip6_addr_packed)) {
543 u16_t copied = pbuf_copy_partial(p_msg_in, dns_addr6, sizeof(struct ip6_addr_packed), idx);
544 if (copied != sizeof(struct ip6_addr_packed)) {
545 /* pbuf length mismatch */
546 return;
547 }
548 ip6_addr_assign_zone(dns_addr6, IP6_UNKNOWN, netif);
549 /* @todo: do we need a different offset than DHCP(v4)? */
550 dns_setserver(n, &dns_addr);
551 }
552 }
553 /* @ todo: parse and set Domain Search List */
554#endif /* LWIP_DHCP6_PROVIDE_DNS_SERVERS */
555
556#if LWIP_DHCP6_GET_NTP_SRV
557 if (dhcp6_option_given(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER)) {
558 ip_addr_t ntp_server_addrs[LWIP_DHCP6_MAX_NTP_SERVERS];
559 u16_t op_start = dhcp6_get_option_start(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER);
560 u16_t op_len = dhcp6_get_option_length(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER);
561 u16_t idx;
562 u8_t n;
563
564 for (n = 0, idx = op_start; (idx < op_start + op_len) && (n < LWIP_DHCP6_MAX_NTP_SERVERS);
565 n++, idx += sizeof(struct ip6_addr_packed)) {
566 u16_t copied;
567 ip6_addr_t *ntp_addr6 = ip_2_ip6(&ntp_server_addrs[n]);
568 ip_addr_set_zero_ip6(&ntp_server_addrs[n]);
569 copied = pbuf_copy_partial(p_msg_in, ntp_addr6, sizeof(struct ip6_addr_packed), idx);
570 if (copied != sizeof(struct ip6_addr_packed)) {
571 /* pbuf length mismatch */
572 return;
573 }
574 ip6_addr_assign_zone(ntp_addr6, IP6_UNKNOWN, netif);
575 }
576 dhcp6_set_ntp_servers(n, ntp_server_addrs);
577 }
578#endif /* LWIP_DHCP6_GET_NTP_SRV */
579}
580#endif /* LWIP_IPV6_DHCP6_STATELESS */
581
585void
586dhcp6_nd6_ra_trigger(struct netif *netif, u8_t managed_addr_config, u8_t other_config)
587{
588 struct dhcp6 *dhcp6;
589
590 LWIP_ASSERT("netif != NULL", netif != NULL);
591 dhcp6 = netif_dhcp6_data(netif);
592
593 LWIP_UNUSED_ARG(managed_addr_config);
594 LWIP_UNUSED_ARG(other_config);
595 LWIP_UNUSED_ARG(dhcp6);
596
597#if LWIP_IPV6_DHCP6_STATELESS
598 if (dhcp6 != NULL) {
599 if (dhcp6_stateless_enabled(dhcp6)) {
600 if (other_config) {
601 dhcp6_request_config(netif, dhcp6);
602 } else {
603 dhcp6_abort_config_request(dhcp6);
604 }
605 }
606 }
607#endif /* LWIP_IPV6_DHCP6_STATELESS */
608}
609
616static err_t
617dhcp6_parse_reply(struct pbuf *p, struct dhcp6 *dhcp6)
618{
620 u16_t offset_max;
621 u16_t options_idx;
622 struct dhcp6_msg *msg_in;
623
624 LWIP_UNUSED_ARG(dhcp6);
625
626 /* clear received options */
627 dhcp6_clear_all_options(dhcp6);
628 msg_in = (struct dhcp6_msg *)p->payload;
629
630 /* parse options */
631
632 options_idx = sizeof(struct dhcp6_msg);
633 /* parse options to the end of the received packet */
634 offset_max = p->tot_len;
635
636 offset = options_idx;
637 /* at least 4 byte to read? */
638 while ((offset + 4 <= offset_max)) {
639 u8_t op_len_buf[4];
640 u8_t *op_len;
641 u16_t op;
642 u16_t len;
643 u16_t val_offset = (u16_t)(offset + 4);
644 if (val_offset < offset) {
645 /* overflow */
646 return ERR_BUF;
647 }
648 /* copy option + length, might be split across pbufs */
649 op_len = (u8_t *)pbuf_get_contiguous(p, op_len_buf, 4, 4, offset);
650 if (op_len == NULL) {
651 /* failed to get option and length */
652 return ERR_VAL;
653 }
654 op = (op_len[0] << 8) | op_len[1];
655 len = (op_len[2] << 8) | op_len[3];
656 offset = val_offset + len;
657 if (offset < val_offset) {
658 /* overflow */
659 return ERR_BUF;
660 }
661
662 switch (op) {
664 dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_CLI_ID);
665 dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_CLI_ID, val_offset, len);
666 break;
668 dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_SERVER_ID);
669 dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_SERVER_ID, val_offset, len);
670 break;
671#if LWIP_DHCP6_PROVIDE_DNS_SERVERS
673 dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER);
674 dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_DNS_SERVER, val_offset, len);
675 break;
677 dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_DOMAIN_LIST);
678 dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_DOMAIN_LIST, val_offset, len);
679 break;
680#endif /* LWIP_DHCP6_PROVIDE_DNS_SERVERS */
681#if LWIP_DHCP6_GET_NTP_SRV
683 dhcp6_got_option(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER);
684 dhcp6_set_option(dhcp6, DHCP6_OPTION_IDX_NTP_SERVER, val_offset, len);
685 break;
686#endif /* LWIP_DHCP6_GET_NTP_SRV*/
687 default:
688 LWIP_DEBUGF(DHCP6_DEBUG, ("skipping option %"U16_F" in options\n", op));
689 LWIP_HOOK_DHCP6_PARSE_OPTION(ip_current_netif(), dhcp6, dhcp6->state, msg_in,
690 msg_in->msgtype, op, len, q, val_offset);
691 break;
692 }
693 }
694 return ERR_OK;
695}
696
697static void
698dhcp6_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
699{
701 struct dhcp6 *dhcp6 = netif_dhcp6_data(netif);
702 struct dhcp6_msg *reply_msg = (struct dhcp6_msg *)p->payload;
704 u32_t xid;
705
707
708 /* Caught DHCPv6 message from netif that does not have DHCPv6 enabled? -> not interested */
709 if ((dhcp6 == NULL) || (dhcp6->pcb_allocated == 0)) {
710 goto free_pbuf_and_return;
711 }
712
713 LWIP_ERROR("invalid server address type", IP_IS_V6(addr), goto free_pbuf_and_return;);
714
715 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_recv(pbuf = %p) from DHCPv6 server %s port %"U16_F"\n", (void *)p,
717 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
718 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
719 /* prevent warnings about unused arguments */
720 LWIP_UNUSED_ARG(pcb);
723
724 if (p->len < sizeof(struct dhcp6_msg)) {
725 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCPv6 reply message or pbuf too short\n"));
726 goto free_pbuf_and_return;
727 }
728
729 /* match transaction ID against what we expected */
730 xid = reply_msg->transaction_id[0] << 16;
731 xid |= reply_msg->transaction_id[1] << 8;
732 xid |= reply_msg->transaction_id[2];
733 if (xid != dhcp6->xid) {
735 ("transaction id mismatch reply_msg->xid(%"X32_F")!= dhcp6->xid(%"X32_F")\n", xid, dhcp6->xid));
736 goto free_pbuf_and_return;
737 }
738 /* option fields could be unfold? */
739 if (dhcp6_parse_reply(p, dhcp6) != ERR_OK) {
741 ("problem unfolding DHCPv6 message - too short on memory?\n"));
742 goto free_pbuf_and_return;
743 }
744
745 /* read DHCP message type */
746 msg_type = reply_msg->msgtype;
747 /* message type is DHCP6 REPLY? */
748 if (msg_type == DHCP6_REPLY) {
749 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("DHCP6_REPLY received\n"));
750#if LWIP_IPV6_DHCP6_STATELESS
751 /* in info-requesting state? */
752 if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) {
753 dhcp6_set_state(dhcp6, DHCP6_STATE_STATELESS_IDLE, "dhcp6_recv");
754 dhcp6_handle_config_reply(netif, p);
755 } else
756#endif /* LWIP_IPV6_DHCP6_STATELESS */
757 {
758 /* @todo: handle reply in other states? */
759 }
760 } else {
761 /* @todo: handle other message types */
762 }
763
764free_pbuf_and_return:
765 pbuf_free(p);
766}
767
774static void
775dhcp6_timeout(struct netif *netif, struct dhcp6 *dhcp6)
776{
777 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp6_timeout()\n"));
778
780 LWIP_UNUSED_ARG(dhcp6);
781
782#if LWIP_IPV6_DHCP6_STATELESS
783 /* back-off period has passed, or server selection timed out */
784 if (dhcp6->state == DHCP6_STATE_REQUESTING_CONFIG) {
785 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE, ("dhcp6_timeout(): retrying information request\n"));
786 dhcp6_information_request(netif, dhcp6);
787 }
788#endif /* LWIP_IPV6_DHCP6_STATELESS */
789}
790
798void
799dhcp6_tmr(void)
800{
801 struct netif *netif;
802 /* loop through netif's */
804 struct dhcp6 *dhcp6 = netif_dhcp6_data(netif);
805 /* only act on DHCPv6 configured interfaces */
806 if (dhcp6 != NULL) {
807 /* timer is active (non zero), and is about to trigger now */
808 if (dhcp6->request_timeout > 1) {
809 dhcp6->request_timeout--;
810 } else if (dhcp6->request_timeout == 1) {
811 dhcp6->request_timeout--;
812 /* { dhcp6->request_timeout == 0 } */
813 LWIP_DEBUGF(DHCP6_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp6_tmr(): request timeout\n"));
814 /* this client's request timeout triggered */
815 dhcp6_timeout(netif, dhcp6);
816 }
817 }
818 }
819}
820
821#endif /* LWIP_IPV6 && LWIP_IPV6_DHCP6 */
#define LWIP_ARRAYSIZE(x)
Definition: def.h:69
#define mem_free(ptr, bsize)
Definition: types.h:124
#define NULL
Definition: types.h:112
UINT op
Definition: effect.c:236
unsigned int idx
Definition: utils.c:41
USHORT port
Definition: uri.c:228
#define U16_F
Definition: cc.h:19
#define X32_F
Definition: cc.h:24
void * mem_malloc(mem_size_t size_in)
Definition: mem.c:831
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ERROR(message, expression, handler)
Definition: debug.h:130
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
#define ip_set_option(pcb, opt)
Definition: ip.h:230
#define ip_current_netif()
Definition: ip.h:146
#define SOF_BROADCAST
Definition: ip.h:112
#define ip_current_input_netif()
Definition: ip.h:150
#define ERR_MEM
Definition: fontsub.h:52
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLdouble n
Definition: glext.h:7729
GLintptr offset
Definition: glext.h:5920
GLenum const GLvoid * addr
Definition: glext.h:9621
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
uint32_t u32_t
Definition: arch.h:129
uint8_t u8_t
Definition: arch.h:125
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:373
uint16_t u16_t
Definition: arch.h:127
#define LWIP_DBG_LEVEL_SERIOUS
Definition: debug.h:57
#define LWIP_DBG_STATE
Definition: debug.h:85
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:55
#define LWIP_DBG_TRACE
Definition: debug.h:83
s8_t err_t
Definition: err.h:96
@ ERR_BUF
Definition: err.h:59
@ ERR_OK
Definition: err.h:55
@ ERR_VAL
Definition: err.h:67
#define DHCP_DEBUG
Definition: opt.h:3526
#define DHCP6_DEBUG
Definition: opt.h:3561
#define LWIP_DHCP6_MAX_NTP_SERVERS
Definition: opt.h:2776
void pbuf_realloc(struct pbuf *p, u16_t new_len)
Definition: pbuf.c:402
void * pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset)
Definition: pbuf.c:1105
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:224
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1058
@ PBUF_RAM
Definition: pbuf.h:152
@ PBUF_TRANSPORT
Definition: pbuf.h:93
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:356
ip6_addr_t ip_addr_t
Definition: ip_addr.h:344
#define IP_IS_V6(ipaddr)
Definition: ip_addr.h:350
#define ipaddr_ntoa(ipaddr)
Definition: ip_addr.h:385
#define IPADDR6_INIT_HOST(a, b, c, d)
Definition: ip_addr.h:346
#define ip_addr_set_zero_ip6(ipaddr)
Definition: ip_addr.h:366
#define NETIF_FOREACH(netif)
Definition: netif.h:424
LONGLONG xid
Definition: nfs41_driver.c:106
#define DHCP6_OPTION_SERVERID
Definition: dhcp6.h:110
#define DHCP6_OPTION_DNS_SERVERS
Definition: dhcp6.h:129
#define DHCP6_INFOREQUEST
Definition: dhcp6.h:88
#define DHCP6_OPTION_CLIENTID
Definition: dhcp6.h:109
#define DHCP6_OPTION_SNTP_SERVERS
Definition: dhcp6.h:131
#define DHCP6_OPTION_DOMAIN_LIST
Definition: dhcp6.h:130
#define DHCP6_OPTION_ORO
Definition: dhcp6.h:114
@ DHCP6_STATE_OFF
Definition: dhcp6.h:72
@ DHCP6_STATE_REQUESTING_CONFIG
Definition: dhcp6.h:74
@ DHCP6_STATE_STATELESS_IDLE
Definition: dhcp6.h:73
#define DHCP6_SERVER_PORT
Definition: dhcp6.h:47
#define DHCP6_CLIENT_PORT
Definition: dhcp6.h:46
#define DHCP6_REPLY
Definition: dhcp6.h:84
#define err(...)
msg_type
Definition: rpc_msg.h:77
#define memset(x, y, z)
Definition: compat.h:39
Definition: netif.h:269
char name[2]
Definition: netif.h:356
u8_t num
Definition: netif.h:359
Definition: pbuf.h:186
u16_t len
Definition: pbuf.h:203
void * payload
Definition: pbuf.h:191
Definition: pdh_main.c:96
int ret