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/dhcp_arch.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  /** Option list */
273 };
274 
275 /**
276  * Check applicability of DHCPv6 setting
277  *
278  * @v settings Settings block
279  * @v setting Setting
280  * @ret applies Setting applies within this settings block
281  */
283  const struct setting *setting ) {
284 
285  return ( ( setting->scope == &dhcpv6_scope ) ||
286  ( setting_cmp ( setting, &ip6_setting ) == 0 ) );
287 }
288 
289 /**
290  * Fetch value of DHCPv6 leased address
291  *
292  * @v dhcpset DHCPv6 settings
293  * @v data Buffer to fill with setting data
294  * @v len Length of buffer
295  * @ret len Length of setting data, or negative error
296  */
297 static int dhcpv6_fetch_lease ( struct dhcpv6_settings *dhcpv6set,
298  void *data, size_t len ) {
299  struct in6_addr *lease = &dhcpv6set->lease;
300 
301  /* Do nothing unless a leased address exists */
302  if ( IN6_IS_ADDR_UNSPECIFIED ( lease ) )
303  return -ENOENT;
304 
305  /* Copy leased address */
306  if ( len > sizeof ( *lease ) )
307  len = sizeof ( *lease );
308  memcpy ( data, lease, len );
309 
310  return sizeof ( *lease );
311 }
312 
313 /**
314  * Fetch value of DHCPv6 setting
315  *
316  * @v settings Settings block
317  * @v setting Setting to fetch
318  * @v data Buffer to fill with setting data
319  * @v len Length of buffer
320  * @ret len Length of setting data, or negative error
321  */
322 static int dhcpv6_fetch ( struct settings *settings,
323  struct setting *setting,
324  void *data, size_t len ) {
325  struct dhcpv6_settings *dhcpv6set =
327  const union dhcpv6_any_option *option;
328  size_t option_len;
329 
330  /* Handle leased address */
331  if ( setting_cmp ( setting, &ip6_setting ) == 0 )
332  return dhcpv6_fetch_lease ( dhcpv6set, data, len );
333 
334  /* Find option */
335  option = dhcpv6_option ( &dhcpv6set->options, setting->tag );
336  if ( ! option )
337  return -ENOENT;
338 
339  /* Copy option to data buffer */
340  option_len = ntohs ( option->header.len );
341  if ( len > option_len )
342  len = option_len;
343  memcpy ( data, option->header.data, len );
344  return option_len;
345 }
346 
347 /** DHCPv6 settings operations */
350  .fetch = dhcpv6_fetch,
351 };
352 
353 /**
354  * Register DHCPv6 options as network device settings
355  *
356  * @v lease DHCPv6 leased address
357  * @v options DHCPv6 option list
358  * @v parent Parent settings block
359  * @ret rc Return status code
360  */
361 static int dhcpv6_register ( struct in6_addr *lease,
362  struct dhcpv6_option_list *options,
363  struct settings *parent ) {
364  struct dhcpv6_settings *dhcpv6set;
365  void *data;
366  size_t len;
367  int rc;
368 
369  /* Allocate and initialise structure */
370  dhcpv6set = zalloc ( sizeof ( *dhcpv6set ) + options->len );
371  if ( ! dhcpv6set ) {
372  rc = -ENOMEM;
373  goto err_alloc;
374  }
375  ref_init ( &dhcpv6set->refcnt, NULL );
377  &dhcpv6set->refcnt, &dhcpv6_scope );
378  dhcpv6set->settings.order = IPV6_ORDER_DHCPV6;
379  data = ( ( ( void * ) dhcpv6set ) + sizeof ( *dhcpv6set ) );
380  len = options->len;
381  memcpy ( data, options->data, len );
382  dhcpv6set->options.data = data;
383  dhcpv6set->options.len = len;
384  memcpy ( &dhcpv6set->lease, lease, sizeof ( dhcpv6set->lease ) );
385 
386  /* Register settings */
387  if ( ( rc = register_settings ( &dhcpv6set->settings, parent,
388  DHCPV6_SETTINGS_NAME ) ) != 0 )
389  goto err_register;
390 
391  err_register:
392  ref_put ( &dhcpv6set->refcnt );
393  err_alloc:
394  return rc;
395 }
396 
397 /****************************************************************************
398  *
399  * DHCPv6 protocol
400  *
401  */
402 
403 /** Raw option data for options common to all DHCPv6 requests */
412  DHCPV6_STRING (
414  DHCP_ARCH_CLIENT_NDI ) ) ),
419 };
420 
421 /**
422  * Name a DHCPv6 packet type
423  *
424  * @v type DHCPv6 packet type
425  * @ret name DHCPv6 packet type name
426  */
427 static __attribute__ (( unused )) const char *
428 dhcpv6_type_name ( unsigned int type ) {
429  static char buf[ 12 /* "UNKNOWN-xxx" + NUL */ ];
430 
431  switch ( type ) {
432  case DHCPV6_SOLICIT: return "SOLICIT";
433  case DHCPV6_ADVERTISE: return "ADVERTISE";
434  case DHCPV6_REQUEST: return "REQUEST";
435  case DHCPV6_REPLY: return "REPLY";
436  case DHCPV6_INFORMATION_REQUEST: return "INFORMATION-REQUEST";
437  default:
438  snprintf ( buf, sizeof ( buf ), "UNKNOWN-%d", type );
439  return buf;
440  }
441 }
442 
443 /** A DHCPv6 session state */
445  /** Current transmitted packet type */
447  /** Current expected received packet type */
449  /** Flags */
451  /** Next state (or NULL to terminate) */
453 };
454 
455 /** DHCPv6 session state flags */
457  /** Include identity association within request */
459  /** Include leased IPv6 address within request */
461  /** Record received server ID */
463  /** Record received IPv6 address */
465 };
466 
467 /** DHCPv6 request state */
470  .rx_type = DHCPV6_REPLY,
471  .flags = ( DHCPV6_TX_IA_NA | DHCPV6_TX_IAADDR |
473  .next = NULL,
474 };
475 
476 /** DHCPv6 solicitation state */
479  .rx_type = DHCPV6_ADVERTISE,
482  .next = &dhcpv6_request,
483 };
484 
485 /** DHCPv6 information request state */
488  .rx_type = DHCPV6_REPLY,
489  .flags = 0,
490  .next = NULL,
491 };
492 
493 /** A DHCPv6 session */
495  /** Reference counter */
496  struct refcnt refcnt;
497  /** Job control interface */
498  struct interface job;
499  /** Data transfer interface */
500  struct interface xfer;
501 
502  /** Network device being configured */
504  /** Transaction ID */
506  /** Identity association ID */
508  /** Start time (in ticks) */
509  unsigned long start;
510  /** Client DUID */
512  /** Server DUID, if known */
513  void *server_duid;
514  /** Server DUID length */
516  /** Leased IPv6 address */
517  struct in6_addr lease;
518 
519  /** Retransmission timer */
521 
522  /** Current session state */
524  /** Current timeout status code */
525  int rc;
526 };
527 
528 /**
529  * Free DHCPv6 session
530  *
531  * @v refcnt Reference count
532  */
533 static void dhcpv6_free ( struct refcnt *refcnt ) {
534  struct dhcpv6_session *dhcpv6 =
536 
537  netdev_put ( dhcpv6->netdev );
538  free ( dhcpv6->server_duid );
539  free ( dhcpv6 );
540 }
541 
542 /**
543  * Terminate DHCPv6 session
544  *
545  * @v dhcpv6 DHCPv6 session
546  * @v rc Reason for close
547  */
548 static void dhcpv6_finished ( struct dhcpv6_session *dhcpv6, int rc ) {
549 
550  /* Stop timer */
551  stop_timer ( &dhcpv6->timer );
552 
553  /* Shut down interfaces */
554  intf_shutdown ( &dhcpv6->xfer, rc );
555  intf_shutdown ( &dhcpv6->job, rc );
556 }
557 
558 /**
559  * Transition to new DHCPv6 session state
560  *
561  * @v dhcpv6 DHCPv6 session
562  * @v state New session state
563  */
564 static void dhcpv6_set_state ( struct dhcpv6_session *dhcpv6,
565  struct dhcpv6_session_state *state ) {
566 
567  DBGC ( dhcpv6, "DHCPv6 %s entering %s state\n", dhcpv6->netdev->name,
568  dhcpv6_type_name ( state->tx_type ) );
569 
570  /* Record state */
571  dhcpv6->state = state;
572 
573  /* Default to -ETIMEDOUT if no more specific error is recorded */
574  dhcpv6->rc = -ETIMEDOUT;
575 
576  /* Start timer to trigger transmission */
577  start_timer_nodelay ( &dhcpv6->timer );
578 }
579 
580 /**
581  * Get DHCPv6 user class
582  *
583  * @v data Data buffer
584  * @v len Length of data buffer
585  * @ret len Length of user class
586  */
587 static size_t dhcpv6_user_class ( void *data, size_t len ) {
588  static const char default_user_class[4] = { 'i', 'P', 'X', 'E' };
589  int actual_len;
590 
591  /* Fetch user-class setting, if defined */
592  actual_len = fetch_raw_setting ( NULL, &user_class_setting, data, len );
593  if ( actual_len >= 0 )
594  return actual_len;
595 
596  /* Otherwise, use the default user class ("iPXE") */
597  if ( len > sizeof ( default_user_class ) )
598  len = sizeof ( default_user_class );
599  memcpy ( data, default_user_class, len );
600  return sizeof ( default_user_class );
601 }
602 
603 /**
604  * Transmit current request
605  *
606  * @v dhcpv6 DHCPv6 session
607  * @ret rc Return status code
608  */
609 static int dhcpv6_tx ( struct dhcpv6_session *dhcpv6 ) {
610  struct dhcpv6_duid_option *client_id;
611  struct dhcpv6_duid_option *server_id;
612  struct dhcpv6_ia_na_option *ia_na;
613  struct dhcpv6_iaaddr_option *iaaddr;
616  struct dhcpv6_header *dhcphdr;
617  struct io_buffer *iobuf;
618  void *options;
619  size_t client_id_len;
620  size_t server_id_len;
621  size_t ia_na_len;
622  size_t user_class_string_len;
623  size_t user_class_len;
624  size_t elapsed_len;
625  size_t total_len;
626  int rc;
627 
628  /* Calculate lengths */
629  client_id_len = ( sizeof ( *client_id ) +
630  sizeof ( dhcpv6->client_duid ) );
631  server_id_len = ( dhcpv6->server_duid ? ( sizeof ( *server_id ) +
632  dhcpv6->server_duid_len ) :0);
633  if ( dhcpv6->state->flags & DHCPV6_TX_IA_NA ) {
634  ia_na_len = sizeof ( *ia_na );
635  if ( dhcpv6->state->flags & DHCPV6_TX_IAADDR )
636  ia_na_len += sizeof ( *iaaddr );
637  } else {
638  ia_na_len = 0;
639  }
640  user_class_string_len = dhcpv6_user_class ( NULL, 0 );
641  user_class_len = ( sizeof ( *user_class ) +
642  sizeof ( user_class->user_class[0] ) +
643  user_class_string_len );
644  elapsed_len = sizeof ( *elapsed );
645  total_len = ( sizeof ( *dhcphdr ) + client_id_len + server_id_len +
646  ia_na_len + sizeof ( dhcpv6_request_options_data ) +
647  user_class_len + elapsed_len );
648 
649  /* Allocate packet */
650  iobuf = xfer_alloc_iob ( &dhcpv6->xfer, total_len );
651  if ( ! iobuf )
652  return -ENOMEM;
653 
654  /* Construct header */
655  dhcphdr = iob_put ( iobuf, sizeof ( *dhcphdr ) );
656  dhcphdr->type = dhcpv6->state->tx_type;
657  memcpy ( dhcphdr->xid, dhcpv6->xid, sizeof ( dhcphdr->xid ) );
658 
659  /* Construct client identifier */
660  client_id = iob_put ( iobuf, client_id_len );
661  client_id->header.code = htons ( DHCPV6_CLIENT_ID );
662  client_id->header.len = htons ( client_id_len -
663  sizeof ( client_id->header ) );
664  memcpy ( client_id->duid, &dhcpv6->client_duid,
665  sizeof ( dhcpv6->client_duid ) );
666 
667  /* Construct server identifier, if applicable */
668  if ( server_id_len ) {
669  server_id = iob_put ( iobuf, server_id_len );
670  server_id->header.code = htons ( DHCPV6_SERVER_ID );
671  server_id->header.len = htons ( server_id_len -
672  sizeof ( server_id->header ) );
673  memcpy ( server_id->duid, dhcpv6->server_duid,
674  dhcpv6->server_duid_len );
675  }
676 
677  /* Construct identity association, if applicable */
678  if ( ia_na_len ) {
679  ia_na = iob_put ( iobuf, ia_na_len );
680  ia_na->header.code = htons ( DHCPV6_IA_NA );
681  ia_na->header.len = htons ( ia_na_len -
682  sizeof ( ia_na->header ) );
683  ia_na->iaid = htonl ( dhcpv6->iaid );
684  ia_na->renew = htonl ( 0 );
685  ia_na->rebind = htonl ( 0 );
686  if ( dhcpv6->state->flags & DHCPV6_TX_IAADDR ) {
687  iaaddr = ( ( void * ) ia_na->options );
688  iaaddr->header.code = htons ( DHCPV6_IAADDR );
689  iaaddr->header.len = htons ( sizeof ( *iaaddr ) -
690  sizeof ( iaaddr->header ));
691  memcpy ( &iaaddr->address, &dhcpv6->lease,
692  sizeof ( iaaddr->address ) );
693  iaaddr->preferred = htonl ( 0 );
694  iaaddr->valid = htonl ( 0 );
695  }
696  }
697 
698  /* Construct fixed request options */
699  options = iob_put ( iobuf, sizeof ( dhcpv6_request_options_data ) );
701  sizeof ( dhcpv6_request_options_data ) );
702 
703  /* Construct user class */
704  user_class = iob_put ( iobuf, user_class_len );
705  user_class->header.code = htons ( DHCPV6_USER_CLASS );
706  user_class->header.len = htons ( user_class_len -
707  sizeof ( user_class->header ) );
708  user_class->user_class[0].len = htons ( user_class_string_len );
709  dhcpv6_user_class ( user_class->user_class[0].string,
710  user_class_string_len );
711 
712  /* Construct elapsed time */
713  elapsed = iob_put ( iobuf, elapsed_len );
714  elapsed->header.code = htons ( DHCPV6_ELAPSED_TIME );
715  elapsed->header.len = htons ( elapsed_len -
716  sizeof ( elapsed->header ) );
717  elapsed->elapsed = htons ( ( ( currticks() - dhcpv6->start ) * 100 ) /
718  TICKS_PER_SEC );
719 
720  /* Sanity check */
721  assert ( iob_len ( iobuf ) == total_len );
722 
723  /* Transmit packet */
724  if ( ( rc = xfer_deliver_iob ( &dhcpv6->xfer, iobuf ) ) != 0 ) {
725  DBGC ( dhcpv6, "DHCPv6 %s could not transmit: %s\n",
726  dhcpv6->netdev->name, strerror ( rc ) );
727  return rc;
728  }
729 
730  return 0;
731 }
732 
733 /**
734  * Handle timer expiry
735  *
736  * @v timer Retransmission timer
737  * @v fail Failure indicator
738  */
739 static void dhcpv6_timer_expired ( struct retry_timer *timer, int fail ) {
740  struct dhcpv6_session *dhcpv6 =
741  container_of ( timer, struct dhcpv6_session, timer );
742 
743  /* If we have failed, terminate DHCPv6 */
744  if ( fail ) {
745  dhcpv6_finished ( dhcpv6, dhcpv6->rc );
746  return;
747  }
748 
749  /* Restart timer */
750  start_timer ( &dhcpv6->timer );
751 
752  /* (Re)transmit current request */
753  dhcpv6_tx ( dhcpv6 );
754 }
755 
756 /**
757  * Receive new data
758  *
759  * @v dhcpv6 DHCPv6 session
760  * @v iobuf I/O buffer
761  * @v meta Data transfer metadata
762  * @ret rc Return status code
763  */
764 static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6,
765  struct io_buffer *iobuf,
766  struct xfer_metadata *meta ) {
767  struct settings *parent = netdev_settings ( dhcpv6->netdev );
768  struct sockaddr_in6 *src = ( ( struct sockaddr_in6 * ) meta->src );
769  struct dhcpv6_header *dhcphdr = iobuf->data;
771  const union dhcpv6_any_option *option;
772  int rc;
773 
774  /* Sanity checks */
775  if ( iob_len ( iobuf ) < sizeof ( *dhcphdr ) ) {
776  DBGC ( dhcpv6, "DHCPv6 %s received packet too short (%zd "
777  "bytes, min %zd bytes)\n", dhcpv6->netdev->name,
778  iob_len ( iobuf ), sizeof ( *dhcphdr ) );
779  rc = -EINVAL;
780  goto done;
781  }
782  assert ( src != NULL );
783  assert ( src->sin6_family == AF_INET6 );
784  DBGC ( dhcpv6, "DHCPv6 %s received %s from %s\n",
785  dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ),
786  inet6_ntoa ( &src->sin6_addr ) );
787 
788  /* Construct option list */
789  options.data = dhcphdr->options;
790  options.len = ( iob_len ( iobuf ) -
791  offsetof ( typeof ( *dhcphdr ), options ) );
792 
793  /* Verify client identifier */
795  &dhcpv6->client_duid,
796  sizeof ( dhcpv6->client_duid ) ) ) !=0){
797  DBGC ( dhcpv6, "DHCPv6 %s received %s without correct client "
798  "ID: %s\n", dhcpv6->netdev->name,
799  dhcpv6_type_name ( dhcphdr->type ), strerror ( rc ) );
800  goto done;
801  }
802 
803  /* Verify server identifier, if applicable */
804  if ( dhcpv6->server_duid &&
806  dhcpv6->server_duid,
807  dhcpv6->server_duid_len ) ) != 0 ) ) {
808  DBGC ( dhcpv6, "DHCPv6 %s received %s without correct server "
809  "ID: %s\n", dhcpv6->netdev->name,
810  dhcpv6_type_name ( dhcphdr->type ), strerror ( rc ) );
811  goto done;
812  }
813 
814  /* Check message type */
815  if ( dhcphdr->type != dhcpv6->state->rx_type ) {
816  DBGC ( dhcpv6, "DHCPv6 %s received %s while expecting %s\n",
817  dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ),
818  dhcpv6_type_name ( dhcpv6->state->rx_type ) );
819  rc = -ENOTTY;
820  goto done;
821  }
822 
823  /* Fetch status code, if present */
824  if ( ( rc = dhcpv6_status_code ( &options ) ) != 0 ) {
825  DBGC ( dhcpv6, "DHCPv6 %s received %s with error status: %s\n",
826  dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ),
827  strerror ( rc ) );
828  /* This is plausibly the error we want to return */
829  dhcpv6->rc = rc;
830  goto done;
831  }
832 
833  /* Record identity association address, if applicable */
834  if ( dhcpv6->state->flags & DHCPV6_RX_RECORD_IAADDR ) {
835  if ( ( rc = dhcpv6_iaaddr ( &options, dhcpv6->iaid,
836  &dhcpv6->lease ) ) != 0 ) {
837  DBGC ( dhcpv6, "DHCPv6 %s received %s with unusable "
838  "IAADDR: %s\n", dhcpv6->netdev->name,
839  dhcpv6_type_name ( dhcphdr->type ),
840  strerror ( rc ) );
841  /* This is plausibly the error we want to return */
842  dhcpv6->rc = rc;
843  goto done;
844  }
845  DBGC ( dhcpv6, "DHCPv6 %s received %s is for %s\n",
846  dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ),
847  inet6_ntoa ( &dhcpv6->lease ) );
848  }
849 
850  /* Record server ID, if applicable */
851  if ( dhcpv6->state->flags & DHCPV6_RX_RECORD_SERVER_ID ) {
852  assert ( dhcpv6->server_duid == NULL );
854  if ( ! option ) {
855  DBGC ( dhcpv6, "DHCPv6 %s received %s missing server "
856  "ID\n", dhcpv6->netdev->name,
857  dhcpv6_type_name ( dhcphdr->type ) );
858  rc = -EINVAL;
859  goto done;
860  }
861  dhcpv6->server_duid_len = ntohs ( option->duid.header.len );
862  dhcpv6->server_duid = malloc ( dhcpv6->server_duid_len );
863  if ( ! dhcpv6->server_duid ) {
864  rc = -ENOMEM;
865  goto done;
866  }
867  memcpy ( dhcpv6->server_duid, option->duid.duid,
868  dhcpv6->server_duid_len );
869  }
870 
871  /* Transition to next state, if applicable */
872  if ( dhcpv6->state->next ) {
873  dhcpv6_set_state ( dhcpv6, dhcpv6->state->next );
874  rc = 0;
875  goto done;
876  }
877 
878  /* Register settings */
879  if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &options,
880  parent ) ) != 0 ) {
881  DBGC ( dhcpv6, "DHCPv6 %s could not register settings: %s\n",
882  dhcpv6->netdev->name, strerror ( rc ) );
883  goto done;
884  }
885 
886  /* Mark as complete */
887  dhcpv6_finished ( dhcpv6, 0 );
888  DBGC ( dhcpv6, "DHCPv6 %s complete\n", dhcpv6->netdev->name );
889 
890  done:
891  free_iob ( iobuf );
892  return rc;
893 }
894 
895 /** DHCPv6 job control interface operations */
898 };
899 
900 /** DHCPv6 job control interface descriptor */
902  INTF_DESC ( struct dhcpv6_session, job, dhcpv6_job_op );
903 
904 /** DHCPv6 data transfer interface operations */
907 };
908 
909 /** DHCPv6 data transfer interface descriptor */
911  INTF_DESC ( struct dhcpv6_session, xfer, dhcpv6_xfer_op );
912 
913 /**
914  * Start DHCPv6
915  *
916  * @v job Job control interface
917  * @v netdev Network device
918  * @v stateful Perform stateful address autoconfiguration
919  * @ret rc Return status code
920  */
921 int start_dhcpv6 ( struct interface *job, struct net_device *netdev,
922  int stateful ) {
924  struct dhcpv6_session *dhcpv6;
925  struct {
926  union {
927  struct sockaddr_in6 sin6;
928  struct sockaddr sa;
929  } client;
930  union {
931  struct sockaddr_in6 sin6;
932  struct sockaddr sa;
933  } server;
934  } addresses;
935  uint32_t xid;
936  int len;
937  int rc;
938 
939  /* Allocate and initialise structure */
940  dhcpv6 = zalloc ( sizeof ( *dhcpv6 ) );
941  if ( ! dhcpv6 )
942  return -ENOMEM;
943  ref_init ( &dhcpv6->refcnt, dhcpv6_free );
944  intf_init ( &dhcpv6->job, &dhcpv6_job_desc, &dhcpv6->refcnt );
945  intf_init ( &dhcpv6->xfer, &dhcpv6_xfer_desc, &dhcpv6->refcnt );
946  dhcpv6->netdev = netdev_get ( netdev );
947  xid = random();
948  memcpy ( dhcpv6->xid, &xid, sizeof ( dhcpv6->xid ) );
949  dhcpv6->start = currticks();
950  timer_init ( &dhcpv6->timer, dhcpv6_timer_expired, &dhcpv6->refcnt );
951 
952  /* Construct client and server addresses */
953  memset ( &addresses, 0, sizeof ( addresses ) );
954  addresses.client.sin6.sin6_family = AF_INET6;
955  addresses.client.sin6.sin6_port = htons ( DHCPV6_CLIENT_PORT );
956  addresses.server.sin6.sin6_family = AF_INET6;
957  ipv6_all_dhcp_relay_and_servers ( &addresses.server.sin6.sin6_addr );
958  addresses.server.sin6.sin6_scope_id = netdev->index;
959  addresses.server.sin6.sin6_port = htons ( DHCPV6_SERVER_PORT );
960 
961  /* Construct client DUID from system UUID */
962  dhcpv6->client_duid.type = htons ( DHCPV6_DUID_UUID );
963  if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
964  &dhcpv6->client_duid.uuid ) ) < 0 ) {
965  rc = len;
966  DBGC ( dhcpv6, "DHCPv6 %s could not create DUID-UUID: %s\n",
967  dhcpv6->netdev->name, strerror ( rc ) );
968  goto err_client_duid;
969  }
970 
971  /* Construct IAID from link-layer address */
972  dhcpv6->iaid = crc32_le ( 0, netdev->ll_addr, ll_protocol->ll_addr_len);
973  DBGC ( dhcpv6, "DHCPv6 %s has XID %02x%02x%02x\n", dhcpv6->netdev->name,
974  dhcpv6->xid[0], dhcpv6->xid[1], dhcpv6->xid[2] );
975 
976  /* Enter initial state */
977  dhcpv6_set_state ( dhcpv6, ( stateful ? &dhcpv6_solicit :
979 
980  /* Open socket */
981  if ( ( rc = xfer_open_socket ( &dhcpv6->xfer, SOCK_DGRAM,
982  &addresses.server.sa,
983  &addresses.client.sa ) ) != 0 ) {
984  DBGC ( dhcpv6, "DHCPv6 %s could not open socket: %s\n",
985  dhcpv6->netdev->name, strerror ( rc ) );
986  goto err_open_socket;
987  }
988 
989  /* Attach parent interface, mortalise self, and return */
990  intf_plug_plug ( &dhcpv6->job, job );
991  ref_put ( &dhcpv6->refcnt );
992  return 0;
993 
994  err_open_socket:
995  dhcpv6_finished ( dhcpv6, rc );
996  err_client_duid:
997  ref_put ( &dhcpv6->refcnt );
998  return rc;
999 }
1000 
1001 /** Boot filename setting */
1002 const struct setting filename6_setting __setting ( SETTING_BOOT, filename ) = {
1003  .name = "filename",
1004  .description = "Boot filename",
1005  .tag = DHCPV6_BOOTFILE_URL,
1006  .type = &setting_type_string,
1007  .scope = &dhcpv6_scope,
1008 };
1009 
1010 /** DNS search list setting */
1011 const struct setting dnssl6_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
1012  .name = "dnssl",
1013  .description = "DNS search list",
1014  .tag = DHCPV6_DOMAIN_LIST,
1015  .type = &setting_type_dnssl,
1016  .scope = &dhcpv6_scope,
1017 };
uint8_t rx_type
Current expected received packet type.
Definition: dhcpv6.c:448
static struct dhcpv6_session_state dhcpv6_solicit
DHCPv6 solicitation state.
Definition: dhcpv6.c:477
struct dhcpv6_session_state * next
Next state (or NULL to terminate)
Definition: dhcpv6.c:452
#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:609
#define EINVAL
Invalid argument.
Definition: errno.h:428
An object interface operation.
Definition: interface.h:17
A DHCPv6 session.
Definition: dhcpv6.c:494
#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:462
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:244
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:116
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:273
#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:254
#define DHCP_ARCH_CLIENT_NDI
Definition: dhcp_arch.h:38
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:910
struct interface xfer
Data transfer interface.
Definition: dhcpv6.c:500
struct sockaddr sa
Definition: dns.c:68
const struct settings_scope dhcpv6_scope
IPv6 settings scope.
Definition: settings.c:1796
uint8_t state
State.
Definition: eth_slow.h:47
struct interface job
Job control interface.
Definition: dhcpv6.c:498
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:564
static struct interface_operation dhcpv6_job_op[]
DHCPv6 job control interface operations.
Definition: dhcpv6.c:896
uint32_t next
Next descriptor address.
Definition: myson.h:18
Include leased IPv6 address within request.
Definition: dhcpv6.c:460
static uint8_t dhcpv6_request_options_data[]
Raw option data for options common to all DHCPv6 requests.
Definition: dhcpv6.c:404
#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:141
struct settings * parent
Parent settings block.
Definition: settings.h:138
struct dhcpv6_option header
Option header.
Definition: dhcpv6.h:80
uint8_t duid[0]
DHCP unique identifier (DUID)
Definition: dhcpv6.h:51
#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:145
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
uint8_t type
Type.
Definition: ena.h:16
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
#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
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:282
uint32_t iaid
Identity association ID.
Definition: dhcpv6.c:507
#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:102
struct net_device * netdev
Network device being configured.
Definition: dhcpv6.c:503
#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:428
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition: xfer.c:157
int fetch_raw_setting(struct settings *settings, const struct setting *setting, void *data, size_t len)
Fetch value of setting.
Definition: settings.c:807
uint8_t options[0]
DHCP options.
Definition: dhcp.h:659
uint32_t xid
Transaction ID.
Definition: dhcp.h:609
iPXE timers
uint8_t tx_type
Current transmitted packet type.
Definition: dhcpv6.c:446
#define ntohs(value)
Definition: byteswap.h:136
static struct settings_operations dhcpv6_settings_operations
DHCPv6 settings operations.
Definition: dhcpv6.c:348
#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:548
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:517
#define htonl(value)
Definition: byteswap.h:133
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:577
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:495
Any DHCPv6 option.
Definition: dhcpv6.h:225
Record received IPv6 address.
Definition: dhcpv6.c:464
#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:523
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
#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.
uint32_t valid
Valid lifetime (in seconds)
Definition: dhcpv6.h:86
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
uint8_t flags
Flags.
Definition: dhcpv6.c:450
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition: netdevice.h:555
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
An object interface.
Definition: interface.h:109
A long option, as used for getopt_long()
Definition: getopt.h:24
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:272
static struct net_device * netdev
Definition: gdbudp.c:52
void * server_duid
Server DUID, if known.
Definition: dhcpv6.c:513
struct refcnt refcnt
Reference counter.
Definition: dhcpv6.c:496
dhcpv6_session_state_flags
DHCPv6 session state flags.
Definition: dhcpv6.c:456
IP6 address structure.
Definition: in.h:48
#define IN6_IS_ADDR_UNSPECIFIED(addr)
Definition: in.h:59
static struct interface_operation dhcpv6_xfer_op[]
DHCPv6 data transfer interface operations.
Definition: dhcpv6.c:905
static void dhcpv6_free(struct refcnt *refcnt)
Free DHCPv6 session.
Definition: dhcpv6.c:533
static void dhcpv6_timer_expired(struct retry_timer *timer, int fail)
Handle timer expiry.
Definition: dhcpv6.c:739
static __always_inline void off_t userptr_t src
Definition: efi_uaccess.h:66
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:40
static struct dhcpv6_session_state dhcpv6_information_request
DHCPv6 information request state.
Definition: dhcpv6.c:486
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
static int dhcpv6_fetch_lease(struct dhcpv6_settings *dhcpv6set, void *data, size_t len)
Fetch value of DHCPv6 leased address.
Definition: dhcpv6.c:297
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
uint32_t rebind
Rebind time (in seconds)
Definition: dhcpv6.h:69
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:151
#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:348
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition: random.c:30
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:193
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:544
#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:520
#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.
int rc
Current timeout status code.
Definition: dhcpv6.c:525
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:322
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:764
A DHCP header.
Definition: dhcp.h:591
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
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition: interface.h:65
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:358
size_t server_duid_len
Server DUID length.
Definition: dhcpv6.c:515
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
unsigned int index
Index of this network device.
Definition: netdevice.h:356
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:509
struct sockaddr_in6 sin6
Definition: dns.c:71
struct dhcpv6_option header
Option header.
Definition: dhcpv6.h:63
void * data
Start of data.
Definition: iobuf.h:44
struct dhcpv6_duid_uuid client_duid
Client DUID.
Definition: dhcpv6.c:511
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:505
#define DHCPV6_WORD(value)
Construct a word-valued DHCPv6 option.
Definition: dhcpv6.h:216
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 int dhcpv6_register(struct in6_addr *lease, struct dhcpv6_option_list *options, struct settings *parent)
Register DHCPv6 options as network device settings.
Definition: dhcpv6.c:361
static struct interface_descriptor dhcpv6_job_desc
DHCPv6 job control interface descriptor.
Definition: dhcpv6.c:901
IPv6 socket address.
Definition: in.h:115
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:478
int fetch_uuid_setting(struct settings *settings, const struct setting *setting, union uuid *uuid)
Fetch value of UUID setting.
Definition: settings.c:1088
#define DHCPV6_SERVER_PORT
DHCPv6 server port.
Definition: dhcpv6.h:17
#define DHCP_VENDOR_PXECLIENT(arch, ndi)
Vendor class identifier for PXE clients.
Definition: dhcp.h:217
A DHCPv6 session state.
Definition: dhcpv6.c:444
#define DHCPV6_IAADDR
DHCPv6 identity association address (IAADDR) option.
Definition: dhcpv6.h:92
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition: netdevice.h:381
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:173
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:587
#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
Include identity association within request.
Definition: dhcpv6.c:458
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:1124
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:98
#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:468
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:669
const void * data
Data buffer.
Definition: dhcpv6.c:87
String functions.
#define DHCP_ARCH_CLIENT_ARCHITECTURE
Definition: dhcp_arch.h:36
#define htons(value)
Definition: byteswap.h:135
int start_dhcpv6(struct interface *job, struct net_device *netdev, int stateful)
Start DHCPv6.
Definition: dhcpv6.c:921
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:366
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:32
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