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