iPXE
dhcpv6.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30#include <errno.h>
31#include <byteswap.h>
32#include <ipxe/interface.h>
33#include <ipxe/xfer.h>
34#include <ipxe/iobuf.h>
35#include <ipxe/open.h>
36#include <ipxe/netdevice.h>
37#include <ipxe/settings.h>
38#include <ipxe/retry.h>
39#include <ipxe/timer.h>
40#include <ipxe/in.h>
41#include <ipxe/crc32.h>
42#include <ipxe/errortab.h>
43#include <ipxe/ipv6.h>
44#include <ipxe/dhcparch.h>
45#include <ipxe/dhcpv6.h>
46
47/** @file
48 *
49 * Dynamic Host Configuration Protocol for IPv6
50 *
51 */
52
53/* Disambiguate the various error causes */
54#define EPROTO_UNSPECFAIL __einfo_error ( EINFO_EPROTO_UNSPECFAIL )
55#define EINFO_EPROTO_UNSPECFAIL \
56 __einfo_uniqify ( EINFO_EPROTO, 1, "Unspecified server failure" )
57#define EPROTO_NOADDRSAVAIL __einfo_error ( EINFO_EPROTO_NOADDRSAVAIL )
58#define EINFO_EPROTO_NOADDRSAVAIL \
59 __einfo_uniqify ( EINFO_EPROTO, 2, "No addresses available" )
60#define EPROTO_NOBINDING __einfo_error ( EINFO_EPROTO_NOBINDING )
61#define EINFO_EPROTO_NOBINDING \
62 __einfo_uniqify ( EINFO_EPROTO, 3, "Client record unavailable" )
63#define EPROTO_NOTONLINK __einfo_error ( EINFO_EPROTO_NOTONLINK )
64#define EINFO_EPROTO_NOTONLINK \
65 __einfo_uniqify ( EINFO_EPROTO, 4, "Prefix not on link" )
66#define EPROTO_USEMULTICAST __einfo_error ( EINFO_EPROTO_USEMULTICAST )
67#define EINFO_EPROTO_USEMULTICAST \
68 __einfo_uniqify ( EINFO_EPROTO, 5, "Use multicast address" )
69#define EPROTO_STATUS( status ) \
70 EUNIQ ( EINFO_EPROTO, ( (status) & 0x0f ), EPROTO_UNSPECFAIL, \
71 EPROTO_NOADDRSAVAIL, EPROTO_NOBINDING, \
72 EPROTO_NOTONLINK, EPROTO_USEMULTICAST )
73
74/** Human-readable error messages */
75struct errortab dhcpv6_errors[] __errortab = {
77};
78
79/****************************************************************************
80 *
81 * DHCPv6 option lists
82 *
83 */
84
85/** A DHCPv6 option list */
87 /** Data buffer */
88 const void *data;
89 /** Length of data buffer */
90 size_t len;
91};
92
93/**
94 * Find DHCPv6 option
95 *
96 * @v options DHCPv6 option list
97 * @v code Option code
98 * @ret option DHCPv6 option, or NULL if not found
99 */
100static const union dhcpv6_any_option *
101dhcpv6_option ( struct dhcpv6_option_list *options, unsigned int code ) {
102 const union dhcpv6_any_option *option = options->data;
103 size_t remaining = options->len;
104 size_t data_len;
105
106 /* Scan through list of options */
107 while ( remaining >= sizeof ( option->header ) ) {
108
109 /* Calculate and validate option length */
110 remaining -= sizeof ( option->header );
111 data_len = ntohs ( option->header.len );
112 if ( data_len > remaining ) {
113 /* Malformed option list */
114 return NULL;
115 }
116
117 /* Return if we have found the specified option */
118 if ( option->header.code == htons ( code ) )
119 return option;
120
121 /* Otherwise, move to the next option */
122 option = ( ( ( void * ) option->header.data ) + data_len );
123 remaining -= data_len;
124 }
125
126 return NULL;
127}
128
129/**
130 * Check DHCPv6 client or server identifier
131 *
132 * @v options DHCPv6 option list
133 * @v code Option code
134 * @v expected Expected value
135 * @v len Length of expected value
136 * @ret rc Return status code
137 */
139 unsigned int code, const void *expected,
140 size_t len ) {
141 const union dhcpv6_any_option *option;
142 const struct dhcpv6_duid_option *duid;
143
144 /* Find option */
146 if ( ! option )
147 return -ENOENT;
148 duid = &option->duid;
149
150 /* Check option length */
151 if ( ntohs ( duid->header.len ) != len )
152 return -EINVAL;
153
154 /* Compare option value */
155 if ( memcmp ( duid->duid, expected, len ) != 0 )
156 return -EINVAL;
157
158 return 0;
159}
160
161/**
162 * Get DHCPv6 status code
163 *
164 * @v options DHCPv6 option list
165 * @ret rc Return status code
166 */
168 const union dhcpv6_any_option *option;
169 const struct dhcpv6_status_code_option *status_code;
170 unsigned int status;
171
172 /* Find status code option, if present */
174 if ( ! option ) {
175 /* Omitted status code should be treated as "success" */
176 return 0;
177 }
178 status_code = &option->status_code;
179
180 /* Sanity check */
181 if ( ntohs ( status_code->header.len ) <
182 ( sizeof ( *status_code ) - sizeof ( status_code->header ) ) ) {
183 return -EINVAL;
184 }
185
186 /* Calculate iPXE error code from DHCPv6 status code */
187 status = ntohs ( status_code->status );
188 return ( status ? -EPROTO_STATUS ( status ) : 0 );
189}
190
191/**
192 * Get DHCPv6 identity association address
193 *
194 * @v options DHCPv6 option list
195 * @v iaid Identity association ID
196 * @v address IPv6 address to fill in
197 * @ret rc Return status code
198 */
200 struct in6_addr *address ) {
201 const union dhcpv6_any_option *option;
202 const struct dhcpv6_ia_na_option *ia_na;
203 const struct dhcpv6_iaaddr_option *iaaddr;
204 struct dhcpv6_option_list suboptions;
205 size_t len;
206 int rc;
207
208 /* Find identity association option, if present */
210 if ( ! option )
211 return -ENOENT;
212 ia_na = &option->ia_na;
213
214 /* Sanity check */
215 len = ntohs ( ia_na->header.len );
216 if ( len < ( sizeof ( *ia_na ) - sizeof ( ia_na->header ) ) )
217 return -EINVAL;
218
219 /* Check identity association ID */
220 if ( ia_na->iaid != htonl ( iaid ) )
221 return -EINVAL;
222
223 /* Construct IA_NA sub-options list */
224 suboptions.data = ia_na->options;
225 suboptions.len = ( len + sizeof ( ia_na->header ) -
226 offsetof ( typeof ( *ia_na ), options ) );
227
228 /* Check IA_NA status code */
229 if ( ( rc = dhcpv6_status_code ( &suboptions ) ) != 0 )
230 return rc;
231
232 /* Find identity association address, if present */
233 option = dhcpv6_option ( &suboptions, DHCPV6_IAADDR );
234 if ( ! option )
235 return -ENOENT;
236 iaaddr = &option->iaaddr;
237
238 /* Sanity check */
239 len = ntohs ( iaaddr->header.len );
240 if ( len < ( sizeof ( *iaaddr ) - sizeof ( iaaddr->header ) ) )
241 return -EINVAL;
242
243 /* Construct IAADDR sub-options list */
244 suboptions.data = iaaddr->options;
245 suboptions.len = ( len + sizeof ( iaaddr->header ) -
246 offsetof ( typeof ( *iaaddr ), options ) );
247
248 /* Check IAADDR status code */
249 if ( ( rc = dhcpv6_status_code ( &suboptions ) ) != 0 )
250 return rc;
251
252 /* Extract IPv6 address */
253 memcpy ( address, &iaaddr->address, sizeof ( *address ) );
254
255 return 0;
256}
257
258/****************************************************************************
259 *
260 * DHCPv6 settings blocks
261 *
262 */
263
264/** A DHCPv6 settings block */
266 /** Reference count */
268 /** Settings block */
270 /** Leased address */
272 /** Router address */
274 /** Option list */
276};
277
278/**
279 * Check applicability of DHCPv6 setting
280 *
281 * @v settings Settings block
282 * @v setting Setting
283 * @ret applies Setting applies within this settings block
284 */
286 const struct setting *setting ) {
287
288 return ( ( setting->scope == &dhcpv6_scope ) ||
290}
291
292/**
293 * Fetch value of DHCPv6 leased address
294 *
295 * @v dhcpv6set DHCPv6 settings
296 * @v data Buffer to fill with setting data
297 * @v len Length of buffer
298 * @ret len Length of setting data, or negative error
299 */
300static int dhcpv6_fetch_ip6 ( struct dhcpv6_settings *dhcpv6set,
301 void *data, size_t len ) {
302 struct in6_addr *lease = &dhcpv6set->lease;
303
304 /* Copy leased address */
305 if ( len > sizeof ( *lease ) )
306 len = sizeof ( *lease );
307 memcpy ( data, lease, len );
308
309 return sizeof ( *lease );
310}
311
312/**
313 * Fetch value of DHCPv6 implicit address prefix length
314 *
315 * @v dhcpv6set DHCPv6 settings
316 * @v data Buffer to fill with setting data
317 * @v len Length of buffer
318 * @ret len Length of setting data, or negative error
319 */
320static int dhcpv6_fetch_len6 ( struct dhcpv6_settings *dhcpv6set __unused,
321 void *data, size_t len ) {
322 uint8_t *len6 = data;
323
324 /* Default to assuming this is the only address on the link.
325 * If the address falls within a known prefix, then the IPv6
326 * routing table construction logic will match it against that
327 * prefix.
328 */
329 if ( len )
330 *len6 = IPV6_MAX_PREFIX_LEN;
331
332 return sizeof ( *len6 );
333}
334
335/**
336 * Fetch value of DHCPv6 router address
337 *
338 * @v dhcpv6set DHCPv6 settings
339 * @v data Buffer to fill with setting data
340 * @v len Length of buffer
341 * @ret len Length of setting data, or negative error
342 */
343static int dhcpv6_fetch_gateway6 ( struct dhcpv6_settings *dhcpv6set,
344 void *data, size_t len ) {
345 struct in6_addr *router = &dhcpv6set->router;
346
347 /* Copy router address */
348 if ( len > sizeof ( *router ) )
349 len = sizeof ( *router );
350 memcpy ( data, router, len );
351
352 return sizeof ( *router );
353}
354
355/** A DHCPv6 address setting operation */
357 /** Generic setting */
358 const struct setting *setting;
359 /**
360 * Fetch value of setting
361 *
362 * @v dhcpv6set DHCPv6 settings
363 * @v data Buffer to fill with setting data
364 * @v len Length of buffer
365 * @ret len Length of setting data, or negative error
366 */
367 int ( * fetch ) ( struct dhcpv6_settings *dhcpv6set,
368 void *data, size_t len );
369};
370
371/** DHCPv6 address settings operations */
377
378/**
379 * Fetch value of DHCPv6 setting
380 *
381 * @v settings Settings block
382 * @v setting Setting to fetch
383 * @v data Buffer to fill with setting data
384 * @v len Length of buffer
385 * @ret len Length of setting data, or negative error
386 */
387static int dhcpv6_fetch ( struct settings *settings,
388 struct setting *setting,
389 void *data, size_t len ) {
390 struct dhcpv6_settings *dhcpv6set =
392 const union dhcpv6_any_option *option;
394 size_t option_len;
395 unsigned int i;
396
397 /* Handle address settings */
398 for ( i = 0 ; i < ( sizeof ( dhcpv6_address_operations ) /
399 sizeof ( dhcpv6_address_operations[0] ) ) ; i++ ) {
401 if ( setting_cmp ( setting, op->setting ) != 0 )
402 continue;
403 if ( IN6_IS_ADDR_UNSPECIFIED ( &dhcpv6set->lease ) )
404 return -ENOENT;
405 return op->fetch ( dhcpv6set, data, len );
406 }
407
408 /* Find option */
409 option = dhcpv6_option ( &dhcpv6set->options, setting->tag );
410 if ( ! option )
411 return -ENOENT;
412
413 /* Copy option to data buffer */
414 option_len = ntohs ( option->header.len );
415 if ( len > option_len )
416 len = option_len;
417 memcpy ( data, option->header.data, len );
418 return option_len;
419}
420
421/** DHCPv6 settings operations */
423 .applies = dhcpv6_applies,
424 .fetch = dhcpv6_fetch,
425};
426
427/**
428 * Register DHCPv6 options as network device settings
429 *
430 * @v lease DHCPv6 leased address
431 * @v router DHCPv6 router address
432 * @v options DHCPv6 option list
433 * @v parent Parent settings block
434 * @ret rc Return status code
435 */
436static int dhcpv6_register ( struct in6_addr *lease, struct in6_addr *router,
438 struct settings *parent ) {
439 struct dhcpv6_settings *dhcpv6set;
440 void *data;
441 size_t len;
442 int rc;
443
444 /* Allocate and initialise structure */
445 dhcpv6set = zalloc ( sizeof ( *dhcpv6set ) + options->len );
446 if ( ! dhcpv6set ) {
447 rc = -ENOMEM;
448 goto err_alloc;
449 }
450 ref_init ( &dhcpv6set->refcnt, NULL );
452 &dhcpv6set->refcnt, &dhcpv6_scope );
453 dhcpv6set->settings.order = IPV6_ORDER_DHCPV6;
454 data = ( ( ( void * ) dhcpv6set ) + sizeof ( *dhcpv6set ) );
455 len = options->len;
456 memcpy ( data, options->data, len );
457 dhcpv6set->options.data = data;
458 dhcpv6set->options.len = len;
459 memcpy ( &dhcpv6set->lease, lease, sizeof ( dhcpv6set->lease ) );
460 memcpy ( &dhcpv6set->router, router, sizeof ( dhcpv6set->router ) );
461
462 /* Register settings */
463 if ( ( rc = register_settings ( &dhcpv6set->settings, parent,
464 DHCPV6_SETTINGS_NAME ) ) != 0 )
465 goto err_register;
466
467 err_register:
468 ref_put ( &dhcpv6set->refcnt );
469 err_alloc:
470 return rc;
471}
472
473/****************************************************************************
474 *
475 * DHCPv6 protocol
476 *
477 */
478
479/** Raw option data for options common to all DHCPv6 requests */
496
497/**
498 * Name a DHCPv6 packet type
499 *
500 * @v type DHCPv6 packet type
501 * @ret name DHCPv6 packet type name
502 */
503static __attribute__ (( unused )) const char *
504dhcpv6_type_name ( unsigned int type ) {
505 static char buf[ 12 /* "UNKNOWN-xxx" + NUL */ ];
506
507 switch ( type ) {
508 case DHCPV6_SOLICIT: return "SOLICIT";
509 case DHCPV6_ADVERTISE: return "ADVERTISE";
510 case DHCPV6_REQUEST: return "REQUEST";
511 case DHCPV6_REPLY: return "REPLY";
512 case DHCPV6_INFORMATION_REQUEST: return "INFORMATION-REQUEST";
513 default:
514 snprintf ( buf, sizeof ( buf ), "UNKNOWN-%d", type );
515 return buf;
516 }
517}
518
519/** A DHCPv6 session state */
521 /** Current transmitted packet type */
523 /** Current expected received packet type */
525 /** Flags */
527 /** Next state (or NULL to terminate) */
529};
530
531/** DHCPv6 session state flags */
533 /** Include identity association within request */
535 /** Include leased IPv6 address within request */
537 /** Record received server ID */
539 /** Record received IPv6 address */
541};
542
543/** DHCPv6 request state */
545 .tx_type = DHCPV6_REQUEST,
546 .rx_type = DHCPV6_REPLY,
547 .flags = ( DHCPV6_TX_IA_NA | DHCPV6_TX_IAADDR |
549 .next = NULL,
550};
551
552/** DHCPv6 solicitation state */
554 .tx_type = DHCPV6_SOLICIT,
555 .rx_type = DHCPV6_ADVERTISE,
559};
560
561/** DHCPv6 information request state */
564 .rx_type = DHCPV6_REPLY,
565 .flags = 0,
566 .next = NULL,
567};
568
569/** A DHCPv6 session */
571 /** Reference counter */
573 /** Job control interface */
575 /** Data transfer interface */
577
578 /** Network device being configured */
580 /** Router address */
582 /** Transaction ID */
584 /** Identity association ID */
586 /** Start time (in ticks) */
587 unsigned long start;
588 /** Client DUID */
590 /** Server DUID, if known */
592 /** Server DUID length */
594 /** Leased IPv6 address */
596
597 /** Retransmission timer */
599
600 /** Current session state */
602 /** Current timeout status code */
603 int rc;
604};
605
606/**
607 * Free DHCPv6 session
608 *
609 * @v refcnt Reference count
610 */
611static void dhcpv6_free ( struct refcnt *refcnt ) {
612 struct dhcpv6_session *dhcpv6 =
614
615 netdev_put ( dhcpv6->netdev );
616 free ( dhcpv6->server_duid );
617 free ( dhcpv6 );
618}
619
620/**
621 * Terminate DHCPv6 session
622 *
623 * @v dhcpv6 DHCPv6 session
624 * @v rc Reason for close
625 */
626static void dhcpv6_finished ( struct dhcpv6_session *dhcpv6, int rc ) {
627
628 /* Stop timer */
629 stop_timer ( &dhcpv6->timer );
630
631 /* Shut down interfaces */
632 intf_shutdown ( &dhcpv6->xfer, rc );
633 intf_shutdown ( &dhcpv6->job, rc );
634}
635
636/**
637 * Transition to new DHCPv6 session state
638 *
639 * @v dhcpv6 DHCPv6 session
640 * @v state New session state
641 */
642static void dhcpv6_set_state ( struct dhcpv6_session *dhcpv6,
643 struct dhcpv6_session_state *state ) {
644
645 DBGC ( dhcpv6, "DHCPv6 %s entering %s state\n", dhcpv6->netdev->name,
646 dhcpv6_type_name ( state->tx_type ) );
647
648 /* Record state */
649 dhcpv6->state = state;
650
651 /* Default to -ETIMEDOUT if no more specific error is recorded */
652 dhcpv6->rc = -ETIMEDOUT;
653
654 /* Start timer to trigger transmission */
655 start_timer_nodelay ( &dhcpv6->timer );
656}
657
658/**
659 * Get DHCPv6 user class
660 *
661 * @v data Data buffer
662 * @v len Length of data buffer
663 * @ret len Length of user class
664 */
665static size_t dhcpv6_user_class ( void *data, size_t len ) {
666 static const char default_user_class[4] = { 'i', 'P', 'X', 'E' };
667 int actual_len;
668
669 /* Fetch user-class setting, if defined */
670 actual_len = fetch_raw_setting ( NULL, &user_class_setting, data, len );
671 if ( actual_len >= 0 )
672 return actual_len;
673
674 /* Otherwise, use the default user class ("iPXE") */
675 if ( len > sizeof ( default_user_class ) )
676 len = sizeof ( default_user_class );
677 memcpy ( data, default_user_class, len );
678 return sizeof ( default_user_class );
679}
680
681/**
682 * Transmit current request
683 *
684 * @v dhcpv6 DHCPv6 session
685 * @ret rc Return status code
686 */
687static int dhcpv6_tx ( struct dhcpv6_session *dhcpv6 ) {
688 struct dhcpv6_duid_option *client_id;
689 struct dhcpv6_duid_option *server_id;
690 struct dhcpv6_ia_na_option *ia_na;
691 struct dhcpv6_iaaddr_option *iaaddr;
694 struct dhcpv6_header *dhcphdr;
695 struct io_buffer *iobuf;
696 void *options;
697 size_t client_id_len;
698 size_t server_id_len;
699 size_t ia_na_len;
700 size_t user_class_string_len;
701 size_t user_class_len;
702 size_t elapsed_len;
703 size_t total_len;
704 int rc;
705
706 /* Calculate lengths */
707 client_id_len = ( sizeof ( *client_id ) +
708 sizeof ( dhcpv6->client_duid ) );
709 server_id_len = ( dhcpv6->server_duid ? ( sizeof ( *server_id ) +
710 dhcpv6->server_duid_len ) :0);
711 if ( dhcpv6->state->flags & DHCPV6_TX_IA_NA ) {
712 ia_na_len = sizeof ( *ia_na );
713 if ( dhcpv6->state->flags & DHCPV6_TX_IAADDR )
714 ia_na_len += sizeof ( *iaaddr );
715 } else {
716 ia_na_len = 0;
717 }
718 user_class_string_len = dhcpv6_user_class ( NULL, 0 );
719 user_class_len = ( sizeof ( *user_class ) +
720 sizeof ( user_class->user_class[0] ) +
721 user_class_string_len );
722 elapsed_len = sizeof ( *elapsed );
723 total_len = ( sizeof ( *dhcphdr ) + client_id_len + server_id_len +
724 ia_na_len + sizeof ( dhcpv6_request_options_data ) +
725 user_class_len + elapsed_len );
726
727 /* Allocate packet */
728 iobuf = xfer_alloc_iob ( &dhcpv6->xfer, total_len );
729 if ( ! iobuf )
730 return -ENOMEM;
731
732 /* Construct header */
733 dhcphdr = iob_put ( iobuf, sizeof ( *dhcphdr ) );
734 dhcphdr->type = dhcpv6->state->tx_type;
735 memcpy ( dhcphdr->xid, dhcpv6->xid, sizeof ( dhcphdr->xid ) );
736
737 /* Construct client identifier */
738 client_id = iob_put ( iobuf, client_id_len );
739 client_id->header.code = htons ( DHCPV6_CLIENT_ID );
740 client_id->header.len = htons ( client_id_len -
741 sizeof ( client_id->header ) );
742 memcpy ( client_id->duid, &dhcpv6->client_duid,
743 sizeof ( dhcpv6->client_duid ) );
744
745 /* Construct server identifier, if applicable */
746 if ( server_id_len ) {
747 server_id = iob_put ( iobuf, server_id_len );
748 server_id->header.code = htons ( DHCPV6_SERVER_ID );
749 server_id->header.len = htons ( server_id_len -
750 sizeof ( server_id->header ) );
751 memcpy ( server_id->duid, dhcpv6->server_duid,
752 dhcpv6->server_duid_len );
753 }
754
755 /* Construct identity association, if applicable */
756 if ( ia_na_len ) {
757 ia_na = iob_put ( iobuf, ia_na_len );
758 ia_na->header.code = htons ( DHCPV6_IA_NA );
759 ia_na->header.len = htons ( ia_na_len -
760 sizeof ( ia_na->header ) );
761 ia_na->iaid = htonl ( dhcpv6->iaid );
762 ia_na->renew = htonl ( 0 );
763 ia_na->rebind = htonl ( 0 );
764 if ( dhcpv6->state->flags & DHCPV6_TX_IAADDR ) {
765 iaaddr = ( ( void * ) ia_na->options );
766 iaaddr->header.code = htons ( DHCPV6_IAADDR );
767 iaaddr->header.len = htons ( sizeof ( *iaaddr ) -
768 sizeof ( iaaddr->header ));
769 memcpy ( &iaaddr->address, &dhcpv6->lease,
770 sizeof ( iaaddr->address ) );
771 iaaddr->preferred = htonl ( 0 );
772 iaaddr->valid = htonl ( 0 );
773 }
774 }
775
776 /* Construct fixed request options */
777 options = iob_put ( iobuf, sizeof ( dhcpv6_request_options_data ) );
779 sizeof ( dhcpv6_request_options_data ) );
780
781 /* Construct user class */
782 user_class = iob_put ( iobuf, user_class_len );
783 user_class->header.code = htons ( DHCPV6_USER_CLASS );
784 user_class->header.len = htons ( user_class_len -
785 sizeof ( user_class->header ) );
786 user_class->user_class[0].len = htons ( user_class_string_len );
787 dhcpv6_user_class ( user_class->user_class[0].string,
788 user_class_string_len );
789
790 /* Construct elapsed time */
791 elapsed = iob_put ( iobuf, elapsed_len );
792 elapsed->header.code = htons ( DHCPV6_ELAPSED_TIME );
793 elapsed->header.len = htons ( elapsed_len -
794 sizeof ( elapsed->header ) );
795 elapsed->elapsed = htons ( ( ( currticks() - dhcpv6->start ) * 100 ) /
797
798 /* Sanity check */
799 assert ( iob_len ( iobuf ) == total_len );
800
801 /* Transmit packet */
802 if ( ( rc = xfer_deliver_iob ( &dhcpv6->xfer, iobuf ) ) != 0 ) {
803 DBGC ( dhcpv6, "DHCPv6 %s could not transmit: %s\n",
804 dhcpv6->netdev->name, strerror ( rc ) );
805 return rc;
806 }
807
808 return 0;
809}
810
811/**
812 * Handle timer expiry
813 *
814 * @v timer Retransmission timer
815 * @v fail Failure indicator
816 */
817static void dhcpv6_timer_expired ( struct retry_timer *timer, int fail ) {
818 struct dhcpv6_session *dhcpv6 =
820
821 /* If we have failed, terminate DHCPv6 */
822 if ( fail ) {
823 dhcpv6_finished ( dhcpv6, dhcpv6->rc );
824 return;
825 }
826
827 /* Restart timer */
828 start_timer ( &dhcpv6->timer );
829
830 /* (Re)transmit current request */
831 dhcpv6_tx ( dhcpv6 );
832}
833
834/**
835 * Receive new data
836 *
837 * @v dhcpv6 DHCPv6 session
838 * @v iobuf I/O buffer
839 * @v meta Data transfer metadata
840 * @ret rc Return status code
841 */
842static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6,
843 struct io_buffer *iobuf,
844 struct xfer_metadata *meta ) {
845 struct settings *parent = netdev_settings ( dhcpv6->netdev );
846 struct sockaddr_in6 *src = ( ( struct sockaddr_in6 * ) meta->src );
847 struct dhcpv6_header *dhcphdr = iobuf->data;
849 const union dhcpv6_any_option *option;
850 int rc;
851
852 /* Sanity checks */
853 if ( iob_len ( iobuf ) < sizeof ( *dhcphdr ) ) {
854 DBGC ( dhcpv6, "DHCPv6 %s received packet too short (%zd "
855 "bytes, min %zd bytes)\n", dhcpv6->netdev->name,
856 iob_len ( iobuf ), sizeof ( *dhcphdr ) );
857 rc = -EINVAL;
858 goto done;
859 }
860 assert ( src != NULL );
861 assert ( src->sin6_family == AF_INET6 );
862 DBGC ( dhcpv6, "DHCPv6 %s received %s from %s\n",
863 dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ),
864 inet6_ntoa ( &src->sin6_addr ) );
865
866 /* Construct option list */
867 options.data = dhcphdr->options;
868 options.len = ( iob_len ( iobuf ) -
869 offsetof ( typeof ( *dhcphdr ), options ) );
870
871 /* Verify client identifier */
873 &dhcpv6->client_duid,
874 sizeof ( dhcpv6->client_duid ) ) ) !=0){
875 DBGC ( dhcpv6, "DHCPv6 %s received %s without correct client "
876 "ID: %s\n", dhcpv6->netdev->name,
877 dhcpv6_type_name ( dhcphdr->type ), strerror ( rc ) );
878 goto done;
879 }
880
881 /* Verify server identifier, if applicable */
882 if ( dhcpv6->server_duid &&
884 dhcpv6->server_duid,
885 dhcpv6->server_duid_len ) ) != 0 ) ) {
886 DBGC ( dhcpv6, "DHCPv6 %s received %s without correct server "
887 "ID: %s\n", dhcpv6->netdev->name,
888 dhcpv6_type_name ( dhcphdr->type ), strerror ( rc ) );
889 goto done;
890 }
891
892 /* Check message type */
893 if ( dhcphdr->type != dhcpv6->state->rx_type ) {
894 DBGC ( dhcpv6, "DHCPv6 %s received %s while expecting %s\n",
895 dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ),
896 dhcpv6_type_name ( dhcpv6->state->rx_type ) );
897 rc = -ENOTTY;
898 goto done;
899 }
900
901 /* Fetch status code, if present */
902 if ( ( rc = dhcpv6_status_code ( &options ) ) != 0 ) {
903 DBGC ( dhcpv6, "DHCPv6 %s received %s with error status: %s\n",
904 dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ),
905 strerror ( rc ) );
906 /* This is plausibly the error we want to return */
907 dhcpv6->rc = rc;
908 goto done;
909 }
910
911 /* Record identity association address, if applicable */
912 if ( dhcpv6->state->flags & DHCPV6_RX_RECORD_IAADDR ) {
913 if ( ( rc = dhcpv6_iaaddr ( &options, dhcpv6->iaid,
914 &dhcpv6->lease ) ) != 0 ) {
915 DBGC ( dhcpv6, "DHCPv6 %s received %s with unusable "
916 "IAADDR: %s\n", dhcpv6->netdev->name,
917 dhcpv6_type_name ( dhcphdr->type ),
918 strerror ( rc ) );
919 /* This is plausibly the error we want to return */
920 dhcpv6->rc = rc;
921 goto done;
922 }
923 DBGC ( dhcpv6, "DHCPv6 %s received %s is for %s\n",
924 dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ),
925 inet6_ntoa ( &dhcpv6->lease ) );
926 }
927
928 /* Record server ID, if applicable */
929 if ( dhcpv6->state->flags & DHCPV6_RX_RECORD_SERVER_ID ) {
930 assert ( dhcpv6->server_duid == NULL );
932 if ( ! option ) {
933 DBGC ( dhcpv6, "DHCPv6 %s received %s missing server "
934 "ID\n", dhcpv6->netdev->name,
935 dhcpv6_type_name ( dhcphdr->type ) );
936 rc = -EINVAL;
937 goto done;
938 }
939 dhcpv6->server_duid_len = ntohs ( option->duid.header.len );
940 dhcpv6->server_duid = malloc ( dhcpv6->server_duid_len );
941 if ( ! dhcpv6->server_duid ) {
942 rc = -ENOMEM;
943 goto done;
944 }
945 memcpy ( dhcpv6->server_duid, option->duid.duid,
946 dhcpv6->server_duid_len );
947 }
948
949 /* Transition to next state, if applicable */
950 if ( dhcpv6->state->next ) {
951 dhcpv6_set_state ( dhcpv6, dhcpv6->state->next );
952 rc = 0;
953 goto done;
954 }
955
956 /* Register settings */
957 if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &dhcpv6->router,
958 &options, parent ) ) != 0 ) {
959 DBGC ( dhcpv6, "DHCPv6 %s could not register settings: %s\n",
960 dhcpv6->netdev->name, strerror ( rc ) );
961 goto done;
962 }
963
964 /* Mark as complete */
965 dhcpv6_finished ( dhcpv6, 0 );
966 DBGC ( dhcpv6, "DHCPv6 %s complete\n", dhcpv6->netdev->name );
967
968 done:
969 free_iob ( iobuf );
970 return rc;
971}
972
973/** DHCPv6 job control interface operations */
977
978/** DHCPv6 job control interface descriptor */
980 INTF_DESC ( struct dhcpv6_session, job, dhcpv6_job_op );
981
982/** DHCPv6 data transfer interface operations */
986
987/** DHCPv6 data transfer interface descriptor */
989 INTF_DESC ( struct dhcpv6_session, xfer, dhcpv6_xfer_op );
990
991/**
992 * Start DHCPv6
993 *
994 * @v job Job control interface
995 * @v netdev Network device
996 * @v router Router address
997 * @v stateful Perform stateful address autoconfiguration
998 * @ret rc Return status code
999 */
1000int start_dhcpv6 ( struct interface *job, struct net_device *netdev,
1001 struct in6_addr *router, int stateful ) {
1002 struct ll_protocol *ll_protocol = netdev->ll_protocol;
1003 struct dhcpv6_session *dhcpv6;
1004 struct {
1005 union {
1006 struct sockaddr_in6 sin6;
1007 struct sockaddr sa;
1008 } client;
1009 union {
1010 struct sockaddr_in6 sin6;
1011 struct sockaddr sa;
1012 } server;
1013 } addresses;
1014 uint32_t xid;
1015 int len;
1016 int rc;
1017
1018 /* Allocate and initialise structure */
1019 dhcpv6 = zalloc ( sizeof ( *dhcpv6 ) );
1020 if ( ! dhcpv6 )
1021 return -ENOMEM;
1022 ref_init ( &dhcpv6->refcnt, dhcpv6_free );
1023 intf_init ( &dhcpv6->job, &dhcpv6_job_desc, &dhcpv6->refcnt );
1024 intf_init ( &dhcpv6->xfer, &dhcpv6_xfer_desc, &dhcpv6->refcnt );
1025 dhcpv6->netdev = netdev_get ( netdev );
1026 memcpy ( &dhcpv6->router, router, sizeof ( dhcpv6->router ) );
1027 xid = random();
1028 memcpy ( dhcpv6->xid, &xid, sizeof ( dhcpv6->xid ) );
1029 dhcpv6->start = currticks();
1030 timer_init ( &dhcpv6->timer, dhcpv6_timer_expired, &dhcpv6->refcnt );
1031
1032 /* Construct client and server addresses */
1033 memset ( &addresses, 0, sizeof ( addresses ) );
1034 addresses.client.sin6.sin6_family = AF_INET6;
1035 addresses.client.sin6.sin6_port = htons ( DHCPV6_CLIENT_PORT );
1036 addresses.server.sin6.sin6_family = AF_INET6;
1037 ipv6_all_dhcp_relay_and_servers ( &addresses.server.sin6.sin6_addr );
1038 addresses.server.sin6.sin6_scope_id = netdev->scope_id;
1039 addresses.server.sin6.sin6_port = htons ( DHCPV6_SERVER_PORT );
1040
1041 /* Construct client DUID from system UUID */
1042 dhcpv6->client_duid.type = htons ( DHCPV6_DUID_UUID );
1043 if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
1044 &dhcpv6->client_duid.uuid ) ) < 0 ) {
1045 rc = len;
1046 DBGC ( dhcpv6, "DHCPv6 %s could not create DUID-UUID: %s\n",
1047 dhcpv6->netdev->name, strerror ( rc ) );
1048 goto err_client_duid;
1049 }
1050
1051 /* Construct IAID from link-layer address */
1052 dhcpv6->iaid = crc32_le ( 0, netdev->ll_addr, ll_protocol->ll_addr_len);
1053 DBGC ( dhcpv6, "DHCPv6 %s has XID %02x%02x%02x\n", dhcpv6->netdev->name,
1054 dhcpv6->xid[0], dhcpv6->xid[1], dhcpv6->xid[2] );
1055
1056 /* Enter initial state */
1057 dhcpv6_set_state ( dhcpv6, ( stateful ? &dhcpv6_solicit :
1059
1060 /* Open socket */
1061 if ( ( rc = xfer_open_socket ( &dhcpv6->xfer, SOCK_DGRAM,
1062 &addresses.server.sa,
1063 &addresses.client.sa ) ) != 0 ) {
1064 DBGC ( dhcpv6, "DHCPv6 %s could not open socket: %s\n",
1065 dhcpv6->netdev->name, strerror ( rc ) );
1066 goto err_open_socket;
1067 }
1068
1069 /* Attach parent interface, mortalise self, and return */
1070 intf_plug_plug ( &dhcpv6->job, job );
1071 ref_put ( &dhcpv6->refcnt );
1072 return 0;
1073
1074 err_open_socket:
1075 dhcpv6_finished ( dhcpv6, rc );
1076 err_client_duid:
1077 ref_put ( &dhcpv6->refcnt );
1078 return rc;
1079}
1080
1081/** Boot filename setting */
1082const struct setting filename6_setting __setting ( SETTING_BOOT, filename ) = {
1083 .name = "filename",
1084 .description = "Boot filename",
1085 .tag = DHCPV6_BOOTFILE_URL,
1086 .type = &setting_type_string,
1087 .scope = &dhcpv6_scope,
1088};
1089
1090/** DNS search list setting */
1091const struct setting dnssl6_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
1092 .name = "dnssl",
1093 .description = "DNS search list",
1094 .tag = DHCPV6_DOMAIN_LIST,
1095 .type = &setting_type_dnssl,
1096 .scope = &dhcpv6_scope,
1097};
static int options
Definition 3c515.c:286
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
static unsigned int code
Response code.
Definition hyperv.h:26
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
#define DHCP_ARCH_CLIENT_ARCHITECTURE
DHCP client architecture.
Definition dhcparch.h:15
#define DHCP_ARCH_CLIENT_NDI
DHCP client network device interface.
Definition dhcparch.h:18
static const void * src
Definition string.h:48
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
struct bofm_section_header done
Definition bofm_test.c:46
u32 crc32_le(u32 seed, const void *data, size_t len)
Calculate 32-bit little-endian CRC checksum.
Definition crc32.c:40
static int dhcpv6_tx(struct dhcpv6_session *dhcpv6)
Transmit current request.
Definition dhcpv6.c:687
static struct interface_operation dhcpv6_xfer_op[]
DHCPv6 data transfer interface operations.
Definition dhcpv6.c:983
static void dhcpv6_free(struct refcnt *refcnt)
Free DHCPv6 session.
Definition dhcpv6.c:611
static const union dhcpv6_any_option * dhcpv6_option(struct dhcpv6_option_list *options, unsigned int code)
Find DHCPv6 option.
Definition dhcpv6.c:101
static uint8_t dhcpv6_request_options_data[]
Raw option data for options common to all DHCPv6 requests.
Definition dhcpv6.c:480
static struct interface_descriptor dhcpv6_xfer_desc
DHCPv6 data transfer interface descriptor.
Definition dhcpv6.c:988
static int dhcpv6_status_code(struct dhcpv6_option_list *options)
Get DHCPv6 status code.
Definition dhcpv6.c:167
static int dhcpv6_register(struct in6_addr *lease, struct in6_addr *router, struct dhcpv6_option_list *options, struct settings *parent)
Register DHCPv6 options as network device settings.
Definition dhcpv6.c:436
static struct dhcpv6_session_state dhcpv6_solicit
DHCPv6 solicitation state.
Definition dhcpv6.c:553
static struct settings_operations dhcpv6_settings_operations
DHCPv6 settings operations.
Definition dhcpv6.c:422
static struct dhcpv6_session_state dhcpv6_information_request
DHCPv6 information request state.
Definition dhcpv6.c:562
static int dhcpv6_check_duid(struct dhcpv6_option_list *options, unsigned int code, const void *expected, size_t len)
Check DHCPv6 client or server identifier.
Definition dhcpv6.c:138
static int dhcpv6_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of DHCPv6 setting.
Definition dhcpv6.c:285
dhcpv6_session_state_flags
DHCPv6 session state flags.
Definition dhcpv6.c:532
@ DHCPV6_RX_RECORD_SERVER_ID
Record received server ID.
Definition dhcpv6.c:538
@ DHCPV6_RX_RECORD_IAADDR
Record received IPv6 address.
Definition dhcpv6.c:540
@ DHCPV6_TX_IA_NA
Include identity association within request.
Definition dhcpv6.c:534
@ DHCPV6_TX_IAADDR
Include leased IPv6 address within request.
Definition dhcpv6.c:536
static size_t dhcpv6_user_class(void *data, size_t len)
Get DHCPv6 user class.
Definition dhcpv6.c:665
static int dhcpv6_fetch_ip6(struct dhcpv6_settings *dhcpv6set, void *data, size_t len)
Fetch value of DHCPv6 leased address.
Definition dhcpv6.c:300
static struct dhcpv6_address_operation dhcpv6_address_operations[]
DHCPv6 address settings operations.
Definition dhcpv6.c:372
static void dhcpv6_finished(struct dhcpv6_session *dhcpv6, int rc)
Terminate DHCPv6 session.
Definition dhcpv6.c:626
static void dhcpv6_timer_expired(struct retry_timer *timer, int fail)
Handle timer expiry.
Definition dhcpv6.c:817
static int dhcpv6_fetch_gateway6(struct dhcpv6_settings *dhcpv6set, void *data, size_t len)
Fetch value of DHCPv6 router address.
Definition dhcpv6.c:343
#define EPROTO_STATUS(status)
Definition dhcpv6.c:69
static struct interface_descriptor dhcpv6_job_desc
DHCPv6 job control interface descriptor.
Definition dhcpv6.c:979
static struct interface_operation dhcpv6_job_op[]
DHCPv6 job control interface operations.
Definition dhcpv6.c:974
#define EINFO_EPROTO_NOADDRSAVAIL
Definition dhcpv6.c:58
static struct dhcpv6_session_state dhcpv6_request
DHCPv6 request state.
Definition dhcpv6.c:544
static int dhcpv6_fetch_len6(struct dhcpv6_settings *dhcpv6set __unused, void *data, size_t len)
Fetch value of DHCPv6 implicit address prefix length.
Definition dhcpv6.c:320
static const char * dhcpv6_type_name(unsigned int type)
Name a DHCPv6 packet type.
Definition dhcpv6.c:504
static void dhcpv6_set_state(struct dhcpv6_session *dhcpv6, struct dhcpv6_session_state *state)
Transition to new DHCPv6 session state.
Definition dhcpv6.c:642
static int dhcpv6_iaaddr(struct dhcpv6_option_list *options, uint32_t iaid, struct in6_addr *address)
Get DHCPv6 identity association address.
Definition dhcpv6.c:199
static int dhcpv6_rx(struct dhcpv6_session *dhcpv6, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive new data.
Definition dhcpv6.c:842
static int dhcpv6_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of DHCPv6 setting.
Definition dhcpv6.c:387
int start_dhcpv6(struct interface *job, struct net_device *netdev, struct in6_addr *router, int stateful)
Start DHCPv6.
Definition dhcpv6.c:1000
Dynamic Host Configuration Protocol for IPv6.
#define DHCPV6_CLIENT_ARCHITECTURE
DHCPv6 client system architecture option.
Definition dhcpv6.h:177
#define DHCPV6_STATUS_CODE
DHCPv6 status code option.
Definition dhcpv6.h:128
#define DHCPV6_OPTION_REQUEST
DHCPv6 option request option.
Definition dhcpv6.h:104
#define DHCPV6_DOMAIN_LIST
DHCPv6 domain search list option.
Definition dhcpv6.h:168
#define DHCPV6_DWORD_VALUE(value)
Construct a DHCPv6 dword value.
Definition dhcpv6.h:197
#define DHCPV6_BOOTFILE_PARAM
DHCPv6 bootfile parameters option.
Definition dhcpv6.h:174
#define DHCPV6_VENDOR_CLASS_PXE
DHCPv6 PXE vendor class.
Definition dhcpv6.h:162
#define DHCPV6_REQUEST
DHCPv6 request.
Definition dhcpv6.h:257
#define DHCPV6_SETTINGS_NAME
DHCPv6 settings block name.
Definition dhcpv6.h:266
#define DHCPV6_REPLY
DHCPv6 reply.
Definition dhcpv6.h:260
#define DHCPV6_STRING(...)
Construct a DHCPv6 option from a list of characters.
Definition dhcpv6.h:211
#define DHCPV6_IAADDR
DHCPv6 identity association address (IAADDR) option.
Definition dhcpv6.h:93
#define DHCPV6_OPTION(...)
Construct a DHCPv6 option from a list of bytes.
Definition dhcpv6.h:207
#define DHCPV6_VENDOR_CLASS
DHCPv6 vendor class option.
Definition dhcpv6.h:150
#define DHCPV6_CLIENT_PORT
DHCPv6 client port.
Definition dhcpv6.h:21
#define DHCPV6_USER_CLASS
DHCPv6 user class option.
Definition dhcpv6.h:147
#define DHCPV6_CLIENT_ID
DHCPv6 client identifier option.
Definition dhcpv6.h:56
#define DHCPV6_DUID_UUID
DHCP unique identifier based on UUID (DUID-UUID)
Definition dhcpv6.h:45
#define DHCPV6_BOOTFILE_URL
DHCPv6 bootfile URI option.
Definition dhcpv6.h:171
#define DHCPV6_IA_NA
DHCPv6 identity association for non-temporary address (IA_NA) option.
Definition dhcpv6.h:76
#define DHCPV6_INFORMATION_REQUEST
DHCPv6 information request.
Definition dhcpv6.h:263
#define DHCPV6_SERVER_PORT
DHCPv6 server port.
Definition dhcpv6.h:18
#define DHCPV6_WORD(value)
Construct a word-valued DHCPv6 option.
Definition dhcpv6.h:217
#define DHCPV6_SERVER_ID
DHCPv6 server identifier option.
Definition dhcpv6.h:59
#define DHCPV6_ADVERTISE
DHCPv6 advertisement.
Definition dhcpv6.h:254
static void ipv6_all_dhcp_relay_and_servers(struct in6_addr *addr)
Construct all-DHCP-relay-agents-and-servers multicast address.
Definition dhcpv6.h:273
#define DHCPV6_ELAPSED_TIME
DHCPv6 elapsed time option.
Definition dhcpv6.h:115
#define DHCPV6_CLIENT_NDI
DHCPv6 client network interface identifier option.
Definition dhcpv6.h:180
#define DHCPV6_CODE(code)
Construct a DHCPv6 option code.
Definition dhcpv6.h:201
#define DHCPV6_SOLICIT
DHCPv6 solicitation.
Definition dhcpv6.h:251
#define DHCPV6_DNS_SERVERS
DHCPv6 DNS recursive name server option.
Definition dhcpv6.h:165
uint32_t next
Next descriptor address.
Definition dwmac.h:11
ring len
Length.
Definition dwmac.h:226
const struct setting gateway6_setting
const struct setting len6_setting
const struct setting ip6_setting
uint32_t type
Operating system type.
Definition ena.h:1
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint8_t status
Status.
Definition ena.h:5
uint8_t meta
Metadata flags.
Definition ena.h:3
uint64_t address
Base address.
Definition ena.h:13
Error codes.
Error message tables.
#define __errortab
Definition errortab.h:22
#define __einfo_errortab(einfo)
Definition errortab.h:24
uint8_t state
State.
Definition eth_slow.h:36
static struct net_device * netdev
Definition gdbudp.c:53
#define AF_INET6
IPv6 Internet addresses.
Definition socket.h:65
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define SOCK_DGRAM
Definition socket.h:30
#define DBGC(...)
Definition compiler.h:505
#define DHCP_VENDOR_PXECLIENT(arch, ndi)
Vendor class identifier for PXE clients.
Definition dhcp.h:220
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:595
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define SETTING_BOOT
Generic boot settings.
Definition settings.h:72
#define SETTING_IP_EXTRA
IPv4 additional settings.
Definition settings.h:71
uint32_t lease
Definition ib_mad.h:4
#define IN6_IS_ADDR_UNSPECIFIED(addr)
Definition in.h:62
#define htonl(value)
Definition byteswap.h:134
#define htons(value)
Definition byteswap.h:136
#define ntohs(value)
Definition byteswap.h:137
#define __attribute__(x)
Definition compiler.h:10
DHCP client architecture definitions.
Configuration settings.
#define __setting(setting_order, name)
Declare a configuration setting.
Definition settings.h:57
static void settings_init(struct settings *settings, struct settings_operations *op, struct refcnt *refcnt, const struct settings_scope *default_scope)
Initialise a settings block.
Definition settings.h:503
iPXE timers
#define TICKS_PER_SEC
Number of ticks per second.
Definition timer.h:16
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
Object interfaces.
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
I/O buffers.
#define iob_put(iobuf, len)
Definition iobuf.h:125
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
char * inet6_ntoa(const struct in6_addr *in)
Convert IPv6 address to standard notation.
Definition ipv6.c:895
const struct settings_scope ipv6_settings_scope
IPv6 settings scope.
Definition ipv6.c:1121
IPv6 protocol.
#define IPV6_MAX_PREFIX_LEN
IPv6 maximum prefix length.
Definition ipv6.h:33
@ IPV6_ORDER_DHCPV6
Address assigned via DHCPv6.
Definition ipv6.h:289
uint8_t unused
Unused.
Definition librm.h:5
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
Network device management.
static struct net_device * netdev_get(struct net_device *netdev)
Get reference to network device.
Definition netdevice.h:565
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition netdevice.h:576
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition netdevice.h:587
static uint16_t struct vmbus_xfer_pages_operations * op
Definition netvsc.h:327
int xfer_open_socket(struct interface *intf, int semantics, struct sockaddr *peer, struct sockaddr *local)
Open socket.
Definition open.c:143
Data transfer interface opening.
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
void start_timer(struct retry_timer *timer)
Start timer.
Definition retry.c:94
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition retry.c:118
Retry timers.
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition retry.h:100
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition settings.c:476
const struct settings_scope dhcpv6_scope
IPv6 settings scope.
Definition settings.c:1793
int fetch_raw_setting(struct settings *settings, const struct setting *setting, void *data, size_t len)
Fetch value of setting.
Definition settings.c:804
int setting_cmp(const struct setting *a, const struct setting *b)
Compare two settings.
Definition settings.c:1121
int fetch_uuid_setting(struct settings *settings, const struct setting *setting, union uuid *uuid)
Fetch value of UUID setting.
Definition settings.c:1085
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
A DHCP header.
Definition dhcp.h:616
uint32_t xid
Transaction ID.
Definition dhcp.h:634
uint8_t options[0]
DHCP options.
Definition dhcp.h:684
A DHCPv6 address setting operation.
Definition dhcpv6.c:356
int(* fetch)(struct dhcpv6_settings *dhcpv6set, void *data, size_t len)
Fetch value of setting.
Definition dhcpv6.c:367
const struct setting * setting
Generic setting.
Definition dhcpv6.c:358
DHCPv6 client or server identifier option.
Definition dhcpv6.h:48
struct dhcpv6_option header
Option header.
Definition dhcpv6.h:50
uint8_t duid[0]
DHCP unique identifier (DUID)
Definition dhcpv6.h:52
DHCP unique identifier based on UUID (DUID-UUID)
Definition dhcpv6.h:37
union uuid uuid
UUID.
Definition dhcpv6.h:41
uint16_t type
Type.
Definition dhcpv6.h:39
DHCPv6 elapsed time option.
Definition dhcpv6.h:107
struct dhcpv6_option header
Option header.
Definition dhcpv6.h:109
uint16_t elapsed
Elapsed time, in centiseconds.
Definition dhcpv6.h:111
A DHCPv6 header.
Definition dhcpv6.h:241
DHCPv6 identity association for non-temporary address (IA_NA) option.
Definition dhcpv6.h:62
uint32_t renew
Renew time (in seconds)
Definition dhcpv6.h:68
struct dhcpv6_option header
Option header.
Definition dhcpv6.h:64
uint32_t iaid
Identity association identifier (IAID)
Definition dhcpv6.h:66
struct dhcpv6_option options[0]
IA_NA options.
Definition dhcpv6.h:72
uint32_t rebind
Rebind time (in seconds)
Definition dhcpv6.h:70
DHCPv6 identity association address (IAADDR) option.
Definition dhcpv6.h:79
struct dhcpv6_option options[0]
IAADDR options.
Definition dhcpv6.h:89
struct dhcpv6_option header
Option header.
Definition dhcpv6.h:81
struct in6_addr address
IPv6 address.
Definition dhcpv6.h:83
uint32_t valid
Valid lifetime (in seconds)
Definition dhcpv6.h:87
uint32_t preferred
Preferred lifetime (in seconds)
Definition dhcpv6.h:85
A DHCPv6 option list.
Definition dhcpv6.c:86
size_t len
Length of data buffer.
Definition dhcpv6.c:90
const void * data
Data buffer.
Definition dhcpv6.c:88
uint16_t len
Length of the data field.
Definition dhcpv6.h:31
uint16_t code
Code.
Definition dhcpv6.h:29
A DHCPv6 session state.
Definition dhcpv6.c:520
uint8_t rx_type
Current expected received packet type.
Definition dhcpv6.c:524
uint8_t flags
Flags.
Definition dhcpv6.c:526
struct dhcpv6_session_state * next
Next state (or NULL to terminate)
Definition dhcpv6.c:528
uint8_t tx_type
Current transmitted packet type.
Definition dhcpv6.c:522
A DHCPv6 session.
Definition dhcpv6.c:570
struct retry_timer timer
Retransmission timer.
Definition dhcpv6.c:598
uint8_t xid[3]
Transaction ID.
Definition dhcpv6.c:583
struct interface job
Job control interface.
Definition dhcpv6.c:574
struct dhcpv6_duid_uuid client_duid
Client DUID.
Definition dhcpv6.c:589
int rc
Current timeout status code.
Definition dhcpv6.c:603
unsigned long start
Start time (in ticks)
Definition dhcpv6.c:587
struct in6_addr lease
Leased IPv6 address.
Definition dhcpv6.c:595
struct in6_addr router
Router address.
Definition dhcpv6.c:581
struct net_device * netdev
Network device being configured.
Definition dhcpv6.c:579
void * server_duid
Server DUID, if known.
Definition dhcpv6.c:591
struct refcnt refcnt
Reference counter.
Definition dhcpv6.c:572
struct dhcpv6_session_state * state
Current session state.
Definition dhcpv6.c:601
struct interface xfer
Data transfer interface.
Definition dhcpv6.c:576
size_t server_duid_len
Server DUID length.
Definition dhcpv6.c:593
uint32_t iaid
Identity association ID.
Definition dhcpv6.c:585
A DHCPv6 settings block.
Definition dhcpv6.c:265
struct settings settings
Settings block.
Definition dhcpv6.c:269
struct refcnt refcnt
Reference count.
Definition dhcpv6.c:267
struct dhcpv6_option_list options
Option list.
Definition dhcpv6.c:275
struct in6_addr router
Router address.
Definition dhcpv6.c:273
struct in6_addr lease
Leased address.
Definition dhcpv6.c:271
DHCPv6 status code option.
Definition dhcpv6.h:118
uint16_t status
Status code.
Definition dhcpv6.h:122
struct dhcpv6_option header
Option header.
Definition dhcpv6.h:120
DHCPv6 user class option.
Definition dhcpv6.h:139
struct dhcpv6_option header
Option header.
Definition dhcpv6.h:141
struct dhcpv6_user_class user_class[0]
User class.
Definition dhcpv6.h:143
char string[0]
User class string.
Definition dhcpv6.h:135
uint16_t len
Length.
Definition dhcpv6.h:133
IP6 address structure.
Definition in.h:51
An object interface descriptor.
Definition interface.h:56
An object interface operation.
Definition interface.h:18
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
A link-layer protocol.
Definition netdevice.h:115
uint8_t ll_addr_len
Link-layer address length.
Definition netdevice.h:199
A network device.
Definition netdevice.h:353
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition netdevice.h:363
A long option, as used for getopt_long()
Definition getopt.h:25
A reference counter.
Definition refcnt.h:27
A retry timer.
Definition retry.h:22
A setting.
Definition settings.h:24
const struct settings_scope * scope
Setting scope (or NULL)
Definition settings.h:50
uint64_t tag
Setting tag, if applicable.
Definition settings.h:44
Settings block operations.
Definition settings.h:86
A settings block.
Definition settings.h:133
int order
Sibling ordering.
Definition settings.h:149
struct settings * parent
Parent settings block.
Definition settings.h:139
IPv6 socket address.
Definition in.h:118
Generalized socket address structure.
Definition socket.h:97
A timer.
Definition timer.h:29
Data transfer metadata.
Definition xfer.h:23
struct sockaddr_in6 sin6
Definition syslog.c:60
struct sockaddr sa
Definition syslog.c:57
unsigned long currticks(void)
Get current system time in ticks.
Definition timer.c:43
uint32_t data_len
Microcode data size (or 0 to indicate 2000 bytes)
Definition ucode.h:15
Any DHCPv6 option.
Definition dhcpv6.h:226
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition xfer.c:159
int xfer_deliver_iob(struct interface *intf, struct io_buffer *iobuf)
Deliver datagram as I/O buffer without metadata.
Definition xfer.c:256
Data transfer interfaces.