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