iPXE
ndp.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 
20 FILE_LICENCE ( GPL2_OR_LATER );
21 FILE_SECBOOT ( PERMITTED );
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <byteswap.h>
28 #include <ipxe/in.h>
29 #include <ipxe/iobuf.h>
30 #include <ipxe/tcpip.h>
31 #include <ipxe/ipv6.h>
32 #include <ipxe/icmpv6.h>
33 #include <ipxe/neighbour.h>
34 #include <ipxe/dhcpv6.h>
35 #include <ipxe/timer.h>
36 #include <ipxe/ndp.h>
37 
38 /** @file
39  *
40  * IPv6 neighbour discovery protocol
41  *
42  */
43 
44 /** Router discovery minimum timeout */
45 #define IPV6CONF_MIN_TIMEOUT ( TICKS_PER_SEC / 8 )
46 
47 /** Router discovery maximum timeout */
48 #define IPV6CONF_MAX_TIMEOUT ( TICKS_PER_SEC * 3 )
49 
50 /** Router discovery blocked link retry timeout */
51 #define IPV6CONF_BLOCK_TIMEOUT ( TICKS_PER_SEC )
52 
53 /** Router discovery maximum number of deferrals */
54 #define IPV6CONF_MAX_DEFERRALS 180
55 
56 static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev );
57 static int
59  struct in6_addr *router,
61  size_t len );
62 
63 /**
64  * Transmit NDP packet with link-layer address option
65  *
66  * @v netdev Network device
67  * @v sin6_src Source socket address
68  * @v sin6_dest Destination socket address
69  * @v data NDP header
70  * @v len Size of NDP header
71  * @v option_type NDP option type
72  * @ret rc Return status code
73  */
74 static int ndp_tx_ll_addr ( struct net_device *netdev,
75  struct sockaddr_in6 *sin6_src,
76  struct sockaddr_in6 *sin6_dest,
77  const void *data, size_t len,
78  unsigned int option_type ) {
79  struct sockaddr_tcpip *st_src =
80  ( ( struct sockaddr_tcpip * ) sin6_src );
81  struct sockaddr_tcpip *st_dest =
82  ( ( struct sockaddr_tcpip * ) sin6_dest );
84  struct io_buffer *iobuf;
85  struct ndp_ll_addr_option *ll_addr_opt;
86  union ndp_header *ndp;
87  size_t option_len;
88  int rc;
89 
90  /* Allocate and populate buffer */
91  option_len = ( ( sizeof ( *ll_addr_opt ) +
93  ~( NDP_OPTION_BLKSZ - 1 ) );
94  iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len + option_len );
95  if ( ! iobuf )
96  return -ENOMEM;
98  memcpy ( iob_put ( iobuf, len ), data, len );
99  ll_addr_opt = iob_put ( iobuf, option_len );
100  ll_addr_opt->header.type = option_type;
101  ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
102  memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
104  ndp = iobuf->data;
105  ndp->icmp.chksum = tcpip_chksum ( ndp, ( len + option_len ) );
106 
107  /* Transmit packet */
108  if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
109  netdev, &ndp->icmp.chksum ) ) != 0 ) {
110  DBGC ( netdev, "NDP %s could not transmit packet: %s\n",
111  netdev->name, strerror ( rc ) );
112  return rc;
113  }
114 
115  return 0;
116 }
117 
118 /**
119  * Transmit NDP neighbour discovery request
120  *
121  * @v netdev Network device
122  * @v net_protocol Network-layer protocol
123  * @v net_dest Destination network-layer address
124  * @v net_source Source network-layer address
125  * @ret rc Return status code
126  */
127 static int ndp_tx_request ( struct net_device *netdev,
129  const void *net_dest, const void *net_source ) {
130  struct sockaddr_in6 sin6_src;
131  struct sockaddr_in6 sin6_dest;
132  struct ndp_neighbour_header neigh;
133  int rc;
134 
135  /* Construct source address */
136  memset ( &sin6_src, 0, sizeof ( sin6_src ) );
137  sin6_src.sin6_family = AF_INET6;
138  memcpy ( &sin6_src.sin6_addr, net_source,
139  sizeof ( sin6_src.sin6_addr ) );
140 
141  /* Construct multicast destination address */
142  memset ( &sin6_dest, 0, sizeof ( sin6_dest ) );
143  sin6_dest.sin6_family = AF_INET6;
144  sin6_dest.sin6_scope_id = netdev->scope_id;
145  ipv6_solicited_node ( &sin6_dest.sin6_addr, net_dest );
146 
147  /* Construct neighbour header */
148  memset ( &neigh, 0, sizeof ( neigh ) );
150  memcpy ( &neigh.target, net_dest, sizeof ( neigh.target ) );
151 
152  /* Transmit neighbour discovery packet */
153  if ( ( rc = ndp_tx_ll_addr ( netdev, &sin6_src, &sin6_dest, &neigh,
154  sizeof ( neigh ),
155  NDP_OPT_LL_SOURCE ) ) != 0 )
156  return rc;
157 
158  return 0;
159 }
160 
161 /** NDP neighbour discovery protocol */
163  .name = "NDP",
164  .tx_request = ndp_tx_request,
165 };
166 
167 /**
168  * Transmit NDP router solicitation
169  *
170  * @v netdev Network device
171  * @ret rc Return status code
172  */
174  struct ndp_router_solicitation_header rsol;
175  struct sockaddr_in6 sin6_dest;
176  int rc;
177 
178  /* Construct multicast destination address */
179  memset ( &sin6_dest, 0, sizeof ( sin6_dest ) );
180  sin6_dest.sin6_family = AF_INET6;
181  sin6_dest.sin6_scope_id = netdev->scope_id;
182  ipv6_all_routers ( &sin6_dest.sin6_addr );
183 
184  /* Construct router solicitation */
185  memset ( &rsol, 0, sizeof ( rsol ) );
187 
188  /* Transmit packet */
189  if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, &sin6_dest, &rsol,
190  sizeof ( rsol ), NDP_OPT_LL_SOURCE ) ) !=0)
191  return rc;
192 
193  return 0;
194 }
195 
196 /**
197  * Process NDP neighbour solicitation source link-layer address option
198  *
199  * @v netdev Network device
200  * @v sin6_src Source socket address
201  * @v ndp NDP packet
202  * @v option NDP option
203  * @v len NDP option length
204  * @ret rc Return status code
205  */
206 static int
208  struct sockaddr_in6 *sin6_src,
209  union ndp_header *ndp,
210  union ndp_option *option,
211  size_t len ) {
212  struct ndp_neighbour_header *neigh = &ndp->neigh;
213  struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
215  int rc;
216 
217  /* Silently ignore neighbour solicitations for addresses we do
218  * not own.
219  */
220  if ( ! ipv6_has_addr ( netdev, &neigh->target ) )
221  return 0;
222 
223  /* Sanity check */
224  if ( offsetof ( typeof ( *ll_addr_opt ),
225  ll_addr[ll_protocol->ll_addr_len] ) > len ) {
226  DBGC ( netdev, "NDP %s neighbour solicitation link-layer "
227  "address option too short at %zd bytes\n",
228  netdev->name, len );
229  return -EINVAL;
230  }
231 
232  /* Create or update neighbour cache entry */
233  if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
234  &sin6_src->sin6_addr,
235  ll_addr_opt->ll_addr ) ) != 0 ) {
236  DBGC ( netdev, "NDP %s could not define %s => %s: %s\n",
237  netdev->name, inet6_ntoa ( &sin6_src->sin6_addr ),
238  ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
239  strerror ( rc ) );
240  return rc;
241  }
242 
243  /* Convert neighbour header to advertisement */
244  memset ( neigh, 0, offsetof ( typeof ( *neigh ), target ) );
247 
248  /* Send neighbour advertisement */
249  if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, sin6_src, neigh,
250  sizeof ( *neigh ),
251  NDP_OPT_LL_TARGET ) ) != 0 )
252  return rc;
253 
254  return 0;
255 }
256 
257 /**
258  * Process NDP neighbour advertisement target link-layer address option
259  *
260  * @v netdev Network device
261  * @v sin6_src Source socket address
262  * @v ndp NDP packet
263  * @v option NDP option
264  * @v len NDP option length
265  * @ret rc Return status code
266  */
267 static int
269  struct sockaddr_in6 *sin6_src
270  __unused,
271  union ndp_header *ndp,
272  union ndp_option *option,
273  size_t len ) {
274  struct ndp_neighbour_header *neigh = &ndp->neigh;
275  struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
277  int rc;
278 
279  /* Sanity check */
280  if ( offsetof ( typeof ( *ll_addr_opt ),
281  ll_addr[ll_protocol->ll_addr_len] ) > len ) {
282  DBGC ( netdev, "NDP %s neighbour advertisement link-layer "
283  "address option too short at %zd bytes\n",
284  netdev->name, len );
285  return -EINVAL;
286  }
287 
288  /* Update neighbour cache entry, if any */
289  if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target,
290  ll_addr_opt->ll_addr ) ) != 0 ) {
291  DBGC ( netdev, "NDP %s could not update %s => %s: %s\n",
292  netdev->name, inet6_ntoa ( &neigh->target ),
293  ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
294  strerror ( rc ) );
295  return rc;
296  }
297 
298  return 0;
299 }
300 
301 /**
302  * Process NDP router advertisement source link-layer address option
303  *
304  * @v netdev Network device
305  * @v sin6_src Source socket address
306  * @v ndp NDP packet
307  * @v option NDP option
308  * @v len NDP option length
309  * @ret rc Return status code
310  */
311 static int
313  struct sockaddr_in6 *sin6_src,
314  union ndp_header *ndp __unused,
315  union ndp_option *option, size_t len ) {
316  struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
318  int rc;
319 
320  /* Sanity check */
321  if ( offsetof ( typeof ( *ll_addr_opt ),
322  ll_addr[ll_protocol->ll_addr_len] ) > len ) {
323  DBGC ( netdev, "NDP %s router advertisement link-layer address "
324  "option too short at %zd bytes\n", netdev->name, len );
325  return -EINVAL;
326  }
327 
328  /* Define neighbour cache entry */
329  if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
330  &sin6_src->sin6_addr,
331  ll_addr_opt->ll_addr ) ) != 0 ) {
332  DBGC ( netdev, "NDP %s could not define %s => %s: %s\n",
333  netdev->name, inet6_ntoa ( &sin6_src->sin6_addr ),
334  ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
335  strerror ( rc ) );
336  return rc;
337  }
338 
339  return 0;
340 }
341 
342 /**
343  * Process NDP router advertisement prefix information option
344  *
345  * @v netdev Network device
346  * @v sin6_src Source socket address
347  * @v ndp NDP packet
348  * @v option NDP option
349  * @v len NDP option length
350  * @ret rc Return status code
351  */
352 static int
354  struct sockaddr_in6 *sin6_src,
355  union ndp_header *ndp,
356  union ndp_option *option, size_t len ) {
357  struct ndp_router_advertisement_header *radv = &ndp->radv;
358  struct ndp_prefix_information_option *prefix_opt = &option->prefix;
359 
360  /* Sanity check */
361  if ( sizeof ( *prefix_opt ) > len ) {
362  DBGC ( netdev, "NDP %s router advertisement prefix option too "
363  "short at %zd bytes\n", netdev->name, len );
364  return -EINVAL;
365  }
366 
367  DBGC ( netdev, "NDP %s found %sdefault router %s ",
368  netdev->name, ( radv->lifetime ? "" : "non-" ),
369  inet6_ntoa ( &sin6_src->sin6_addr ) );
370  DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d\n",
371  ( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ),
372  ( ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) ? "" : "non-" ),
373  inet6_ntoa ( &prefix_opt->prefix ), prefix_opt->prefix_len );
374 
375  return 0;
376 }
377 
378 /** An NDP option handler */
380  /** ICMPv6 type */
382  /** Option type */
384  /**
385  * Handle received option
386  *
387  * @v netdev Network device
388  * @v sin6_src Source socket address
389  * @v ndp NDP packet
390  * @v option NDP option
391  * @ret rc Return status code
392  */
393  int ( * rx ) ( struct net_device *netdev, struct sockaddr_in6 *sin6_src,
394  union ndp_header *ndp, union ndp_option *option,
395  size_t len );
396 };
397 
398 /** NDP option handlers */
400  {
402  .option_type = NDP_OPT_LL_SOURCE,
404  },
405  {
406  .icmp_type = ICMPV6_NEIGHBOUR_ADVERTISEMENT,
407  .option_type = NDP_OPT_LL_TARGET,
409  },
410  {
411  .icmp_type = ICMPV6_ROUTER_ADVERTISEMENT,
412  .option_type = NDP_OPT_LL_SOURCE,
414  },
415  {
416  .icmp_type = ICMPV6_ROUTER_ADVERTISEMENT,
417  .option_type = NDP_OPT_PREFIX,
419  },
420 };
421 
422 /**
423  * Process received NDP option
424  *
425  * @v netdev Network device
426  * @v sin6_src Source socket address
427  * @v ndp NDP packet
428  * @v option NDP option
429  * @v len Option length
430  * @ret rc Return status code
431  */
432 static int ndp_rx_option ( struct net_device *netdev,
433  struct sockaddr_in6 *sin6_src, union ndp_header *ndp,
434  union ndp_option *option, size_t len ) {
435  struct ndp_option_handler *handler;
436  unsigned int i;
437 
438  /* Locate a suitable option handler, if any */
439  for ( i = 0 ; i < ( sizeof ( ndp_option_handlers ) /
440  sizeof ( ndp_option_handlers[0] ) ) ; i++ ) {
441  handler = &ndp_option_handlers[i];
442  if ( ( handler->icmp_type == ndp->icmp.type ) &&
443  ( handler->option_type == option->header.type ) ) {
444  return handler->rx ( netdev, sin6_src, ndp,
445  option, len );
446  }
447  }
448 
449  /* Silently ignore unknown options as per RFC 4861 */
450  return 0;
451 }
452 
453 /**
454  * Process received NDP packet options
455  *
456  * @v netdev Network device
457  * @v sin6_src Source socket address
458  * @v ndp NDP header
459  * @v offset Offset to NDP options
460  * @v len Length of NDP packet
461  * @ret rc Return status code
462  */
463 static int ndp_rx_options ( struct net_device *netdev,
464  struct sockaddr_in6 *sin6_src,
465  union ndp_header *ndp, size_t offset, size_t len ) {
466  union ndp_option *option;
467  size_t remaining;
468  size_t option_len;
469  int rc;
470 
471  /* Sanity check */
472  if ( len < offset ) {
473  DBGC ( netdev, "NDP %s packet too short at %zd bytes (min %zd "
474  "bytes)\n", netdev->name, len, offset );
475  return -EINVAL;
476  }
477 
478  /* Search for option */
479  option = ( ( ( void * ) ndp ) + offset );
480  remaining = ( len - offset );
481  while ( remaining ) {
482 
483  /* Sanity check */
484  if ( ( remaining < sizeof ( option->header ) ) ||
485  ( option->header.blocks == 0 ) ||
486  ( remaining < ( option->header.blocks *
487  NDP_OPTION_BLKSZ ) ) ) {
488  DBGC ( netdev, "NDP %s bad option length:\n",
489  netdev->name );
490  DBGC_HDA ( netdev, 0, option, remaining );
491  return -EINVAL;
492  }
493  option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
494 
495  /* Handle option */
496  if ( ( rc = ndp_rx_option ( netdev, sin6_src, ndp, option,
497  option_len ) ) != 0 )
498  return rc;
499 
500  /* Move to next option */
501  option = ( ( ( void * ) option ) + option_len );
502  remaining -= option_len;
503  }
504 
505  return 0;
506 }
507 
508 /**
509  * Process received NDP neighbour solicitation or advertisement
510  *
511  * @v iobuf I/O buffer
512  * @v netdev Network device
513  * @v sin6_src Source socket address
514  * @v sin6_dest Destination socket address
515  * @ret rc Return status code
516  */
517 static int ndp_rx_neighbour ( struct io_buffer *iobuf,
518  struct net_device *netdev,
519  struct sockaddr_in6 *sin6_src,
520  struct sockaddr_in6 *sin6_dest __unused ) {
521  union ndp_header *ndp = iobuf->data;
522  struct ndp_neighbour_header *neigh = &ndp->neigh;
523  size_t len = iob_len ( iobuf );
524  int rc;
525 
526  /* Process options */
527  if ( ( rc = ndp_rx_options ( netdev, sin6_src, ndp,
528  offsetof ( typeof ( *neigh ), option ),
529  len ) ) != 0 )
530  goto err_options;
531 
532  err_options:
533  free_iob ( iobuf );
534  return rc;
535 }
536 
537 /**
538  * Process received NDP router advertisement
539  *
540  * @v iobuf I/O buffer
541  * @v netdev Network device
542  * @v sin6_src Source socket address
543  * @v sin6_dest Destination socket address
544  * @ret rc Return status code
545  */
546 static int
548  struct net_device *netdev,
549  struct sockaddr_in6 *sin6_src,
550  struct sockaddr_in6 *sin6_dest __unused ) {
551  union ndp_header *ndp = iobuf->data;
552  struct ndp_router_advertisement_header *radv = &ndp->radv;
553  struct in6_addr *router = &sin6_src->sin6_addr;
554  size_t len = iob_len ( iobuf );
555  int rc;
556 
557  /* Process options */
558  if ( ( rc = ndp_rx_options ( netdev, sin6_src, ndp,
559  offsetof ( typeof ( *radv ), option ),
560  len ) ) != 0 )
561  goto err_options;
562 
563  /* Pass to IPv6 autoconfiguration */
564  if ( ( rc = ipv6conf_rx_router_advertisement ( netdev, router,
565  radv, len ) ) != 0 )
566  goto err_ipv6conf;
567 
568  err_ipv6conf:
569  err_options:
570  free_iob ( iobuf );
571  return rc;
572 }
573 
574 /** NDP ICMPv6 handlers */
575 struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
576  {
578  .rx = ndp_rx_neighbour,
579  },
580  {
582  .rx = ndp_rx_neighbour,
583  },
584  {
587  },
588 };
589 
590 /****************************************************************************
591  *
592  * NDP settings
593  *
594  */
595 
596 /** An NDP prefix settings block */
598  /** Settings interface */
600  /** Name */
601  char name[4];
602  /** Prefix information option */
604 };
605 
606 /** An NDP settings block */
607 struct ndp_settings {
608  /** Reference counter */
609  struct refcnt refcnt;
610  /** Settings interface */
612  /** Router address */
613  struct in6_addr router;
614  /** Router lifetime */
615  unsigned int lifetime;
616  /** Length of NDP options */
617  size_t len;
618  /** NDP options */
619  union ndp_option options[0];
620 };
621 
622 /** NDP settings scope */
623 static const struct settings_scope ndp_settings_scope;
624 
625 /**
626  * Construct NDP tag
627  *
628  * @v type NDP option type
629  * @v offset Starting offset of data
630  * @v len Length of data (or 0 to use all remaining data)
631  * @ret tag NDP tag
632  */
633 #define NDP_TAG( type, offset, len ) \
634  ( ( (len) << 16 ) | ( (offset) << 8 ) | (type) )
635 
636 /**
637  * Extract NDP tag type
638  *
639  * @v tag NDP tag
640  * @ret type NDP option type
641  */
642 #define NDP_TAG_TYPE( tag ) ( ( (tag) >> 0 ) & 0xff )
643 
644 /**
645  * Extract NDP tag offset
646  *
647  * @v tag NDP tag
648  * @ret offset Starting offset of data
649  */
650 #define NDP_TAG_OFFSET( tag ) ( ( (tag) >> 8 ) & 0xff )
651 
652 /**
653  * Extract NDP tag length
654  *
655  * @v tag NDP tag
656  * @ret len Length of data (or 0 to use all remaining data)
657  */
658 #define NDP_TAG_LEN( tag ) ( ( (tag) >> 16 ) & 0xff )
659 
660 /**
661  * Extract NDP tag instance
662  *
663  * @v tag NDP tag
664  * @ret instance Instance
665  */
666 #define NDP_TAG_INSTANCE( tag ) ( ( (tag) >> 24 ) & 0xff )
667 
668 /**
669  * Check applicability of NDP setting
670  *
671  * @v settings Settings block
672  * @v setting Setting to fetch
673  * @ret applies Setting applies within this settings block
674  */
675 static int ndp_applies ( struct settings *settings __unused,
676  const struct setting *setting ) {
677 
678  return ( setting->scope == &ndp_settings_scope );
679 }
680 
681 /**
682  * Fetch value of NDP setting
683  *
684  * @v settings Settings block
685  * @v setting Setting to fetch
686  * @v data Buffer to fill with setting data
687  * @v len Length of buffer
688  * @ret len Length of setting data, or negative error
689  */
690 static int ndp_fetch ( struct settings *settings,
691  struct setting *setting,
692  void *data, size_t len ) {
693  struct ndp_settings *ndpset =
695  struct net_device *netdev =
697  settings.settings );
698  union ndp_option *option;
699  unsigned int tag_type;
700  unsigned int tag_offset;
701  unsigned int tag_len;
702  unsigned int tag_instance;
703  size_t offset;
704  size_t option_len;
705  void *option_data;
706 
707  /* Parse setting tag */
708  tag_type = NDP_TAG_TYPE ( setting->tag );
709  tag_offset = NDP_TAG_OFFSET ( setting->tag );
710  tag_len = NDP_TAG_LEN ( setting->tag );
711  tag_instance = NDP_TAG_INSTANCE ( setting->tag );
712 
713  /* Scan through NDP options for requested type. We can assume
714  * that the options are well-formed, otherwise they would have
715  * been rejected prior to being stored.
716  */
717  for ( offset = 0 ; offset < ndpset->len ; offset += option_len ) {
718 
719  /* Calculate option length */
720  option = ( ( ( void * ) ndpset->options ) + offset );
721  option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
722 
723  /* Skip options that do not match this tag */
724  if ( option->header.type != tag_type )
725  continue;
726 
727  /* Skip previous instances of this option */
728  if ( tag_instance-- != 0 )
729  continue;
730 
731  /* Sanity check */
732  if ( ( tag_offset + tag_len ) > option_len ) {
733  DBGC ( netdev, "NDP %s option %d too short\n",
734  netdev->name, tag_type );
735  return -EINVAL;
736  }
737  if ( ! tag_len )
738  tag_len = ( option_len - tag_offset );
739  option_data = ( ( ( void * ) option ) + tag_offset );
740 
741  /* Copy data to output buffer */
742  if ( len > tag_len )
743  len = tag_len;
744  memcpy ( data, option_data, len );
745 
746  /* Default to hex if no type is specified */
747  if ( ! setting->type )
748  setting->type = &setting_type_hex;
749 
750  return tag_len;
751  }
752 
753  return -ENOENT;
754 }
755 
756 /** NDP settings operations */
758  .applies = ndp_applies,
759  .fetch = ndp_fetch,
760 };
761 
762 /**
763  * Check applicability of NDP per-prefix setting
764  *
765  * @v settings Settings block
766  * @v setting Setting to fetch
767  * @ret applies Setting applies within this settings block
768  */
770  const struct setting *setting ) {
771 
772  return ( setting->scope == &ipv6_settings_scope );
773 }
774 
775 /**
776  * Fetch value of NDP IPv6 address setting
777  *
778  * @v settings Settings block
779  * @v data Buffer to fill with setting data
780  * @v len Length of buffer
781  * @ret len Length of setting data, or negative error
782  */
783 static int ndp_prefix_fetch_ip6 ( struct settings *settings, void *data,
784  size_t len ) {
785  struct ndp_prefix_settings *prefset =
787  struct ndp_settings *ndpset =
789  struct net_device *netdev =
790  container_of ( ndpset->settings.parent, struct net_device,
791  settings.settings );
792  struct ndp_prefix_information_option *prefix = prefset->prefix;
793  struct in6_addr *ip6 = &prefix->prefix;
794  struct in6_addr slaac;
795  int prefix_len;
796  int rc;
797 
798  /* Skip dead prefixes */
799  if ( ! prefix->valid )
800  return -ENOENT;
801 
802  /* Construct IPv6 address via SLAAC, if applicable */
803  if ( prefix->flags & NDP_PREFIX_AUTONOMOUS ) {
804  memcpy ( &slaac, ip6, sizeof ( slaac ) );
805  prefix_len = ipv6_eui64 ( &slaac, netdev );
806  if ( prefix_len == prefix->prefix_len ) {
807  /* Correctly configured prefix: use SLAAC address */
808  ip6 = &slaac;
809  } else if ( prefix_len < 0 ) {
810  /* Link layer does not support SLAAC */
811  rc = prefix_len;
812  DBGC ( netdev, "NDP %s does not support SLAAC: %s\n",
813  netdev->name, strerror ( rc ) );
814  } else {
815  /* Prefix length incorrect: assume a badly
816  * configured router and ignore SLAAC address.
817  */
818  DBGC ( netdev, "NDP %s ignoring misconfigured SLAAC "
819  "on prefix %s/%d\n", netdev->name,
820  inet6_ntoa ( ip6 ), prefix->prefix_len );
821  }
822  }
823 
824  /* Fill in IPv6 address */
825  if ( len > sizeof ( *ip6 ) )
826  len = sizeof ( *ip6 );
827  memcpy ( data, ip6, len );
828 
829  return sizeof ( *ip6 );
830 }
831 
832 /**
833  * Fetch value of NDP prefix length setting
834  *
835  * @v settings Settings block
836  * @v data Buffer to fill with setting data
837  * @v len Length of buffer
838  * @ret len Length of setting data, or negative error
839  */
840 static int ndp_prefix_fetch_len6 ( struct settings *settings, void *data,
841  size_t len ) {
842  struct ndp_prefix_settings *prefset =
844  struct ndp_prefix_information_option *prefix = prefset->prefix;
845  uint8_t *len6;
846 
847  /* Fill in prefix length */
848  if ( len >= sizeof ( *len6 ) ) {
849  /* We treat an off-link prefix as having a prefix
850  * length covering the entire IPv6 address.
851  */
852  len6 = data;
853  *len6 = ( ( prefix->flags & NDP_PREFIX_ON_LINK ) ?
854  prefix->prefix_len : -1UL );
855  }
856 
857  return sizeof ( *len6 );
858 }
859 
860 /**
861  * Fetch value of NDP router address setting
862  *
863  * @v settings Settings block
864  * @v data Buffer to fill with setting data
865  * @v len Length of buffer
866  * @ret len Length of setting data, or negative error
867  */
869  void *data, size_t len ) {
870  struct ndp_settings *ndpset =
872 
873  /* Treat non-routing router as non-existent */
874  if ( ! ndpset->lifetime )
875  return -ENOENT;
876 
877  /* Fill in router address */
878  if ( len > sizeof ( ndpset->router ) )
879  len = sizeof ( ndpset->router );
880  memcpy ( data, &ndpset->router, len );
881 
882  return sizeof ( ndpset->router );
883 }
884 
885 /** An NDP per-prefix setting operation */
887  /** Generic setting */
888  const struct setting *setting;
889  /**
890  * Fetch value of setting
891  *
892  * @v settings Settings block
893  * @v data Buffer to fill with setting data
894  * @v len Length of buffer
895  * @ret len Length of setting data, or negative error
896  */
897  int ( * fetch ) ( struct settings *settings, void *data, size_t len );
898 };
899 
900 /** NDP per-prefix settings operations */
902  { &ip6_setting, ndp_prefix_fetch_ip6 },
903  { &len6_setting, ndp_prefix_fetch_len6 },
904  { &gateway6_setting, ndp_prefix_fetch_gateway6 },
905 };
906 
907 /**
908  * Fetch value of NDP pre-prefix setting
909  *
910  * @v settings Settings block
911  * @v setting Setting to fetch
912  * @v data Buffer to fill with setting data
913  * @v len Length of buffer
914  * @ret len Length of setting data, or negative error
915  */
916 static int ndp_prefix_fetch ( struct settings *settings,
917  struct setting *setting,
918  void *data, size_t len ) {
919  struct ndp_prefix_operation *op;
920  unsigned int i;
921 
922  /* Handle per-prefix settings */
923  for ( i = 0 ; i < ( sizeof ( ndp_prefix_operations ) /
924  sizeof ( ndp_prefix_operations[0] ) ) ; i++ ) {
926  if ( setting_cmp ( setting, op->setting ) == 0 )
927  return op->fetch ( settings, data, len );
928  }
929 
930  return -ENOENT;
931 }
932 
933 /** NDP per-prefix settings operations */
936  .fetch = ndp_prefix_fetch,
937 };
938 
939 /**
940  * Register NDP settings
941  *
942  * @v netdev Network device
943  * @v router Router address
944  * @v lifetime Router lifetime
945  * @v options NDP options
946  * @v len Length of options
947  * @ret rc Return status code
948  */
950  struct in6_addr *router,
951  unsigned int lifetime,
952  union ndp_option *options, size_t len ) {
953  struct settings *parent = netdev_settings ( netdev );
954  union ndp_option *option;
955  struct ndp_settings *ndpset;
956  struct ndp_prefix_settings *prefset;
957  size_t offset;
958  size_t option_len;
959  unsigned int prefixes;
960  unsigned int instance;
961  int order;
962  int rc;
963 
964  /* Count number of prefix options. We can assume that the
965  * options are well-formed, otherwise they would have been
966  * rejected prior to being stored.
967  */
968  order = IPV6_ORDER_PREFIX_ONLY;
969  for ( prefixes = 0, offset = 0 ; offset < len ; offset += option_len ) {
970 
971  /* Skip non-prefix options */
972  option = ( ( ( void * ) options ) + offset );
973  option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
974  if ( option->header.type != NDP_OPT_PREFIX )
975  continue;
976 
977  /* Count number of prefixes */
978  prefixes++;
979 
980  /* Increase overall order if we have SLAAC addresses */
981  if ( option->prefix.flags & NDP_PREFIX_AUTONOMOUS )
982  order = IPV6_ORDER_SLAAC;
983  }
984 
985  /* Allocate and initialise structure */
986  ndpset = zalloc ( sizeof ( *ndpset ) + len +
987  ( prefixes * sizeof ( *prefset ) ) );
988  if ( ! ndpset ) {
989  rc = -ENOMEM;
990  goto err_alloc;
991  }
992  ref_init ( &ndpset->refcnt, NULL );
994  &ndpset->refcnt, &ndp_settings_scope );
995  ndpset->settings.order = order;
996  memcpy ( &ndpset->router, router, sizeof ( ndpset->router ) );
997  ndpset->lifetime = lifetime;
998  ndpset->len = len;
999  memcpy ( ndpset->options, options, len );
1000  prefset = ( ( ( void * ) ndpset->options ) + len );
1001 
1002  /* Register settings */
1003  if ( ( rc = register_settings ( &ndpset->settings, parent,
1004  NDP_SETTINGS_NAME ) ) != 0 )
1005  goto err_register;
1006 
1007  /* Construct and register per-prefix settings */
1008  for ( instance = 0, offset = 0 ; offset < len ; offset += option_len ) {
1009 
1010  /* Skip non-prefix options */
1011  option = ( ( ( void * ) ndpset->options ) + offset );
1012  option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
1013  if ( option->header.type != NDP_OPT_PREFIX )
1014  continue;
1015 
1016  /* Initialise structure */
1017  settings_init ( &prefset->settings,
1019  &ndpset->refcnt, &ndp_settings_scope );
1020  prefset->settings.order =
1021  ( ( option->prefix.flags & NDP_PREFIX_AUTONOMOUS ) ?
1023  prefset->prefix = &option->prefix;
1024  snprintf ( prefset->name, sizeof ( prefset->name ), "%d",
1025  instance++ );
1026 
1027  /* Register settings */
1028  if ( ( rc = register_settings ( &prefset->settings,
1029  &ndpset->settings,
1030  prefset->name ) ) != 0 )
1031  goto err_register_prefix;
1032 
1033  /* Move to next per-prefix settings */
1034  prefset++;
1035  }
1036  assert ( instance == prefixes );
1037 
1038  ref_put ( &ndpset->refcnt );
1039  return 0;
1040 
1041  err_register_prefix:
1042  unregister_settings ( &ndpset->settings );
1043  err_register:
1044  ref_put ( &ndpset->refcnt );
1045  err_alloc:
1046  return rc;
1047 }
1048 
1049 /** DNS server setting */
1050 const struct setting ndp_dns6_setting __setting ( SETTING_IP6_EXTRA, dns6 ) = {
1051  .name = "dns6",
1052  .description = "DNS server",
1053  .tag = NDP_TAG ( NDP_OPT_RDNSS,
1054  offsetof ( struct ndp_rdnss_option, addresses ), 0 ),
1055  .type = &setting_type_ipv6,
1056  .scope = &ndp_settings_scope,
1057 };
1058 
1059 /** DNS search list setting */
1060 const struct setting ndp_dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
1061  .name = "dnssl",
1062  .description = "DNS search list",
1063  .tag = NDP_TAG ( NDP_OPT_DNSSL,
1064  offsetof ( struct ndp_dnssl_option, names ), 0 ),
1065  .type = &setting_type_dnssl,
1066  .scope = &ndp_settings_scope,
1067 };
1068 
1069 /****************************************************************************
1070  *
1071  * IPv6 autoconfiguration
1072  *
1073  */
1074 
1075 /** An IPv6 configurator */
1076 struct ipv6conf {
1077  /** Reference count */
1078  struct refcnt refcnt;
1079  /** List of configurators */
1080  struct list_head list;
1081 
1082  /** Job control interface */
1083  struct interface job;
1084  /** DHCPv6 interface */
1085  struct interface dhcp;
1086 
1087  /** Network device being configured */
1089 
1090  /** Retransmission timer */
1092 
1093  /** Deferred discovery counter */
1094  unsigned int deferred;
1095 };
1096 
1097 /** List of IPv6 configurators */
1098 static LIST_HEAD ( ipv6confs );
1099 
1100 /**
1101  * Free IPv6 configurator
1102  *
1103  * @v refcnt Reference count
1104  */
1105 static void ipv6conf_free ( struct refcnt *refcnt ) {
1106  struct ipv6conf *ipv6conf =
1107  container_of ( refcnt, struct ipv6conf, refcnt );
1108 
1109  netdev_put ( ipv6conf->netdev );
1110  free ( ipv6conf );
1111 }
1112 
1113 /**
1114  * Identify IPv6 configurator by network device
1115  *
1116  * @v netdev Network device
1117  * @ret ipv6 IPv6 configurator, or NULL
1118  */
1119 static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev ) {
1120  struct ipv6conf *ipv6conf;
1121 
1122  list_for_each_entry ( ipv6conf, &ipv6confs, list ) {
1123  if ( ipv6conf->netdev == netdev )
1124  return ipv6conf;
1125  }
1126  return NULL;
1127 }
1128 
1129 /**
1130  * Finish IPv6 autoconfiguration
1131  *
1132  * @v ipv6 IPv6 configurator
1133  * @v rc Reason for finishing
1134  */
1135 static void ipv6conf_done ( struct ipv6conf *ipv6conf, int rc ) {
1136 
1137  /* Shut down interfaces */
1138  intf_shutdown ( &ipv6conf->job, rc );
1139  intf_shutdown ( &ipv6conf->dhcp, rc );
1140 
1141  /* Stop timer */
1142  stop_timer ( &ipv6conf->timer );
1143 
1144  /* Remove from list and drop list's reference */
1145  list_del ( &ipv6conf->list );
1146  ref_put ( &ipv6conf->refcnt );
1147 }
1148 
1149 /**
1150  * Handle IPv6 configurator timer expiry
1151  *
1152  * @v timer Retry timer
1153  * @v fail Failure indicator
1154  */
1155 static void ipv6conf_expired ( struct retry_timer *timer, int fail ) {
1156  struct ipv6conf *ipv6conf =
1157  container_of ( timer, struct ipv6conf, timer );
1158  struct net_device *netdev = ipv6conf->netdev;
1159 
1160  /* If we have failed, terminate autoconfiguration */
1161  if ( fail ) {
1163  return;
1164  }
1165 
1166  /* Otherwise, transmit router solicitation and restart timer */
1167  start_timer ( &ipv6conf->timer );
1169 
1170  /* If link is blocked, defer router discovery timeout */
1171  if ( netdev_link_blocked ( netdev ) &&
1173  DBGC ( netdev, "NDP %s deferring discovery timeout\n",
1174  netdev->name );
1176  }
1177 }
1178 
1179 /**
1180  * Handle router advertisement during IPv6 autoconfiguration
1181  *
1182  * @v netdev Network device
1183  * @v router Router address
1184  * @v radv Router advertisement
1185  * @v len Length of router advertisement
1186  * @ret rc Return status code
1187  *
1188  * This function assumes that the router advertisement is well-formed,
1189  * since it must have already passed through option processing.
1190  */
1191 static int
1193  struct in6_addr *router,
1194  struct ndp_router_advertisement_header *radv,
1195  size_t len ) {
1196  struct ipv6conf *ipv6conf;
1197  size_t option_len;
1198  int stateful;
1199  int rc;
1200 
1201  /* Identify IPv6 configurator, if any */
1203 
1204  /* Do nothing unless IPv6 autoconfiguration is in progress */
1205  if ( ! ipv6conf )
1206  return 0;
1207 
1208  /* If this is not the first solicited router advertisement, ignore it */
1209  if ( ! timer_running ( &ipv6conf->timer ) )
1210  return 0;
1211 
1212  /* Stop router solicitation timer */
1213  stop_timer ( &ipv6conf->timer );
1214 
1215  /* Register NDP settings */
1216  option_len = ( len - offsetof ( typeof ( *radv ), option ) );
1217  if ( ( rc = ndp_register_settings ( netdev, router,
1218  ntohl ( radv->lifetime ),
1219  radv->option, option_len ) ) != 0 )
1220  return rc;
1221 
1222  /* Start DHCPv6 if required */
1223  if ( radv->flags & ( NDP_ROUTER_MANAGED | NDP_ROUTER_OTHER ) ) {
1224  stateful = ( radv->flags & NDP_ROUTER_MANAGED );
1225  if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev, router,
1226  stateful ) ) != 0 ) {
1227  DBGC ( netdev, "NDP %s could not start state%s DHCPv6: "
1228  "%s\n", netdev->name,
1229  ( stateful ? "ful" : "less" ), strerror ( rc ) );
1230  ipv6conf_done ( ipv6conf, rc );
1231  return rc;
1232  }
1233  return 0;
1234  }
1235 
1236  /* Otherwise, terminate autoconfiguration */
1237  ipv6conf_done ( ipv6conf, 0 );
1238 
1239  return 0;
1240 }
1241 
1242 /** IPv6 configurator job interface operations */
1244  INTF_OP ( intf_close, struct ipv6conf *, ipv6conf_done ),
1245 };
1246 
1247 /** IPv6 configurator job interface descriptor */
1249  INTF_DESC ( struct ipv6conf, job, ipv6conf_job_op );
1250 
1251 /** IPv6 configurator DHCPv6 interface operations */
1253  INTF_OP ( intf_close, struct ipv6conf *, ipv6conf_done ),
1254 };
1255 
1256 /** IPv6 configurator DHCPv6 interface descriptor */
1258  INTF_DESC ( struct ipv6conf, dhcp, ipv6conf_dhcp_op );
1259 
1260 /**
1261  * Start IPv6 autoconfiguration
1262  *
1263  * @v job Job control interface
1264  * @v netdev Network device
1265  * @ret rc Return status code
1266  */
1267 int start_ipv6conf ( struct interface *job, struct net_device *netdev ) {
1268  struct ipv6conf *ipv6conf;
1269 
1270  /* Allocate and initialise structure */
1271  ipv6conf = zalloc ( sizeof ( *ipv6conf ) );
1272  if ( ! ipv6conf )
1273  return -ENOMEM;
1277  timer_init ( &ipv6conf->timer, ipv6conf_expired, &ipv6conf->refcnt );
1278  set_timer_limits ( &ipv6conf->timer, IPV6CONF_MIN_TIMEOUT,
1281 
1282  /* Start timer to initiate router solicitation */
1284 
1285  /* Attach parent interface, transfer reference to list, and return */
1286  intf_plug_plug ( &ipv6conf->job, job );
1287  list_add ( &ipv6conf->list, &ipv6confs );
1288  return 0;
1289 }
1290 
1291 /** IPv6 network device configurator */
1293  .name = "ipv6",
1294  .start = start_ipv6conf,
1295 };
#define NDP_OPT_RDNSS
NDP recursive DNS server option.
Definition: ndp.h:72
#define EINVAL
Invalid argument.
Definition: errno.h:429
static int ipv6conf_rx_router_advertisement(struct net_device *netdev, struct in6_addr *router, struct ndp_router_advertisement_header *radv, size_t len)
Handle router advertisement during IPv6 autoconfiguration.
Definition: ndp.c:1192
An object interface operation.
Definition: interface.h:18
#define SETTING_IP_EXTRA
IPv4 additional settings.
Definition: settings.h:71
TCP/IP socket address.
Definition: tcpip.h:76
static int ndp_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of NDP setting.
Definition: ndp.c:675
#define NDP_OPT_PREFIX
NDP prefix information option.
Definition: ndp.h:45
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
const char * name
Name.
Definition: netdevice.h:316
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition: interface.c:250
static int ndp_prefix_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of NDP per-prefix setting.
Definition: ndp.c:769
uint8_t blocks
Length (in blocks of 8 bytes)
Definition: ndp.h:24
static int ndp_tx_router_solicitation(struct net_device *netdev)
Transmit NDP router solicitation.
Definition: ndp.c:173
#define iob_put(iobuf, len)
Definition: iobuf.h:125
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition: interface.c:279
#define NDP_SETTINGS_NAME
NDP settings block name.
Definition: ndp.h:203
#define AF_INET6
IPv6 Internet addresses.
Definition: socket.h:65
const char * name
Name.
Definition: neighbour.h:22
uint8_t flags
Flags.
Definition: ndp.h:54
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition: retry.h:100
uint8_t ll_addr_len
Link-layer address length.
Definition: netdevice.h:199
uint8_t type
Type.
Definition: ndp.h:22
#define ICMPV6_NEIGHBOUR_SOLICITATION
ICMPv6 neighbour solicitation.
Definition: icmpv6.h:69
static int ndp_prefix_fetch_gateway6(struct settings *settings, void *data, size_t len)
Fetch value of NDP router address setting.
Definition: ndp.c:868
unsigned int lifetime
Router lifetime.
Definition: ndp.c:615
static int ndp_rx_neighbour_solicitation_ll_source(struct net_device *netdev, struct sockaddr_in6 *sin6_src, union ndp_header *ndp, union ndp_option *option, size_t len)
Process NDP neighbour solicitation source link-layer address option.
Definition: ndp.c:207
#define NDP_TAG_INSTANCE(tag)
Extract NDP tag instance.
Definition: ndp.c:666
static void ipv6conf_expired(struct retry_timer *timer, int fail)
Handle IPv6 configurator timer expiry.
Definition: ndp.c:1155
void unregister_settings(struct settings *settings)
Unregister settings block.
Definition: settings.c:515
static int ndp_prefix_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of NDP pre-prefix setting.
Definition: ndp.c:916
char * inet6_ntoa(const struct in6_addr *in)
Convert IPv6 address to standard notation.
Definition: ipv6.c:895
#define list_add(new, head)
Add a new entry to the head of a list.
Definition: list.h:70
int(* fetch)(struct settings *settings, void *data, size_t len)
Fetch value of setting.
Definition: ndp.c:897
uint8_t ll_addr[0]
Link-layer address.
Definition: ndp.h:41
struct in6_addr target
Target address.
Definition: ndp.h:124
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:65
Error codes.
struct settings * parent
Parent settings block.
Definition: settings.h:139
An NDP per-prefix setting operation.
Definition: ndp.c:886
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
static struct settings_operations ndp_settings_operations
NDP settings operations.
Definition: ndp.c:757
struct refcnt refcnt
Reference count.
Definition: ndp.c:1078
NDP recursive DNS server.
Definition: ndp.h:75
struct icmp_header icmp
ICMPv6 header.
Definition: ndp.h:175
static void ipv6_solicited_node(struct in6_addr *addr, const struct in6_addr *unicast)
Construct solicited-node multicast address.
Definition: ipv6.h:249
struct interface dhcp
DHCPv6 interface.
Definition: ndp.c:1085
uint16_t chksum
Checksum.
Definition: icmp.h:26
#define NDP_TAG(type, offset, len)
Construct NDP tag.
Definition: ndp.c:633
static struct interface_operation ipv6conf_job_op[]
IPv6 configurator job interface operations.
Definition: ndp.c:1243
static const struct settings_scope ndp_settings_scope
NDP settings scope.
Definition: ndp.c:623
static int ndp_rx_option(struct net_device *netdev, struct sockaddr_in6 *sin6_src, union ndp_header *ndp, union ndp_option *option, size_t len)
Process received NDP option.
Definition: ndp.c:432
#define DBGC(...)
Definition: compiler.h:505
struct icmp_header icmp
ICMPv6 header.
Definition: ndp.h:165
int(* rx)(struct net_device *netdev, struct sockaddr_in6 *sin6_src, union ndp_header *ndp, union ndp_option *option, size_t len)
Handle received option.
Definition: ndp.c:393
static int ndp_tx_request(struct net_device *netdev, struct net_protocol *net_protocol __unused, const void *net_dest, const void *net_source)
Transmit NDP neighbour discovery request.
Definition: ndp.c:127
A retry timer.
Definition: retry.h:22
A neighbour discovery protocol.
Definition: neighbour.h:20
#define ENOENT
No such file or directory.
Definition: errno.h:515
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition: interface.c:108
#define ntohl(value)
Definition: byteswap.h:135
char prefix[4]
Definition: vmconsole.c:53
uint16_t sin6_scope_id
Scope ID (part of struct sockaddr_tcpip)
Definition: in.h:133
iPXE timers
#define NDP_OPT_LL_TARGET
NDP target link-layer address option.
Definition: ndp.h:34
#define offsetof(type, field)
Get offset of a field within a structure.
Definition: stddef.h:25
static int ndp_rx_neighbour_advertisement_ll_target(struct net_device *netdev, struct sockaddr_in6 *sin6_src __unused, union ndp_header *ndp, union ndp_option *option, size_t len)
Process NDP neighbour advertisement target link-layer address option.
Definition: ndp.c:268
static void ipv6conf_free(struct refcnt *refcnt)
Free IPv6 configurator.
Definition: ndp.c:1105
struct neighbour_discovery ndp_discovery
NDP neighbour discovery protocol.
Definition: ndp.c:162
static int netdev_link_blocked(struct net_device *netdev)
Check link block state of network device.
Definition: netdevice.h:651
#define NDP_ROUTER_MANAGED
NDP managed address configuration.
Definition: ndp.h:157
uint8_t icmp_type
ICMPv6 type.
Definition: ndp.c:381
int neighbour_update(struct net_device *netdev, struct net_protocol *net_protocol, const void *net_dest, const void *ll_dest)
Update existing neighbour cache entry.
Definition: neighbour.c:441
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition: iobuf.c:131
uint8_t type
Type.
Definition: icmp.h:22
unsigned int scope_id
Scope ID.
Definition: netdevice.h:361
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:587
A link-layer protocol.
Definition: netdevice.h:115
NDP DNS search list.
Definition: ndp.h:90
static void settings_init(struct settings *settings, struct settings_operations *op, struct refcnt *refcnt, const struct settings_scope *default_scope)
Initialise a settings block.
Definition: settings.h:503
FILE_SECBOOT(PERMITTED)
A doubly-linked list entry (or list head)
Definition: list.h:19
NDP source or target link-layer address option.
Definition: ndp.h:37
A reference counter.
Definition: refcnt.h:27
A timer.
Definition: timer.h:29
static int ndp_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch value of NDP setting.
Definition: ndp.c:690
const char * name
Name.
Definition: settings.h:29
#define NDP_NEIGHBOUR_SOLICITED
NDP solicited flag.
Definition: ndp.h:133
static int ndp_rx_router_advertisement(struct io_buffer *iobuf, struct net_device *netdev, struct sockaddr_in6 *sin6_src, struct sockaddr_in6 *sin6_dest __unused)
Process received NDP router advertisement.
Definition: ndp.c:547
#define NDP_TAG_LEN(tag)
Extract NDP tag length.
Definition: ndp.c:658
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:44
#define list_del(list)
Delete an entry from a list.
Definition: list.h:120
struct ndp_option_header header
NDP option header.
Definition: ndp.h:39
static struct settings_operations ndp_prefix_settings_operations
NDP per-prefix settings operations.
Definition: ndp.c:934
#define ENOMEM
Not enough space.
Definition: errno.h:535
int start_dhcpv6(struct interface *job, struct net_device *netdev, struct in6_addr *router, int stateful)
Start DHCPv6.
Definition: dhcpv6.c:1000
void * memcpy(void *dest, const void *src, size_t len) __nonnull
An IPv6 configurator.
Definition: ndp.c:1076
struct ndp_router_advertisement_header radv
Router advertisement header.
Definition: ndp.h:181
struct net_device_configurator ipv6_configurator __net_device_configurator
IPv6 network device configurator.
Definition: ndp.c:1292
FILE_LICENCE(GPL2_OR_LATER)
static void ipv6_all_routers(struct in6_addr *addr)
Construct all-routers multicast address.
Definition: ipv6.h:263
#define MAX_LL_NET_HEADER_LEN
Maximum combined length of a link-layer and network-layer header.
Definition: netdevice.h:59
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition: netdevice.h:576
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
static void ipv6conf_done(struct ipv6conf *ipv6conf, int rc)
Finish IPv6 autoconfiguration.
Definition: ndp.c:1135
An object interface.
Definition: interface.h:125
A long option, as used for getopt_long()
Definition: getopt.h:25
static int options
Definition: 3c515.c:286
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition: list.h:432
size_t len
Length of NDP options.
Definition: ndp.c:617
#define DBGC_HDA(...)
Definition: compiler.h:506
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
ring len
Length.
Definition: dwmac.h:231
int neighbour_define(struct net_device *netdev, struct net_protocol *net_protocol, const void *net_dest, const void *ll_dest)
Define neighbour cache entry.
Definition: neighbour.c:466
NDP prefix information.
Definition: ndp.h:48
static struct net_device * netdev
Definition: gdbudp.c:52
Transport-network layer interface.
Address assigned via SLAAC.
Definition: ipv6.h:287
const struct setting_type * type
Setting type.
Definition: settings.h:37
struct list_head list
List of configurators.
Definition: ndp.c:1080
IP6 address structure.
Definition: in.h:51
#define IPV6CONF_MAX_TIMEOUT
Router discovery maximum timeout.
Definition: ndp.c:48
#define NDP_OPT_LL_SOURCE
NDP source link-layer address option.
Definition: ndp.h:31
struct refcnt refcnt
Reference counter.
Definition: ndp.c:609
struct net_device * netdev
Network device being configured.
Definition: ndp.c:1088
struct icmp_header icmp
ICMPv6 header.
Definition: ndp.h:118
An object interface descriptor.
Definition: interface.h:56
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
struct interface job
Job control interface.
Definition: ndp.c:1083
#define NDP_TAG_TYPE(tag)
Extract NDP tag type.
Definition: ndp.c:642
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
#define NDP_OPT_DNSSL
NDP DNS search list option.
Definition: ndp.h:87
#define NDP_PREFIX_ON_LINK
NDP on-link flag.
Definition: ndp.h:66
static int ndp_rx_options(struct net_device *netdev, struct sockaddr_in6 *sin6_src, union ndp_header *ndp, size_t offset, size_t len)
Process received NDP packet options.
Definition: ndp.c:463
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
static struct interface_operation ipv6conf_dhcp_op[]
IPv6 configurator DHCPv6 interface operations.
Definition: ndp.c:1252
const struct setting * setting
Generic setting.
Definition: ndp.c:888
#define NDP_NEIGHBOUR_OVERRIDE
NDP override flag.
Definition: ndp.h:136
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition: interface.h:33
static int ndp_prefix_fetch_len6(struct settings *settings, void *data, size_t len)
Fetch value of NDP prefix length setting.
Definition: ndp.c:840
A network device.
Definition: netdevice.h:353
struct ndp_prefix_information_option * prefix
Prefix information option.
Definition: ndp.c:603
Settings block operations.
Definition: settings.h:86
static struct ipv6conf * ipv6conf_demux(struct net_device *netdev)
Identify IPv6 configurator by network device.
Definition: ndp.c:1119
A settings block.
Definition: settings.h:133
unsigned char uint8_t
Definition: stdint.h:10
A setting scope.
Definition: settings.h:177
static struct net_device * netdev_get(struct net_device *netdev)
Get reference to network device.
Definition: netdevice.h:565
struct retry_timer timer
Retransmission timer.
Definition: ndp.c:1091
unsigned int type
Type.
Definition: icmpv6.h:22
uint8_t option_type
Option type.
Definition: ndp.c:383
u32 lifetime
For Lifetime-type KDEs, the lifetime in seconds.
Definition: wpa.h:54
An NDP settings block.
Definition: ndp.c:607
char name[4]
Name.
Definition: ndp.c:601
#define ICMPV6_ROUTER_SOLICITATION
ICMPv6 router solicitation.
Definition: icmpv6.h:63
An NDP prefix settings block.
Definition: ndp.c:597
An NDP router advertisement header.
Definition: ndp.h:139
IPv6 protocol.
uint8_t prefix_len
Prefix length.
Definition: ndp.h:52
#define ICMPV6_ROUTER_ADVERTISEMENT
ICMPv6 router advertisement.
Definition: icmpv6.h:66
static int ndp_rx_neighbour(struct io_buffer *iobuf, struct net_device *netdev, struct sockaddr_in6 *sin6_src, struct sockaddr_in6 *sin6_dest __unused)
Process received NDP neighbour solicitation or advertisement.
Definition: ndp.c:517
A setting.
Definition: settings.h:24
An NDP neighbour solicitation or advertisement header.
Definition: ndp.h:116
#define IPV6CONF_BLOCK_TIMEOUT
Router discovery blocked link retry timeout.
Definition: ndp.c:51
void start_timer(struct retry_timer *timer)
Start timer.
Definition: retry.c:94
A network-layer protocol.
Definition: netdevice.h:65
An NDP option handler.
Definition: ndp.c:379
static struct ndp_option_handler ndp_option_handlers[]
NDP option handlers.
Definition: ndp.c:399
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition: retry.c:65
struct icmpv6_handler ndp_handlers [] __icmpv6_handler
NDP ICMPv6 handlers.
Definition: ndp.c:575
#define IPV6CONF_MIN_TIMEOUT
Router discovery minimum timeout.
Definition: ndp.c:45
An NDP header.
Definition: ndp.h:173
struct in6_addr router
Router address.
Definition: ndp.c:613
static int ndp_rx_router_advertisement_ll_source(struct net_device *netdev, struct sockaddr_in6 *sin6_src, union ndp_header *ndp __unused, union ndp_option *option, size_t len)
Process NDP router advertisement source link-layer address option.
Definition: ndp.c:312
#define iob_reserve(iobuf, len)
Definition: iobuf.h:72
static uint16_t struct vmbus_xfer_pages_operations * op
Definition: netvsc.h:327
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition: interface.h:81
int order
Sibling ordering.
Definition: settings.h:149
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition: retry.c:118
union ndp_option options[0]
NDP options.
Definition: ndp.c:619
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:363
static struct ndp_prefix_operation ndp_prefix_operations[]
NDP per-prefix settings operations.
Definition: ndp.c:901
ICMPv6 protocol.
#define ICMPV6_NEIGHBOUR_ADVERTISEMENT
ICMPv6 neighbour advertisement.
Definition: icmpv6.h:72
struct settings settings
Settings interface.
Definition: ndp.c:611
#define NDP_TAG_OFFSET(tag)
Extract NDP tag offset.
Definition: ndp.c:650
An ICMPv6 handler.
Definition: icmpv6.h:20
static struct interface_descriptor ipv6conf_job_desc
IPv6 configurator job interface descriptor.
Definition: ndp.c:1248
static int ndp_register_settings(struct net_device *netdev, struct in6_addr *router, unsigned int lifetime, union ndp_option *options, size_t len)
Register NDP settings.
Definition: ndp.c:949
#define SETTING_IP6_EXTRA
IPv6 additional settings.
Definition: settings.h:69
Neighbour discovery.
static int ndp_prefix_fetch_ip6(struct settings *settings, void *data, size_t len)
Fetch value of NDP IPv6 address setting.
Definition: ndp.c:783
#define NDP_PREFIX_AUTONOMOUS
NDP autonomous address configuration flag.
Definition: ndp.h:69
No address.
Definition: ipv6.h:283
void * data
Start of data.
Definition: iobuf.h:53
An NDP router solicitation header.
Definition: ndp.h:163
A network device configurator.
Definition: netdevice.h:314
int start_ipv6conf(struct interface *job, struct net_device *netdev)
Start IPv6 autoconfiguration.
Definition: ndp.c:1267
uint8_t data[48]
Additional event data.
Definition: ena.h:22
int ipv6_has_addr(struct net_device *netdev, struct in6_addr *addr)
Check if network device has a specific IPv6 address.
Definition: ipv6.c:142
static int ipv6_eui64(struct in6_addr *addr, struct net_device *netdev)
Construct local IPv6 address via EUI-64.
Definition: ipv6.h:217
union ndp_option option[0]
Options.
Definition: ndp.h:153
const char *(* ntoa)(const void *ll_addr)
Transcribe link-layer address.
Definition: netdevice.h:164
Neighbour discovery protocol.
static LIST_HEAD(ipv6confs)
List of IPv6 configurators.
IPv6 socket address.
Definition: in.h:118
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:383
unsigned int deferred
Deferred discovery counter.
Definition: ndp.c:1094
uint8_t flags
Flags.
Definition: ndp.h:120
int(* applies)(struct settings *settings, const struct setting *setting)
Check applicability of setting.
Definition: settings.h:99
struct in6_addr prefix
Prefix.
Definition: ndp.h:62
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition: settings.c:476
An NDP option.
Definition: ndp.h:102
sa_family_t sin6_family
Socket address family (part of struct sockaddr)
Definition: in.h:123
static int ndp_rx_router_advertisement_prefix(struct net_device *netdev, struct sockaddr_in6 *sin6_src, union ndp_header *ndp, union ndp_option *option, size_t len)
Process NDP router advertisement prefix information option.
Definition: ndp.c:353
#define IPV6CONF_MAX_DEFERRALS
Router discovery maximum number of deferrals.
Definition: ndp.c:54
static int ndp_tx_ll_addr(struct net_device *netdev, struct sockaddr_in6 *sin6_src, struct sockaddr_in6 *sin6_dest, const void *data, size_t len, unsigned int option_type)
Transmit NDP packet with link-layer address option.
Definition: ndp.c:74
static struct interface_descriptor ipv6conf_dhcp_desc
IPv6 configurator DHCPv6 interface descriptor.
Definition: ndp.c:1257
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:48
const struct settings_scope ipv6_settings_scope
IPv6 settings scope.
Definition: ipv6.c:1121
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition: netdevice.h:388
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
const struct setting ndp_dns6_setting __setting(SETTING_IP6_EXTRA, dns6)
DNS server setting.
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition: interface.h:204
struct ndp_neighbour_header neigh
Neighbour solicitation or advertisement header.
Definition: ndp.h:177
const struct settings_scope * scope
Setting scope (or NULL)
Definition: settings.h:50
int tcpip_tx(struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum)
Transmit a TCP/IP packet.
Definition: tcpip.c:92
uint16_t tcpip_chksum(const void *data, size_t len)
Calculate TCP/IP checkum.
Definition: tcpip.c:204
#define NDP_OPTION_BLKSZ
NDP option block size.
Definition: ndp.h:28
int setting_cmp(const struct setting *a, const struct setting *b)
Compare two settings.
Definition: settings.c:1121
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
#define ETIMEDOUT
Connection timed out.
Definition: errno.h:670
String functions.
struct settings settings
Settings interface.
Definition: ndp.c:599
uint16_t lifetime
Router lifetime.
Definition: ndp.h:147
#define NDP_ROUTER_OTHER
NDP other configuration.
Definition: ndp.h:160
struct in6_addr sin6_addr
IPv6 address.
Definition: in.h:135
struct ll_protocol * ll_protocol
Link-layer protocol.
Definition: netdevice.h:373
static struct dns_server dns6
IPv6 DNS server list.
Definition: dns.c:86
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:107
Dynamic Host Configuration Protocol for IPv6.
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:38