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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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 */
75 struct 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  */
100 static const union dhcpv6_any_option *
101 dhcpv6_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 */
267  struct refcnt refcnt;
268  /** Settings block */
270  /** Leased address */
271  struct in6_addr lease;
272  /** Router address */
273  struct in6_addr router;
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 ) ||
289  ( setting->scope == &ipv6_settings_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  */
300 static 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  */
320 static 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  */
343 static 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 */
376 };
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  */
387 static 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 */
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  */
436 static int dhcpv6_register ( struct in6_addr *lease, struct in6_addr *router,
437  struct dhcpv6_option_list *options,
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 */
488  DHCPV6_STRING (
490  DHCP_ARCH_CLIENT_NDI ) ) ),
495 };
496 
497 /**
498  * Name a DHCPv6 packet type
499  *
500  * @v type DHCPv6 packet type
501  * @ret name DHCPv6 packet type name
502  */
503 static __attribute__ (( unused )) const char *
504 dhcpv6_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 */
546  .rx_type = DHCPV6_REPLY,
547  .flags = ( DHCPV6_TX_IA_NA | DHCPV6_TX_IAADDR |
549  .next = NULL,
550 };
551 
552 /** DHCPv6 solicitation state */
555  .rx_type = DHCPV6_ADVERTISE,
558  .next = &dhcpv6_request,
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 */
572  struct refcnt refcnt;
573  /** Job control interface */
574  struct interface job;
575  /** Data transfer interface */
576  struct interface xfer;
577 
578  /** Network device being configured */
580  /** Router address */
581  struct in6_addr router;
582  /** Transaction ID */
584  /** Identity association ID */
586  /** Start time (in ticks) */
587  unsigned long start;
588  /** Client DUID */
590  /** Server DUID, if known */
591  void *server_duid;
592  /** Server DUID length */
594  /** Leased IPv6 address */
595  struct in6_addr lease;
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  */
611 static 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  */
626 static 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  */
642 static 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  */
665 static 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  */
687 static 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 ) /
796  TICKS_PER_SEC );
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  */
817 static void dhcpv6_timer_expired ( struct retry_timer *timer, int fail ) {
818  struct dhcpv6_session *dhcpv6 =
819  container_of ( timer, struct dhcpv6_session, timer );
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  */
842 static 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 */
976 };
977 
978 /** DHCPv6 job control interface descriptor */
980  INTF_DESC ( struct dhcpv6_session, job, dhcpv6_job_op );
981 
982 /** DHCPv6 data transfer interface operations */
985 };
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  */
1000 int start_dhcpv6 ( struct interface *job, struct net_device *netdev,
1001  struct in6_addr *router, int stateful ) {
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 */
1082 const 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 */
1091 const 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 };
uint8_t rx_type
Current expected received packet type.
Definition: dhcpv6.c:524
static struct dhcpv6_session_state dhcpv6_solicit
DHCPv6 solicitation state.
Definition: dhcpv6.c:553
struct dhcpv6_session_state * next
Next state (or NULL to terminate)
Definition: dhcpv6.c:528
#define DHCPV6_SERVER_ID
DHCPv6 server identifier option.
Definition: dhcpv6.h:59
#define __attribute__(x)
Definition: compiler.h:10
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static int dhcpv6_tx(struct dhcpv6_session *dhcpv6)
Transmit current request.
Definition: dhcpv6.c:687
#define EINVAL
Invalid argument.
Definition: errno.h:429
An object interface operation.
Definition: interface.h:18
A DHCPv6 session.
Definition: dhcpv6.c:570
#define SETTING_IP_EXTRA
IPv4 additional settings.
Definition: settings.h:71
#define DHCPV6_BOOTFILE_PARAM
DHCPv6 bootfile parameters option.
Definition: dhcpv6.h:174
Record received server ID.
Definition: dhcpv6.c:538
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition: interface.c:250
char string[0]
User class string.
Definition: dhcpv6.h:135
#define DHCPV6_SOLICIT
DHCPv6 solicitation.
Definition: dhcpv6.h:251
#define iob_put(iobuf, len)
Definition: iobuf.h:125
Error message tables.
#define TICKS_PER_SEC
Number of ticks per second.
Definition: timer.h:16
Data transfer metadata.
Definition: xfer.h:23
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition: interface.c:279
#define DHCPV6_ELAPSED_TIME
DHCPv6 elapsed time option.
Definition: dhcpv6.h:115
#define AF_INET6
IPv6 Internet addresses.
Definition: socket.h:65
int xfer_deliver_iob(struct interface *intf, struct io_buffer *iobuf)
Deliver datagram as I/O buffer without metadata.
Definition: xfer.c:256
static int dhcpv6_fetch_ip6(struct dhcpv6_settings *dhcpv6set, void *data, size_t len)
Fetch value of DHCPv6 leased address.
Definition: dhcpv6.c:300
DHCP unique identifier based on UUID (DUID-UUID)
Definition: dhcpv6.h:37
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition: retry.h:100
uint8_t ll_addr_len
Link-layer address length.
Definition: netdevice.h:199
static struct interface_descriptor dhcpv6_xfer_desc
DHCPv6 data transfer interface descriptor.
Definition: dhcpv6.c:988
struct interface xfer
Data transfer interface.
Definition: dhcpv6.c:576
const struct settings_scope dhcpv6_scope
IPv6 settings scope.
Definition: settings.c:1793
uint8_t state
State.
Definition: eth_slow.h:48
struct interface job
Job control interface.
Definition: dhcpv6.c:574
char * inet6_ntoa(const struct in6_addr *in)
Convert IPv6 address to standard notation.
Definition: ipv6.c:895
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 struct interface_operation dhcpv6_job_op[]
DHCPv6 job control interface operations.
Definition: dhcpv6.c:974
Include leased IPv6 address within request.
Definition: dhcpv6.c:536
static uint8_t dhcpv6_request_options_data[]
Raw option data for options common to all DHCPv6 requests.
Definition: dhcpv6.c:480
#define DHCPV6_IA_NA
DHCPv6 identity association for non-temporary address (IA_NA) option.
Definition: dhcpv6.h:76
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:65
Error codes.
uint16_t len
Length.
Definition: dhcpv6.h:133
int xfer_open_socket(struct interface *intf, int semantics, struct sockaddr *peer, struct sockaddr *local)
Open socket.
Definition: open.c:143
struct settings * parent
Parent settings block.
Definition: settings.h:139
struct dhcpv6_option header
Option header.
Definition: dhcpv6.h:81
uint8_t duid[0]
DHCP unique identifier (DUID)
Definition: dhcpv6.h:52
#define IPV6_MAX_PREFIX_LEN
IPv6 maximum prefix length.
Definition: ipv6.h:33
#define DHCPV6_USER_CLASS
DHCPv6 user class option.
Definition: dhcpv6.h:147
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
size_t len
Length of data buffer.
Definition: dhcpv6.c:90
uint64_t address
Base address.
Definition: ena.h:24
struct dhcpv6_option options[0]
IA_NA options.
Definition: dhcpv6.h:72
uint32_t type
Operating system type.
Definition: ena.h:12
uint16_t status
Status code.
Definition: dhcpv6.h:122
#define SOCK_DGRAM
Definition: socket.h:30
static int dhcpv6_status_code(struct dhcpv6_option_list *options)
Get DHCPv6 status code.
Definition: dhcpv6.c:167
#define EPROTO_STATUS(status)
Definition: dhcpv6.c:69
#define __einfo_errortab(einfo)
Definition: errortab.h:24
Retry timers.
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
uint32_t iaid
Identity association identifier (IAID)
Definition: dhcpv6.h:66
#define DHCPV6_VENDOR_CLASS_PXE
DHCPv6 PXE vendor class.
Definition: dhcpv6.h:162
#define DHCPV6_SETTINGS_NAME
DHCPv6 settings block name.
Definition: dhcpv6.h:266
#define DBGC(...)
Definition: compiler.h:505
struct sockaddr_in6 sin6
Definition: syslog.c:60
A retry timer.
Definition: retry.h:22
static int dhcpv6_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of DHCPv6 setting.
Definition: dhcpv6.c:285
uint32_t iaid
Identity association ID.
Definition: dhcpv6.c:585
#define ENOENT
No such file or directory.
Definition: errno.h:515
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition: interface.c:108
int(* fetch)(struct dhcpv6_settings *dhcpv6set, void *data, size_t len)
Fetch value of setting.
Definition: dhcpv6.c:367
struct net_device * netdev
Network device being configured.
Definition: dhcpv6.c:579
#define DHCPV6_INFORMATION_REQUEST
DHCPv6 information request.
Definition: dhcpv6.h:263
const struct setting ip6_setting
static const char * dhcpv6_type_name(unsigned int type)
Name a DHCPv6 packet type.
Definition: dhcpv6.c:504
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition: xfer.c:159
int fetch_raw_setting(struct settings *settings, const struct setting *setting, void *data, size_t len)
Fetch value of setting.
Definition: settings.c:804
uint8_t options[0]
DHCP options.
Definition: dhcp.h:684
uint32_t xid
Transaction ID.
Definition: dhcp.h:634
uint32_t data_len
Microcode data size (or 0 to indicate 2000 bytes)
Definition: ucode.h:26
iPXE timers
uint8_t tx_type
Current transmitted packet type.
Definition: dhcpv6.c:522
#define ntohs(value)
Definition: byteswap.h:137
static struct settings_operations dhcpv6_settings_operations
DHCPv6 settings operations.
Definition: dhcpv6.c:422
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:25
Address assigned via DHCPv6.
Definition: ipv6.h:289
#define DHCPV6_VENDOR_CLASS
DHCPv6 vendor class option.
Definition: dhcpv6.h:150
A DHCPv6 settings block.
Definition: dhcpv6.c:265
static void dhcpv6_finished(struct dhcpv6_session *dhcpv6, int rc)
Terminate DHCPv6 session.
Definition: dhcpv6.c:626
DHCPv6 user class option.
Definition: dhcpv6.h:139
#define DHCPV6_REPLY
DHCPv6 reply.
Definition: dhcpv6.h:260
static unsigned int code
Response code.
Definition: hyperv.h:26
A DHCPv6 header.
Definition: dhcpv6.h:241
struct in6_addr lease
Leased IPv6 address.
Definition: dhcpv6.c:595
#define htonl(value)
Definition: byteswap.h:134
unsigned int scope_id
Scope ID.
Definition: netdevice.h:361
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:587
A link-layer protocol.
Definition: netdevice.h:115
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
Any DHCPv6 option.
Definition: dhcpv6.h:226
Record received IPv6 address.
Definition: dhcpv6.c:540
#define DHCPV6_DWORD_VALUE(value)
Construct a DHCPv6 dword value.
Definition: dhcpv6.h:197
Data transfer interfaces.
A reference counter.
Definition: refcnt.h:27
A timer.
Definition: timer.h:29
const char * name
Name.
Definition: settings.h:29
u32 crc32_le(u32 seed, const void *data, size_t len)
Calculate 32-bit little-endian CRC checksum.
Definition: crc32.c:40
struct dhcpv6_option header
Option header.
Definition: dhcpv6.h:109
FILE_SECBOOT(PERMITTED)
struct dhcpv6_session_state * state
Current session state.
Definition: dhcpv6.c:601
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:44
#define ENOMEM
Not enough space.
Definition: errno.h:535
struct in6_addr lease
Leased address.
Definition: dhcpv6.c:271
int start_dhcpv6(struct interface *job, struct net_device *netdev, struct in6_addr *router, int stateful)
Start DHCPv6.
Definition: dhcpv6.c:1000
#define DHCPV6_CLIENT_ID
DHCPv6 client identifier option.
Definition: dhcpv6.h:56
void * memcpy(void *dest, const void *src, size_t len) __nonnull
const struct setting filename6_setting __setting(SETTING_BOOT, filename)
Boot filename setting.
DHCP client architecture definitions.
uint32_t valid
Valid lifetime (in seconds)
Definition: dhcpv6.h:87
const struct setting gateway6_setting
const struct setting len6_setting
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
uint8_t flags
Flags.
Definition: dhcpv6.c:526
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition: netdevice.h:576
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
An object interface.
Definition: interface.h:125
static const void * src
Definition: string.h:48
A long option, as used for getopt_long()
Definition: getopt.h:25
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
struct dhcpv6_option options[0]
IAADDR options.
Definition: dhcpv6.h:89
static int options
Definition: 3c515.c:286
struct settings settings
Settings block.
Definition: dhcpv6.c:269
struct dhcpv6_option header
Option header.
Definition: dhcpv6.h:120
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
Object interfaces.
ring len
Length.
Definition: dwmac.h:231
#define DHCPV6_ADVERTISE
DHCPv6 advertisement.
Definition: dhcpv6.h:254
struct dhcpv6_option_list options
Option list.
Definition: dhcpv6.c:275
static struct net_device * netdev
Definition: gdbudp.c:53
struct sockaddr sa
Definition: syslog.c:57
struct in6_addr router
Router address.
Definition: dhcpv6.c:581
void * server_duid
Server DUID, if known.
Definition: dhcpv6.c:591
struct refcnt refcnt
Reference counter.
Definition: dhcpv6.c:572
#define DHCP_ARCH_CLIENT_ARCHITECTURE
DHCP client architecture.
Definition: dhcparch.h:15
dhcpv6_session_state_flags
DHCPv6 session state flags.
Definition: dhcpv6.c:532
IP6 address structure.
Definition: in.h:51
#define IN6_IS_ADDR_UNSPECIFIED(addr)
Definition: in.h:62
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 void dhcpv6_timer_expired(struct retry_timer *timer, int fail)
Handle timer expiry.
Definition: dhcpv6.c:817
#define DHCPV6_CODE(code)
Construct a DHCPv6 option code.
Definition: dhcpv6.h:201
Configuration settings.
Generalized socket address structure.
Definition: socket.h:97
An object interface descriptor.
Definition: interface.h:56
static struct dhcpv6_session_state dhcpv6_information_request
DHCPv6 information request state.
Definition: dhcpv6.c:562
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
uint32_t rebind
Rebind time (in seconds)
Definition: dhcpv6.h:70
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 size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition: interface.h:33
#define EINFO_EPROTO_NOADDRSAVAIL
Definition: dhcpv6.c:58
A network device.
Definition: netdevice.h:353
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition: random.c:32
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:195
Settings block operations.
Definition: settings.h:86
A settings block.
Definition: settings.h:133
#define DHCPV6_DNS_SERVERS
DHCPv6 DNS recursive name server option.
Definition: dhcpv6.h:165
struct in6_addr address
IPv6 address.
Definition: dhcpv6.h:83
unsigned char uint8_t
Definition: stdint.h:10
#define SETTING_BOOT
Generic boot settings.
Definition: settings.h:72
Data transfer interface opening.
DHCPv6 client or server identifier option.
Definition: dhcpv6.h:48
DHCPv6 identity association address (IAADDR) option.
Definition: dhcpv6.h:79
static struct net_device * netdev_get(struct net_device *netdev)
Get reference to network device.
Definition: netdevice.h:565
#define DHCPV6_OPTION_REQUEST
DHCPv6 option request option.
Definition: dhcpv6.h:104
#define DHCPV6_REQUEST
DHCPv6 request.
Definition: dhcpv6.h:257
struct retry_timer timer
Retransmission timer.
Definition: dhcpv6.c:598
#define DHCPV6_DOMAIN_LIST
DHCPv6 domain search list option.
Definition: dhcpv6.h:168
unsigned int uint32_t
Definition: stdint.h:12
uint32_t next
Next descriptor address.
Definition: dwmac.h:22
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:621
IPv6 protocol.
static struct dhcpv6_address_operation dhcpv6_address_operations[]
DHCPv6 address settings operations.
Definition: dhcpv6.c:372
uint8_t unused
Unused.
Definition: librm.h:140
int rc
Current timeout status code.
Definition: dhcpv6.c:603
A setting.
Definition: settings.h:24
DHCPv6 status code option.
Definition: dhcpv6.h:118
uint8_t status
Status.
Definition: ena.h:16
static int dhcpv6_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of DHCPv6 setting.
Definition: dhcpv6.c:387
void start_timer(struct retry_timer *timer)
Start timer.
Definition: retry.c:94
static int dhcpv6_rx(struct dhcpv6_session *dhcpv6, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive new data.
Definition: dhcpv6.c:842
A DHCP header.
Definition: dhcp.h:616
Network device management.
A DHCPv6 option list.
Definition: dhcpv6.c:86
uint32_t renew
Renew time (in seconds)
Definition: dhcpv6.h:68
uint32_t lease
Definition: ib_mad.h:16
static uint16_t struct vmbus_xfer_pages_operations * op
Definition: netvsc.h:327
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition: interface.h:81
int order
Sibling ordering.
Definition: settings.h:149
struct refcnt refcnt
Reference count.
Definition: dhcpv6.c:267
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition: retry.c:118
uint16_t type
Type.
Definition: dhcpv6.h:39
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:363
size_t server_duid_len
Server DUID length.
Definition: dhcpv6.c:593
uint16_t len
Length of the data field.
Definition: dhcpv6.h:31
#define ENOTTY
Inappropriate I/O control operation.
Definition: errno.h:595
unsigned long start
Start time (in ticks)
Definition: dhcpv6.c:587
#define DHCP_ARCH_CLIENT_NDI
DHCP client network device interface.
Definition: dhcparch.h:18
A DHCPv6 address setting operation.
Definition: dhcpv6.c:356
struct dhcpv6_option header
Option header.
Definition: dhcpv6.h:64
void * data
Start of data.
Definition: iobuf.h:53
const struct setting * setting
Generic setting.
Definition: dhcpv6.c:358
struct dhcpv6_duid_uuid client_duid
Client DUID.
Definition: dhcpv6.c:589
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
uint8_t xid[3]
Transaction ID.
Definition: dhcpv6.c:583
#define DHCPV6_WORD(value)
Construct a word-valued DHCPv6 option.
Definition: dhcpv6.h:217
uint8_t data[48]
Additional event data.
Definition: ena.h:22
static const union dhcpv6_any_option * dhcpv6_option(struct dhcpv6_option_list *options, unsigned int code)
Find DHCPv6 option.
Definition: dhcpv6.c:101
#define DHCPV6_CLIENT_PORT
DHCPv6 client port.
Definition: dhcpv6.h:21
static struct interface_descriptor dhcpv6_job_desc
DHCPv6 job control interface descriptor.
Definition: dhcpv6.c:979
static int dhcpv6_fetch_gateway6(struct dhcpv6_settings *dhcpv6set, void *data, size_t len)
Fetch value of DHCPv6 router address.
Definition: dhcpv6.c:343
IPv6 socket address.
Definition: in.h:118
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:383
#define DHCPV6_STRING(...)
Construct a DHCPv6 option from a list of characters.
Definition: dhcpv6.h:211
int(* applies)(struct settings *settings, const struct setting *setting)
Check applicability of setting.
Definition: settings.h:99
#define DHCPV6_DUID_UUID
DHCP unique identifier based on UUID (DUID-UUID)
Definition: dhcpv6.h:45
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition: settings.c:476
int fetch_uuid_setting(struct settings *settings, const struct setting *setting, union uuid *uuid)
Fetch value of UUID setting.
Definition: settings.c:1085
#define DHCPV6_SERVER_PORT
DHCPv6 server port.
Definition: dhcpv6.h:18
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:48
const struct settings_scope ipv6_settings_scope
IPv6 settings scope.
Definition: ipv6.c:1121
#define DHCP_VENDOR_PXECLIENT(arch, ndi)
Vendor class identifier for PXE clients.
Definition: dhcp.h:220
A DHCPv6 session state.
Definition: dhcpv6.c:520
#define DHCPV6_IAADDR
DHCPv6 identity association address (IAADDR) option.
Definition: dhcpv6.h:93
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition: netdevice.h:388
uint8_t meta
Metadata flags.
Definition: ena.h:14
uint16_t elapsed
Elapsed time, in centiseconds.
Definition: dhcpv6.h:111
unsigned long currticks(void)
Get current system time in ticks.
Definition: timer.c:43
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition: interface.h:204
const struct settings_scope * scope
Setting scope (or NULL)
Definition: settings.h:50
static size_t dhcpv6_user_class(void *data, size_t len)
Get DHCPv6 user class.
Definition: dhcpv6.c:665
#define DHCPV6_STATUS_CODE
DHCPv6 status code option.
Definition: dhcpv6.h:128
uint32_t preferred
Preferred lifetime (in seconds)
Definition: dhcpv6.h:85
uint16_t code
Code.
Definition: dhcpv6.h:29
struct in6_addr router
Router address.
Definition: dhcpv6.c:273
Include identity association within request.
Definition: dhcpv6.c:534
struct dhcpv6_option header
Option header.
Definition: dhcpv6.h:50
int setting_cmp(const struct setting *a, const struct setting *b)
Compare two settings.
Definition: settings.c:1121
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:115
#define DHCPV6_CLIENT_ARCHITECTURE
DHCPv6 client system architecture option.
Definition: dhcpv6.h:177
DHCPv6 identity association for non-temporary address (IA_NA) option.
Definition: dhcpv6.h:62
static struct dhcpv6_session_state dhcpv6_request
DHCPv6 request state.
Definition: dhcpv6.c:544
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:670
const void * data
Data buffer.
Definition: dhcpv6.c:88
String functions.
#define htons(value)
Definition: byteswap.h:136
struct bofm_section_header done
Definition: bofm_test.c:46
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
struct ll_protocol * ll_protocol
Link-layer protocol.
Definition: netdevice.h:373
struct dhcpv6_user_class user_class[0]
User class.
Definition: dhcpv6.h:143
#define DHCPV6_BOOTFILE_URL
DHCPv6 bootfile URI option.
Definition: dhcpv6.h:171
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:107
Dynamic Host Configuration Protocol for IPv6.
struct errortab dhcpv6_errors [] __errortab
Human-readable error messages.
Definition: dhcpv6.c:75
#define DHCPV6_CLIENT_NDI
DHCPv6 client network interface identifier option.
Definition: dhcpv6.h:180
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:38
struct dhcpv6_option header
Option header.
Definition: dhcpv6.h:141
#define DHCPV6_OPTION(...)
Construct a DHCPv6 option from a list of bytes.
Definition: dhcpv6.h:207
DHCPv6 elapsed time option.
Definition: dhcpv6.h:107
union uuid uuid
UUID.
Definition: dhcpv6.h:41