iPXE
ipv6.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 <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <strings.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <byteswap.h>
31 #include <ipxe/iobuf.h>
32 #include <ipxe/tcpip.h>
33 #include <ipxe/if_ether.h>
34 #include <ipxe/crc32.h>
35 #include <ipxe/fragment.h>
36 #include <ipxe/ipstat.h>
37 #include <ipxe/ndp.h>
38 #include <ipxe/ipv6.h>
39 
40 /** @file
41  *
42  * IPv6 protocol
43  *
44  */
45 
46 /* Disambiguate the various error causes */
47 #define EINVAL_LEN __einfo_error ( EINFO_EINVAL_LEN )
48 #define EINFO_EINVAL_LEN \
49  __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid length" )
50 #define ENOTSUP_VER __einfo_error ( EINFO_ENOTSUP_VER )
51 #define EINFO_ENOTSUP_VER \
52  __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported version" )
53 #define ENOTSUP_HDR __einfo_error ( EINFO_ENOTSUP_HDR )
54 #define EINFO_ENOTSUP_HDR \
55  __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported header type" )
56 #define ENOTSUP_OPT __einfo_error ( EINFO_ENOTSUP_OPT )
57 #define EINFO_ENOTSUP_OPT \
58  __einfo_uniqify ( EINFO_ENOTSUP, 0x03, "Unsupported option" )
59 
60 /** List of IPv6 miniroutes */
62 
63 /** IPv6 statistics */
64 static struct ip_statistics ipv6_stats;
65 
66 /** IPv6 statistics family */
68 ipv6_statistics_family __ip_statistics_family ( IP_STATISTICS_IPV6 ) = {
69  .version = 6,
70  .stats = &ipv6_stats,
71 };
72 
73 /**
74  * Determine debugging colour for IPv6 debug messages
75  *
76  * @v in IPv6 address
77  * @ret col Debugging colour (for DBGC())
78  */
79 static uint32_t ipv6col ( struct in6_addr *in ) {
80  return crc32_le ( 0, in, sizeof ( *in ) );
81 }
82 
83 /**
84  * Determine IPv6 address scope
85  *
86  * @v addr IPv6 address
87  * @ret scope Address scope
88  */
89 static unsigned int ipv6_scope ( const struct in6_addr *addr ) {
90 
91  /* Multicast addresses directly include a scope field */
92  if ( IN6_IS_ADDR_MULTICAST ( addr ) )
93  return ipv6_multicast_scope ( addr );
94 
95  /* Link-local addresses have link-local scope */
96  if ( IN6_IS_ADDR_LINKLOCAL ( addr ) )
97  return IPV6_SCOPE_LINK_LOCAL;
98 
99  /* Site-local addresses have site-local scope */
100  if ( IN6_IS_ADDR_SITELOCAL ( addr ) )
101  return IPV6_SCOPE_SITE_LOCAL;
102 
103  /* Unique local addresses do not directly map to a defined
104  * scope. They effectively have a scope which is wider than
105  * link-local but narrower than global. Since the only
106  * multicast packets that we transmit are link-local, we can
107  * simply choose an arbitrary scope between link-local and
108  * global.
109  */
110  if ( IN6_IS_ADDR_ULA ( addr ) )
112 
113  /* All other addresses are assumed to be global */
114  return IPV6_SCOPE_GLOBAL;
115 }
116 
117 /**
118  * Dump IPv6 routing table entry
119  *
120  * @v miniroute Routing table entry
121  */
122 static inline __attribute__ (( always_inline )) void
123 ipv6_dump_miniroute ( struct ipv6_miniroute *miniroute ) {
124  struct net_device *netdev = miniroute->netdev;
125 
126  DBGC ( netdev, "IPv6 %s has %s %s/%d", netdev->name,
127  ( ( miniroute->flags & IPV6_HAS_ADDRESS ) ?
128  "address" : "prefix" ),
129  inet6_ntoa ( &miniroute->address ), miniroute->prefix_len );
130  if ( miniroute->flags & IPV6_HAS_ROUTER )
131  DBGC ( netdev, " router %s", inet6_ntoa ( &miniroute->router ));
132  DBGC ( netdev, "\n" );
133 }
134 
135 /**
136  * Check if network device has a specific IPv6 address
137  *
138  * @v netdev Network device
139  * @v addr IPv6 address
140  * @ret has_addr Network device has this IPv6 address
141  */
142 int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ) {
143  struct ipv6_miniroute *miniroute;
144 
145  list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
146  if ( ( miniroute->netdev == netdev ) &&
147  ( miniroute->flags & IPV6_HAS_ADDRESS ) &&
148  ( memcmp ( &miniroute->address, addr,
149  sizeof ( miniroute->address ) ) == 0 ) ) {
150  /* Found matching address */
151  return 1;
152  }
153  }
154  return 0;
155 }
156 
157 /**
158  * Count matching bits of an IPv6 routing table entry prefix
159  *
160  * @v miniroute Routing table entry
161  * @v address IPv6 address
162  * @ret match_len Number of matching prefix bits
163  */
164 static unsigned int ipv6_match_len ( struct ipv6_miniroute *miniroute,
165  struct in6_addr *address ) {
166  unsigned int match_len = 0;
167  unsigned int i;
168  uint32_t diff;
169 
170  for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
171  sizeof ( address->s6_addr32[0] ) ) ; i++ ) {
172 
173  diff = ntohl ( ~( ( ~( address->s6_addr32[i] ^
174  miniroute->address.s6_addr32[i] ) )
175  & miniroute->prefix_mask.s6_addr32[i] ) );
176  match_len += 32;
177  if ( diff ) {
178  match_len -= flsl ( diff );
179  break;
180  }
181  }
182 
183  return match_len;
184 }
185 
186 /**
187  * Find IPv6 routing table entry for a given address
188  *
189  * @v netdev Network device
190  * @v address IPv6 address
191  * @ret miniroute Routing table entry, or NULL if not found
192  */
193 static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev,
194  struct in6_addr *address ) {
195  struct ipv6_miniroute *miniroute;
196  unsigned int match_len;
197 
198  list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
199  if ( miniroute->netdev != netdev )
200  continue;
201  match_len = ipv6_match_len ( miniroute, address );
202  if ( match_len < miniroute->prefix_len )
203  continue;
204  return miniroute;
205  }
206  return NULL;
207 }
208 
209 /**
210  * Add IPv6 routing table entry
211  *
212  * @v netdev Network device
213  * @v address IPv6 address (or prefix)
214  * @v prefix_len Prefix length
215  * @v router Router address (if any)
216  * @ret rc Return status code
217  */
219  unsigned int prefix_len, struct in6_addr *router ) {
220  struct ipv6_miniroute *miniroute;
222  unsigned int remaining;
223  unsigned int i;
224 
225  /* Find or create routing table entry */
226  miniroute = ipv6_miniroute ( netdev, address );
227  if ( miniroute ) {
228 
229  /* Remove from existing position in routing table */
230  list_del ( &miniroute->list );
231 
232  } else {
233 
234  /* Create new routing table entry */
235  miniroute = zalloc ( sizeof ( *miniroute ) );
236  if ( ! miniroute )
237  return -ENOMEM;
238  miniroute->netdev = netdev_get ( netdev );
239  memcpy ( &miniroute->address, address,
240  sizeof ( miniroute->address ) );
241 
242  /* Default to prefix length of 64 if none specified */
243  if ( ! prefix_len )
245  miniroute->prefix_len = prefix_len;
247 
248  /* Construct prefix mask */
249  remaining = prefix_len;
250  for ( prefix_mask = miniroute->prefix_mask.s6_addr ;
251  remaining >= 8 ; prefix_mask++, remaining -= 8 ) {
252  *prefix_mask = 0xff;
253  }
254  if ( remaining )
255  *prefix_mask = ( 0xff << ( 8 - remaining ) );
256  }
257 
258  /* Add to start of routing table */
259  list_add ( &miniroute->list, &ipv6_miniroutes );
260 
261  /* Set or update address, if applicable */
262  for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
263  sizeof ( address->s6_addr32[0] ) ) ; i++ ) {
264  if ( ( address->s6_addr32[i] &
265  ~miniroute->prefix_mask.s6_addr32[i] ) != 0 ) {
266  memcpy ( &miniroute->address, address,
267  sizeof ( miniroute->address ) );
268  miniroute->flags |= IPV6_HAS_ADDRESS;
269  }
270  }
271  if ( miniroute->prefix_len == IPV6_MAX_PREFIX_LEN )
272  miniroute->flags |= IPV6_HAS_ADDRESS;
273 
274  /* Update scope */
275  miniroute->scope = ipv6_scope ( &miniroute->address );
276 
277  /* Set or update router, if applicable */
278  if ( router ) {
279  memcpy ( &miniroute->router, router,
280  sizeof ( miniroute->router ) );
281  miniroute->flags |= IPV6_HAS_ROUTER;
282  }
283 
284  ipv6_dump_miniroute ( miniroute );
285  return 0;
286 }
287 
288 /**
289  * Delete IPv6 minirouting table entry
290  *
291  * @v miniroute Routing table entry
292  */
293 void ipv6_del_miniroute ( struct ipv6_miniroute *miniroute ) {
294 
295  netdev_put ( miniroute->netdev );
296  list_del ( &miniroute->list );
297  free ( miniroute );
298 }
299 
300 /**
301  * Perform IPv6 routing
302  *
303  * @v scope_id Destination address scope ID (for link-local addresses)
304  * @v dest Final destination address
305  * @ret dest Next hop destination address
306  * @ret miniroute Routing table entry to use, or NULL if no route
307  */
308 struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
309  struct in6_addr **dest ) {
310  struct ipv6_miniroute *miniroute;
311  struct ipv6_miniroute *chosen = NULL;
312  unsigned int best = 0;
313  unsigned int match_len;
314  unsigned int score;
315  unsigned int scope;
316 
317  /* Calculate destination address scope */
318  scope = ipv6_scope ( *dest );
319 
320  /* Find first usable route in routing table */
321  list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
322 
323  /* Skip closed network devices */
324  if ( ! netdev_is_open ( miniroute->netdev ) )
325  continue;
326 
327  /* Skip entries with no usable source address */
328  if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) )
329  continue;
330 
331  /* Skip entries with a non-matching scope ID, if
332  * destination specifies a scope ID.
333  */
334  if ( scope_id && ( miniroute->netdev->scope_id != scope_id ) )
335  continue;
336 
337  /* Skip entries that are out of scope */
338  if ( miniroute->scope < scope )
339  continue;
340 
341  /* Calculate match length */
342  match_len = ipv6_match_len ( miniroute, *dest );
343 
344  /* If destination is on-link, then use this route */
345  if ( match_len >= miniroute->prefix_len )
346  return miniroute;
347 
348  /* If destination is unicast, then skip off-link
349  * entries with no router.
350  */
351  if ( ! ( IN6_IS_ADDR_MULTICAST ( *dest ) ||
352  ( miniroute->flags & IPV6_HAS_ROUTER ) ) )
353  continue;
354 
355  /* Choose best route, defined as being the route with
356  * the smallest viable scope. If two routes both have
357  * the same scope, then prefer the route with the
358  * longest match length.
359  */
360  score = ( ( ( IPV6_SCOPE_MAX + 1 - miniroute->scope ) << 8 )
361  + match_len );
362  if ( score > best ) {
363  chosen = miniroute;
364  best = score;
365  }
366  }
367 
368  /* Return chosen route, if any */
369  if ( chosen ) {
370  if ( ! IN6_IS_ADDR_MULTICAST ( *dest ) )
371  *dest = &chosen->router;
372  return chosen;
373  }
374 
375  return NULL;
376 }
377 
378 /**
379  * Determine transmitting network device
380  *
381  * @v st_dest Destination network-layer address
382  * @ret netdev Transmitting network device, or NULL
383  */
384 static struct net_device * ipv6_netdev ( struct sockaddr_tcpip *st_dest ) {
385  struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
386  struct in6_addr *dest = &sin6_dest->sin6_addr;
387  struct ipv6_miniroute *miniroute;
388 
389  /* Find routing table entry */
390  miniroute = ipv6_route ( sin6_dest->sin6_scope_id, &dest );
391  if ( ! miniroute )
392  return NULL;
393 
394  return miniroute->netdev;
395 }
396 
397 /**
398  * Check that received options can be safely ignored
399  *
400  * @v iphdr IPv6 header
401  * @v options Options extension header
402  * @v len Maximum length of header
403  * @ret rc Return status code
404  */
405 static int ipv6_check_options ( struct ipv6_header *iphdr,
407  size_t len ) {
408  struct ipv6_option *option = options->options;
409  struct ipv6_option *end = ( ( ( void * ) options ) + len );
410 
411  while ( option < end ) {
412  if ( ! IPV6_CAN_IGNORE_OPT ( option->type ) ) {
413  DBGC ( ipv6col ( &iphdr->src ), "IPv6 unrecognised "
414  "option type %#02x:\n", option->type );
415  DBGC_HDA ( ipv6col ( &iphdr->src ), 0,
416  options, len );
417  return -ENOTSUP_OPT;
418  }
419  if ( option->type == IPV6_OPT_PAD1 ) {
420  option = ( ( ( void * ) option ) + 1 );
421  } else {
422  option = ( ( ( void * ) option->value ) + option->len );
423  }
424  }
425  return 0;
426 }
427 
428 /**
429  * Check if fragment matches fragment reassembly buffer
430  *
431  * @v fragment Fragment reassembly buffer
432  * @v iobuf I/O buffer
433  * @v hdrlen Length of non-fragmentable potion of I/O buffer
434  * @ret is_fragment Fragment matches this reassembly buffer
435  */
436 static int ipv6_is_fragment ( struct fragment *fragment,
437  struct io_buffer *iobuf, size_t hdrlen ) {
438  struct ipv6_header *frag_iphdr = fragment->iobuf->data;
439  struct ipv6_fragment_header *frag_fhdr =
441  sizeof ( *frag_fhdr ) );
442  struct ipv6_header *iphdr = iobuf->data;
443  struct ipv6_fragment_header *fhdr =
444  ( iobuf->data + hdrlen - sizeof ( *fhdr ) );
445 
446  return ( ( memcmp ( &iphdr->src, &frag_iphdr->src,
447  sizeof ( iphdr->src ) ) == 0 ) &&
448  ( fhdr->ident == frag_fhdr->ident ) );
449 }
450 
451 /**
452  * Get fragment offset
453  *
454  * @v iobuf I/O buffer
455  * @v hdrlen Length of non-fragmentable potion of I/O buffer
456  * @ret offset Offset
457  */
458 static size_t ipv6_fragment_offset ( struct io_buffer *iobuf, size_t hdrlen ) {
459  struct ipv6_fragment_header *fhdr =
460  ( iobuf->data + hdrlen - sizeof ( *fhdr ) );
461 
462  return ( ntohs ( fhdr->offset_more ) & IPV6_MASK_OFFSET );
463 }
464 
465 /**
466  * Check if more fragments exist
467  *
468  * @v iobuf I/O buffer
469  * @v hdrlen Length of non-fragmentable potion of I/O buffer
470  * @ret more_frags More fragments exist
471  */
472 static int ipv6_more_fragments ( struct io_buffer *iobuf, size_t hdrlen ) {
473  struct ipv6_fragment_header *fhdr =
474  ( iobuf->data + hdrlen - sizeof ( *fhdr ) );
475 
476  return ( fhdr->offset_more & htons ( IPV6_MASK_MOREFRAGS ) );
477 }
478 
479 /** Fragment reassembler */
482  .is_fragment = ipv6_is_fragment,
483  .fragment_offset = ipv6_fragment_offset,
484  .more_fragments = ipv6_more_fragments,
485  .stats = &ipv6_stats,
486 };
487 
488 /**
489  * Calculate IPv6 pseudo-header checksum
490  *
491  * @v iphdr IPv6 header
492  * @v len Payload length
493  * @v next_header Next header type
494  * @v csum Existing checksum
495  * @ret csum Updated checksum
496  */
497 static uint16_t ipv6_pshdr_chksum ( struct ipv6_header *iphdr, size_t len,
498  int next_header, uint16_t csum ) {
499  struct ipv6_pseudo_header pshdr;
500 
501  /* Build pseudo-header */
502  memcpy ( &pshdr.src, &iphdr->src, sizeof ( pshdr.src ) );
503  memcpy ( &pshdr.dest, &iphdr->dest, sizeof ( pshdr.dest ) );
504  pshdr.len = htonl ( len );
505  memset ( pshdr.zero, 0, sizeof ( pshdr.zero ) );
506  pshdr.next_header = next_header;
507 
508  /* Update the checksum value */
509  return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
510 }
511 
512 /**
513  * Transmit IPv6 packet
514  *
515  * @v iobuf I/O buffer
516  * @v tcpip Transport-layer protocol
517  * @v st_src Source network-layer address
518  * @v st_dest Destination network-layer address
519  * @v netdev Network device to use if no route found, or NULL
520  * @v trans_csum Transport-layer checksum to complete, or NULL
521  * @ret rc Status
522  *
523  * This function expects a transport-layer segment and prepends the
524  * IPv6 header
525  */
526 static int ipv6_tx ( struct io_buffer *iobuf,
528  struct sockaddr_tcpip *st_src,
529  struct sockaddr_tcpip *st_dest,
530  struct net_device *netdev,
531  uint16_t *trans_csum ) {
532  struct sockaddr_in6 *sin6_src = ( ( struct sockaddr_in6 * ) st_src );
533  struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
534  struct ipv6_miniroute *miniroute;
535  struct ipv6_header *iphdr;
536  struct in6_addr *src = NULL;
537  struct in6_addr *next_hop;
538  uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
539  const void *ll_dest;
540  size_t len;
541  int rc;
542 
543  /* Update statistics */
545 
546  /* Fill up the IPv6 header, except source address */
547  len = iob_len ( iobuf );
548  iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
549  memset ( iphdr, 0, sizeof ( *iphdr ) );
550  iphdr->ver_tc_label = htonl ( IPV6_VER );
551  iphdr->len = htons ( len );
552  iphdr->next_header = tcpip_protocol->tcpip_proto;
553  iphdr->hop_limit = IPV6_HOP_LIMIT;
554  memcpy ( &iphdr->dest, &sin6_dest->sin6_addr, sizeof ( iphdr->dest ) );
555 
556  /* Use routing table to identify next hop and transmitting netdev */
557  next_hop = &iphdr->dest;
558  if ( ( miniroute = ipv6_route ( sin6_dest->sin6_scope_id,
559  &next_hop ) ) != NULL ) {
560  src = &miniroute->address;
561  netdev = miniroute->netdev;
562  }
563  if ( ! netdev ) {
564  DBGC ( ipv6col ( &iphdr->dest ), "IPv6 has no route to %s\n",
565  inet6_ntoa ( &iphdr->dest ) );
567  rc = -ENETUNREACH;
568  goto err;
569  }
570  if ( sin6_src && ! IN6_IS_ADDR_UNSPECIFIED ( &sin6_src->sin6_addr ) )
571  src = &sin6_src->sin6_addr;
572  if ( src )
573  memcpy ( &iphdr->src, src, sizeof ( iphdr->src ) );
574 
575  /* Fix up checksums */
576  if ( trans_csum ) {
577  *trans_csum = ipv6_pshdr_chksum ( iphdr, len,
579  *trans_csum );
580  if ( ! *trans_csum )
581  *trans_csum = tcpip_protocol->zero_csum;
582  }
583 
584  /* Print IPv6 header for debugging */
585  DBGC2 ( ipv6col ( &iphdr->dest ), "IPv6 TX %s->",
586  inet6_ntoa ( &iphdr->src ) );
587  DBGC2 ( ipv6col ( &iphdr->dest ), "%s len %zd next %d\n",
588  inet6_ntoa ( &iphdr->dest ), len, iphdr->next_header );
589 
590  /* Calculate link-layer destination address, if possible */
591  if ( IN6_IS_ADDR_MULTICAST ( next_hop ) ) {
592  /* Multicast address */
594  if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET6, next_hop,
595  ll_dest_buf ) ) !=0){
596  DBGC ( ipv6col ( &iphdr->dest ), "IPv6 could not hash "
597  "multicast %s: %s\n", inet6_ntoa ( next_hop ),
598  strerror ( rc ) );
599  goto err;
600  }
601  ll_dest = ll_dest_buf;
602  } else {
603  /* Unicast address */
604  ll_dest = NULL;
605  }
606 
607  /* Update statistics */
609  ipv6_stats.out_octets += iob_len ( iobuf );
610 
611  /* Hand off to link layer (via NDP if applicable) */
612  if ( ll_dest ) {
613  if ( ( rc = net_tx ( iobuf, netdev, &ipv6_protocol, ll_dest,
614  netdev->ll_addr ) ) != 0 ) {
615  DBGC ( ipv6col ( &iphdr->dest ), "IPv6 could not "
616  "transmit packet via %s: %s\n",
617  netdev->name, strerror ( rc ) );
618  return rc;
619  }
620  } else {
621  if ( ( rc = ndp_tx ( iobuf, netdev, next_hop,
622  &iphdr->src ) ) != 0 ) {
623  DBGC ( ipv6col ( &iphdr->dest ), "IPv6 could not "
624  "transmit packet via %s: %s\n",
625  netdev->name, strerror ( rc ) );
626  return rc;
627  }
628  }
629 
630  return 0;
631 
632  err:
633  free_iob ( iobuf );
634  return rc;
635 }
636 
637 /**
638  * Process incoming IPv6 packets
639  *
640  * @v iobuf I/O buffer
641  * @v netdev Network device
642  * @v ll_dest Link-layer destination address
643  * @v ll_source Link-layer destination source
644  * @v flags Packet flags
645  * @ret rc Return status code
646  *
647  * This function expects an IPv6 network datagram. It processes the
648  * headers and sends it to the transport layer.
649  */
650 static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
651  const void *ll_dest __unused,
652  const void *ll_source __unused,
653  unsigned int flags __unused ) {
654  struct ipv6_header *iphdr = iobuf->data;
655  union ipv6_extension_header *ext;
656  union {
657  struct sockaddr_in6 sin6;
658  struct sockaddr_tcpip st;
659  } src, dest;
660  uint16_t pshdr_csum;
661  size_t len;
662  size_t hdrlen;
663  size_t extlen;
664  int this_header;
665  int next_header;
666  int rc;
667 
668  /* Update statistics */
670  ipv6_stats.in_octets += iob_len ( iobuf );
671  if ( flags & LL_BROADCAST ) {
673  } else if ( flags & LL_MULTICAST ) {
675  }
676 
677  /* Sanity check the IPv6 header */
678  if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
679  DBGC ( ipv6col ( &iphdr->src ), "IPv6 packet too short at %zd "
680  "bytes (min %zd bytes)\n", iob_len ( iobuf ),
681  sizeof ( *iphdr ) );
682  rc = -EINVAL_LEN;
683  goto err_header;
684  }
685  if ( ( iphdr->ver_tc_label & htonl ( IPV6_MASK_VER ) ) !=
686  htonl ( IPV6_VER ) ) {
687  DBGC ( ipv6col ( &iphdr->src ), "IPv6 version %#08x not "
688  "supported\n", ntohl ( iphdr->ver_tc_label ) );
689  rc = -ENOTSUP_VER;
690  goto err_header;
691  }
692 
693  /* Truncate packet to specified length */
694  len = ntohs ( iphdr->len );
695  if ( len > iob_len ( iobuf ) ) {
696  DBGC ( ipv6col ( &iphdr->src ), "IPv6 length too long at %zd "
697  "bytes (packet is %zd bytes)\n", len, iob_len ( iobuf ));
699  rc = -EINVAL_LEN;
700  goto err_other;
701  }
702  iob_unput ( iobuf, ( iob_len ( iobuf ) - len - sizeof ( *iphdr ) ) );
703  hdrlen = sizeof ( *iphdr );
704 
705  /* Print IPv6 header for debugging */
706  DBGC2 ( ipv6col ( &iphdr->src ), "IPv6 RX %s<-",
707  inet6_ntoa ( &iphdr->dest ) );
708  DBGC2 ( ipv6col ( &iphdr->src ), "%s len %zd next %d\n",
709  inet6_ntoa ( &iphdr->src ), len, iphdr->next_header );
710 
711  /* Discard unicast packets not destined for us */
712  if ( ( ! ( flags & LL_MULTICAST ) ) &&
713  ( ! ipv6_has_addr ( netdev, &iphdr->dest ) ) ) {
714  DBGC ( ipv6col ( &iphdr->src ), "IPv6 discarding non-local "
715  "unicast packet for %s\n", inet6_ntoa ( &iphdr->dest ) );
717  rc = -EPIPE;
718  goto err_other;
719  }
720 
721  /* Process any extension headers */
722  next_header = iphdr->next_header;
723  while ( 1 ) {
724 
725  /* Extract extension header */
726  this_header = next_header;
727  ext = ( iobuf->data + hdrlen );
728  extlen = sizeof ( ext->pad );
729  if ( iob_len ( iobuf ) < ( hdrlen + extlen ) ) {
730  DBGC ( ipv6col ( &iphdr->src ), "IPv6 too short for "
731  "extension header type %d at %zd bytes (min "
732  "%zd bytes)\n", this_header,
733  ( iob_len ( iobuf ) - hdrlen ), extlen );
734  rc = -EINVAL_LEN;
735  goto err_header;
736  }
737 
738  /* Determine size of extension header (if applicable) */
739  if ( ( this_header == IPV6_HOPBYHOP ) ||
740  ( this_header == IPV6_DESTINATION ) ||
741  ( this_header == IPV6_ROUTING ) ) {
742  /* Length field is present */
743  extlen += ext->common.len;
744  } else if ( this_header == IPV6_FRAGMENT ) {
745  /* Length field is reserved and ignored (RFC2460) */
746  } else {
747  /* Not an extension header; assume rest is payload */
748  break;
749  }
750  if ( iob_len ( iobuf ) < ( hdrlen + extlen ) ) {
751  DBGC ( ipv6col ( &iphdr->src ), "IPv6 too short for "
752  "extension header type %d at %zd bytes (min "
753  "%zd bytes)\n", this_header,
754  ( iob_len ( iobuf ) - hdrlen ), extlen );
755  rc = -EINVAL_LEN;
756  goto err_header;
757  }
758  hdrlen += extlen;
759  next_header = ext->common.next_header;
760  DBGC2 ( ipv6col ( &iphdr->src ), "IPv6 RX %s<-",
761  inet6_ntoa ( &iphdr->dest ) );
762  DBGC2 ( ipv6col ( &iphdr->src ), "%s ext type %d len %zd next "
763  "%d\n", inet6_ntoa ( &iphdr->src ), this_header,
764  extlen, next_header );
765 
766  /* Process this extension header */
767  if ( ( this_header == IPV6_HOPBYHOP ) ||
768  ( this_header == IPV6_DESTINATION ) ) {
769 
770  /* Check that all options can be ignored */
771  if ( ( rc = ipv6_check_options ( iphdr, &ext->options,
772  extlen ) ) != 0 )
773  goto err_header;
774 
775  } else if ( this_header == IPV6_FRAGMENT ) {
776 
777  /* Reassemble fragments */
778  iobuf = fragment_reassemble ( &ipv6_reassembler, iobuf,
779  &hdrlen );
780  if ( ! iobuf )
781  return 0;
782  iphdr = iobuf->data;
783  }
784  }
785 
786  /* Construct socket address, calculate pseudo-header checksum,
787  * and hand off to transport layer
788  */
789  memset ( &src, 0, sizeof ( src ) );
790  src.sin6.sin6_family = AF_INET6;
791  memcpy ( &src.sin6.sin6_addr, &iphdr->src,
792  sizeof ( src.sin6.sin6_addr ) );
793  src.sin6.sin6_scope_id = netdev->scope_id;
794  memset ( &dest, 0, sizeof ( dest ) );
795  dest.sin6.sin6_family = AF_INET6;
796  memcpy ( &dest.sin6.sin6_addr, &iphdr->dest,
797  sizeof ( dest.sin6.sin6_addr ) );
798  dest.sin6.sin6_scope_id = netdev->scope_id;
799  iob_pull ( iobuf, hdrlen );
800  pshdr_csum = ipv6_pshdr_chksum ( iphdr, iob_len ( iobuf ),
801  next_header, TCPIP_EMPTY_CSUM );
802  if ( ( rc = tcpip_rx ( iobuf, netdev, next_header, &src.st, &dest.st,
803  pshdr_csum, &ipv6_stats ) ) != 0 ) {
804  DBGC ( ipv6col ( &src.sin6.sin6_addr ), "IPv6 received packet "
805  "rejected by stack: %s\n", strerror ( rc ) );
806  return rc;
807  }
808 
809  return 0;
810 
811  err_header:
813  err_other:
814  free_iob ( iobuf );
815  return rc;
816 }
817 
818 /**
819  * Parse IPv6 address
820  *
821  * @v string IPv6 address string
822  * @ret in IPv6 address to fill in
823  * @ret rc Return status code
824  */
825 int inet6_aton ( const char *string, struct in6_addr *in ) {
826  uint16_t *word = in->s6_addr16;
827  uint16_t *end = ( word + ( sizeof ( in->s6_addr16 ) /
828  sizeof ( in->s6_addr16[0] ) ) );
829  uint16_t *pad = NULL;
830  const char *nptr = string;
831  char *endptr;
832  unsigned long value;
833  size_t pad_len;
834  size_t move_len;
835 
836  /* Parse string */
837  while ( 1 ) {
838 
839  /* Parse current word */
840  value = strtoul ( nptr, &endptr, 16 );
841  if ( value > 0xffff ) {
842  DBG ( "IPv6 invalid word value %#lx in \"%s\"\n",
843  value, string );
844  return -EINVAL;
845  }
846  *(word++) = htons ( value );
847 
848  /* Parse separator */
849  if ( ! *endptr )
850  break;
851  if ( *endptr != ':' ) {
852  DBG ( "IPv6 invalid separator '%c' in \"%s\"\n",
853  *endptr, string );
854  return -EINVAL;
855  }
856  if ( ( endptr == nptr ) && ( nptr != string ) ) {
857  if ( pad ) {
858  DBG ( "IPv6 invalid multiple \"::\" in "
859  "\"%s\"\n", string );
860  return -EINVAL;
861  }
862  pad = word;
863  }
864  nptr = ( endptr + 1 );
865 
866  /* Check for overrun */
867  if ( word == end ) {
868  DBG ( "IPv6 too many words in \"%s\"\n", string );
869  return -EINVAL;
870  }
871  }
872 
873  /* Insert padding if specified */
874  if ( pad ) {
875  move_len = ( ( ( void * ) word ) - ( ( void * ) pad ) );
876  pad_len = ( ( ( void * ) end ) - ( ( void * ) word ) );
877  memmove ( ( ( ( void * ) pad ) + pad_len ), pad, move_len );
878  memset ( pad, 0, pad_len );
879  } else if ( word != end ) {
880  DBG ( "IPv6 underlength address \"%s\"\n", string );
881  return -EINVAL;
882  }
883 
884  return 0;
885 }
886 
887 /**
888  * Convert IPv6 address to standard notation
889  *
890  * @v in IPv6 address
891  * @ret string IPv6 address string in canonical format
892  *
893  * RFC5952 defines the canonical format for IPv6 textual representation.
894  */
895 char * inet6_ntoa ( const struct in6_addr *in ) {
896  static char buf[41]; /* ":xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" */
897  char *out = buf;
898  char *longest_start = NULL;
899  char *start = NULL;
900  int longest_len = 1;
901  int len = 0;
902  char *dest;
903  unsigned int i;
904  uint16_t value;
905 
906  /* Format address, keeping track of longest run of zeros */
907  for ( i = 0 ; i < ( sizeof ( in->s6_addr16 ) /
908  sizeof ( in->s6_addr16[0] ) ) ; i++ ) {
909  value = ntohs ( in->s6_addr16[i] );
910  if ( value == 0 ) {
911  if ( len++ == 0 )
912  start = out;
913  if ( len > longest_len ) {
914  longest_start = start;
915  longest_len = len;
916  }
917  } else {
918  len = 0;
919  }
920  out += sprintf ( out, ":%x", value );
921  }
922 
923  /* Abbreviate longest run of zeros, if applicable */
924  if ( longest_start ) {
925  dest = strcpy ( ( longest_start + 1 ),
926  ( longest_start + ( 2 * longest_len ) ) );
927  if ( dest[0] == '\0' )
928  dest[1] = '\0';
929  dest[0] = ':';
930  }
931  return ( ( longest_start == buf ) ? buf : ( buf + 1 ) );
932 }
933 
934 /**
935  * Transcribe IPv6 address
936  *
937  * @v net_addr IPv6 address
938  * @ret string IPv6 address in standard notation
939  *
940  */
941 static const char * ipv6_ntoa ( const void *net_addr ) {
942  return inet6_ntoa ( net_addr );
943 }
944 
945 /**
946  * Transcribe IPv6 socket address
947  *
948  * @v sa Socket address
949  * @ret string Socket address in standard notation
950  */
951 static const char * ipv6_sock_ntoa ( struct sockaddr *sa ) {
952  static char buf[ 39 /* "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" */ +
953  1 /* "%" */ + NETDEV_NAME_LEN + 1 /* NUL */ ];
954  struct sockaddr_in6 *sin6 = ( ( struct sockaddr_in6 * ) sa );
955  struct in6_addr *in = &sin6->sin6_addr;
956  struct net_device *netdev;
957  const char *netdev_name;
958 
959  /* Identify network device, if applicable */
962  netdev_name = ( netdev ? netdev->name : "UNKNOWN" );
963  } else {
964  netdev_name = NULL;
965  }
966 
967  /* Format socket address */
968  snprintf ( buf, sizeof ( buf ), "%s%s%s", inet6_ntoa ( in ),
969  ( netdev_name ? "%" : "" ),
970  ( netdev_name ? netdev_name : "" ) );
971  return buf;
972 }
973 
974 /**
975  * Parse IPv6 socket address
976  *
977  * @v string Socket address string
978  * @v sa Socket address to fill in
979  * @ret rc Return status code
980  */
981 static int ipv6_sock_aton ( const char *string, struct sockaddr *sa ) {
982  struct sockaddr_in6 *sin6 = ( ( struct sockaddr_in6 * ) sa );
983  struct in6_addr in;
984  struct net_device *netdev;
985  size_t len;
986  char *tmp;
987  char *in_string;
988  char *netdev_string;
989  int rc;
990 
991  /* Create modifiable copy of string */
992  tmp = strdup ( string );
993  if ( ! tmp ) {
994  rc = -ENOMEM;
995  goto err_alloc;
996  }
997  in_string = tmp;
998 
999  /* Strip surrounding "[...]", if present */
1000  len = strlen ( in_string );
1001  if ( ( in_string[0] == '[' ) && ( in_string[ len - 1 ] == ']' ) ) {
1002  in_string[ len - 1 ] = '\0';
1003  in_string++;
1004  }
1005 
1006  /* Split at network device name, if present */
1007  netdev_string = strchr ( in_string, '%' );
1008  if ( netdev_string )
1009  *(netdev_string++) = '\0';
1010 
1011  /* Parse IPv6 address portion */
1012  if ( ( rc = inet6_aton ( in_string, &in ) ) != 0 )
1013  goto err_inet6_aton;
1014 
1015  /* Parse scope ID, if applicable */
1016  if ( netdev_string ) {
1017 
1018  /* Parse explicit network device name, if present */
1019  netdev = find_netdev ( netdev_string );
1020  if ( ! netdev ) {
1021  rc = -ENODEV;
1022  goto err_find_netdev;
1023  }
1025 
1026  } else if ( IN6_IS_ADDR_LINKLOCAL ( &in ) ||
1027  IN6_IS_ADDR_MULTICAST ( &in ) ) {
1028 
1029  /* If no network device is explicitly specified for a
1030  * link-local or multicast address, default to using
1031  * "netX" (if existent).
1032  */
1034  if ( netdev )
1036  }
1037 
1038  /* Copy IPv6 address portion to socket address */
1039  memcpy ( &sin6->sin6_addr, &in, sizeof ( sin6->sin6_addr ) );
1040 
1041  err_find_netdev:
1042  err_inet6_aton:
1043  free ( tmp );
1044  err_alloc:
1045  return rc;
1046 }
1047 
1048 /** IPv6 protocol */
1049 struct net_protocol ipv6_protocol __net_protocol = {
1050  .name = "IPv6",
1051  .net_proto = htons ( ETH_P_IPV6 ),
1052  .net_addr_len = sizeof ( struct in6_addr ),
1053  .rx = ipv6_rx,
1054  .ntoa = ipv6_ntoa,
1055 };
1056 
1057 /** IPv6 TCPIP net protocol */
1058 struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol = {
1059  .name = "IPv6",
1060  .sa_family = AF_INET6,
1061  .header_len = sizeof ( struct ipv6_header ),
1062  .net_protocol = &ipv6_protocol,
1063  .tx = ipv6_tx,
1064  .netdev = ipv6_netdev,
1065 };
1066 
1067 /** IPv6 socket address converter */
1068 struct sockaddr_converter ipv6_sockaddr_converter __sockaddr_converter = {
1069  .family = AF_INET6,
1070  .ntoa = ipv6_sock_ntoa,
1071  .aton = ipv6_sock_aton,
1072 };
1073 
1074 /**
1075  * Parse IPv6 address setting value
1076  *
1077  * @v type Setting type
1078  * @v value Formatted setting value
1079  * @v buf Buffer to contain raw value
1080  * @v len Length of buffer
1081  * @ret len Length of raw value, or negative error
1082  */
1084  const char *value, void *buf, size_t len ) {
1085  struct in6_addr ipv6;
1086  int rc;
1087 
1088  /* Parse IPv6 address */
1089  if ( ( rc = inet6_aton ( value, &ipv6 ) ) != 0 )
1090  return rc;
1091 
1092  /* Copy to buffer */
1093  if ( len > sizeof ( ipv6 ) )
1094  len = sizeof ( ipv6 );
1095  memcpy ( buf, &ipv6, len );
1096 
1097  return ( sizeof ( ipv6 ) );
1098 }
1099 
1100 /**
1101  * Format IPv6 address setting value
1102  *
1103  * @v type Setting type
1104  * @v raw Raw setting value
1105  * @v raw_len Length of raw setting value
1106  * @v buf Buffer to contain formatted value
1107  * @v len Length of buffer
1108  * @ret len Length of formatted value, or negative error
1109  */
1111  const void *raw, size_t raw_len, char *buf,
1112  size_t len ) {
1113  const struct in6_addr *ipv6 = raw;
1114 
1115  if ( raw_len < sizeof ( *ipv6 ) )
1116  return -EINVAL;
1117  return snprintf ( buf, len, "%s", inet6_ntoa ( ipv6 ) );
1118 }
1119 
1120 /** IPv6 settings scope */
1122 
1123 /** IPv6 address setting */
1124 const struct setting ip6_setting __setting ( SETTING_IP6, ip6 ) = {
1125  .name = "ip6",
1126  .description = "IPv6 address",
1127  .type = &setting_type_ipv6,
1128  .scope = &ipv6_settings_scope,
1129 };
1130 
1131 /** IPv6 prefix length setting */
1132 const struct setting len6_setting __setting ( SETTING_IP6, len6 ) = {
1133  .name = "len6",
1134  .description = "IPv6 prefix length",
1135  .type = &setting_type_int8,
1136  .scope = &ipv6_settings_scope,
1137 };
1138 
1139 /** Default gateway setting */
1140 const struct setting gateway6_setting __setting ( SETTING_IP6, gateway6 ) = {
1141  .name = "gateway6",
1142  .description = "IPv6 gateway",
1143  .type = &setting_type_ipv6,
1144  .scope = &ipv6_settings_scope,
1145 };
1146 
1147 /**
1148  * Check applicability of IPv6 link-local address setting
1149  *
1150  * @v settings Settings block
1151  * @v setting Setting to fetch
1152  * @ret applies Setting applies within this settings block
1153  */
1155  const struct setting *setting ) {
1156 
1157  return ( setting->scope == &ipv6_settings_scope );
1158 }
1159 
1160 /**
1161  * Fetch IPv6 link-local address setting
1162  *
1163  * @v settings Settings block
1164  * @v setting Setting to fetch
1165  * @v data Buffer to fill with setting data
1166  * @v len Length of buffer
1167  * @ret len Length of setting data, or negative error
1168  */
1169 static int ipv6_fetch ( struct settings *settings, struct setting *setting,
1170  void *data, size_t len ) {
1171  struct net_device *netdev =
1173  settings.settings );
1174  struct in6_addr ip6;
1175  uint8_t *len6;
1176  int prefix_len;
1177  int rc;
1178 
1179  /* Construct link-local address from EUI-64 as per RFC 2464 */
1180  memset ( &ip6, 0, sizeof ( ip6 ) );
1181  prefix_len = ipv6_link_local ( &ip6, netdev );
1182  if ( prefix_len < 0 ) {
1183  rc = prefix_len;
1184  return rc;
1185  }
1186 
1187  /* Handle setting */
1188  if ( setting_cmp ( setting, &ip6_setting ) == 0 ) {
1189 
1190  /* Return link-local ip6 */
1191  if ( len > sizeof ( ip6 ) )
1192  len = sizeof ( ip6 );
1193  memcpy ( data, &ip6, len );
1194  return sizeof ( ip6 );
1195 
1196  } else if ( setting_cmp ( setting, &len6_setting ) == 0 ) {
1197 
1198  /* Return prefix length */
1199  if ( len ) {
1200  len6 = data;
1201  *len6 = prefix_len;
1202  }
1203  return sizeof ( *len6 );
1204 
1205  }
1206 
1207  return -ENOENT;
1208 }
1209 
1210 /** IPv6 link-local address settings operations */
1212  .applies = ipv6_applies,
1213  .fetch = ipv6_fetch,
1214 };
1215 
1216 /**
1217  * Register IPv6 link-local address settings
1218  *
1219  * @v netdev Network device
1220  * @v priv Private data
1221  * @ret rc Return status code
1222  */
1223 static int ipv6_register_settings ( struct net_device *netdev, void *priv ) {
1224  struct settings *parent = netdev_settings ( netdev );
1225  struct settings *settings = priv;
1226  int rc;
1227 
1228  /* Initialise and register settings */
1232  if ( ( rc = register_settings ( settings, parent,
1233  IPV6_SETTINGS_NAME ) ) != 0 )
1234  return rc;
1235 
1236  return 0;
1237 }
1238 
1239 /** IPv6 network device driver */
1240 struct net_driver ipv6_driver __net_driver = {
1241  .name = "IPv6",
1242  .priv_len = sizeof ( struct settings ),
1243  .probe = ipv6_register_settings,
1244 };
1245 
1246 /**
1247  * Create IPv6 routing table based on configured settings
1248  *
1249  * @v netdev Network device
1250  * @v settings Settings block
1251  * @ret rc Return status code
1252  */
1253 static int ipv6_create_routes ( struct net_device *netdev,
1254  struct settings *settings ) {
1255  struct settings *child;
1256  struct settings *origin;
1257  struct in6_addr ip6_buf;
1258  struct in6_addr gateway6_buf;
1259  struct in6_addr *ip6 = &ip6_buf;
1260  struct in6_addr *gateway6 = &gateway6_buf;
1261  uint8_t len6;
1262  size_t len;
1263  int rc;
1264 
1265  /* First, create routing table for any child settings. We do
1266  * this depth-first and in reverse order so that the end
1267  * result reflects the relative priorities of the settings
1268  * blocks.
1269  */
1270  list_for_each_entry_reverse ( child, &settings->children, siblings )
1271  ipv6_create_routes ( netdev, child );
1272 
1273  /* Fetch IPv6 address, if any */
1275  ip6, sizeof ( *ip6 ) );
1276  if ( ( len != sizeof ( *ip6 ) ) || ( origin != settings ) )
1277  return 0;
1278 
1279  /* Fetch prefix length, if defined */
1281  &len6, sizeof ( len6 ) );
1282  if ( ( len != sizeof ( len6 ) ) || ( origin != settings ) )
1283  len6 = 0;
1284  if ( len6 > IPV6_MAX_PREFIX_LEN )
1285  len6 = IPV6_MAX_PREFIX_LEN;
1286 
1287  /* Fetch gateway, if defined */
1289  gateway6, sizeof ( *gateway6 ) );
1290  if ( ( len != sizeof ( *gateway6 ) ) || ( origin != settings ) )
1291  gateway6 = NULL;
1292 
1293  /* Create or update route */
1294  if ( ( rc = ipv6_add_miniroute ( netdev, ip6, len6, gateway6 ) ) != 0){
1295  DBGC ( netdev, "IPv6 %s could not add route: %s\n",
1296  netdev->name, strerror ( rc ) );
1297  return rc;
1298  }
1299 
1300  return 0;
1301 }
1302 
1303 /**
1304  * Create IPv6 routing table based on configured settings
1305  *
1306  * @ret rc Return status code
1307  */
1308 static int ipv6_create_all_routes ( void ) {
1309  struct ipv6_miniroute *miniroute;
1310  struct ipv6_miniroute *tmp;
1311  struct net_device *netdev;
1312  struct settings *settings;
1313  int rc;
1314 
1315  /* Delete all existing routes */
1316  list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list )
1317  ipv6_del_miniroute ( miniroute );
1318 
1319  /* Create routes for each configured network device */
1320  for_each_netdev ( netdev ) {
1322  if ( ( rc = ipv6_create_routes ( netdev, settings ) ) != 0 )
1323  return rc;
1324  }
1325 
1326  return 0;
1327 }
1328 
1329 /** IPv6 settings applicator */
1330 struct settings_applicator ipv6_settings_applicator __settings_applicator = {
1332 };
1333 
1334 /* Drag in objects via ipv6_protocol */
1335 REQUIRING_SYMBOL ( ipv6_protocol );
1336 
1337 /* Drag in ICMPv6 */
1338 REQUIRE_OBJECT ( icmpv6 );
1339 
1340 /* Drag in NDP */
1341 REQUIRE_OBJECT ( ndp );
#define LL_MULTICAST
Packet is a multicast (including broadcast) packet.
Definition: netdevice.h:106
#define IPV6_DEFAULT_PREFIX_LEN
IPv6 default prefix length.
Definition: ipv6.h:30
static int ipv6_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of IPv6 link-local address setting.
Definition: ipv6.c:1154
#define iob_pull(iobuf, len)
Definition: iobuf.h:107
#define __attribute__(x)
Definition: compiler.h:10
static struct ip_statistics ipv6_stats
IPv6 statistics.
Definition: ipv6.c:64
#define EINVAL
Invalid argument.
Definition: errno.h:429
TCP/IP socket address.
Definition: tcpip.h:76
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned short uint16_t
Definition: stdint.h:11
IPv6 header.
Definition: ipv6.h:36
const char * name
Protocol name.
Definition: netdevice.h:67
#define ENOTSUP_OPT
Definition: ipv6.c:56
uint64_t origin
Origin.
Definition: hyperv.h:20
#define AF_INET6
IPv6 Internet addresses.
Definition: socket.h:65
unsigned long in_receives
ipSystemStatsInReceives
Definition: ipstat.h:51
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:485
struct in6_addr src
Source address.
Definition: ipv6.h:151
Link-local address.
Definition: ipv6.h:285
__be32 in[4]
Definition: CIB_PRM.h:35
Global address scope.
Definition: ipv6.h:175
An IP system statistics family.
Definition: ipstat.h:170
char * inet6_ntoa(const struct in6_addr *in)
Convert IPv6 address to standard notation.
Definition: ipv6.c:895
struct net_protocol ipv6_protocol __net_protocol
IPv6 protocol.
Definition: ipv6.c:1049
#define TCPIP_EMPTY_CSUM
Empty checksum value.
Definition: tcpip.h:58
#define list_add(new, head)
Add a new entry to the head of a list.
Definition: list.h:70
static struct net_device * ipv6_netdev(struct sockaddr_tcpip *st_dest)
Determine transmitting network device.
Definition: ipv6.c:384
static int ipv6_sock_aton(const char *string, struct sockaddr *sa)
Parse IPv6 socket address.
Definition: ipv6.c:981
Error codes.
IPv6 option-based extension header.
Definition: ipv6.h:81
struct in_addr src
Definition: ip.h:45
#define ENOTSUP_VER
Definition: ipv6.c:50
IPv6 hop-by-hop options header type.
Definition: ipv6.h:137
unsigned long in_addr_errors
ipSystemStatsInAddrErrors
Definition: ipstat.h:77
struct settings * parent
Parent settings block.
Definition: settings.h:139
uint8_t scope
Scope.
Definition: ena.h:18
#define iob_push(iobuf, len)
Definition: iobuf.h:89
int tcpip_rx(struct io_buffer *iobuf, struct net_device *netdev, uint8_t tcpip_proto, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum, struct ip_statistics *stats)
Process a received TCP/IP packet.
Definition: tcpip.c:41
struct ipv6_miniroute * ipv6_route(unsigned int scope_id, struct in6_addr **dest)
Perform IPv6 routing.
Definition: ipv6.c:308
#define IPV6_MAX_PREFIX_LEN
IPv6 maximum prefix length.
Definition: ipv6.h:33
I/O buffers.
A fragment reassembly buffer.
Definition: fragment.h:22
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
static unsigned int ipv6_scope(const struct in6_addr *addr)
Determine IPv6 address scope.
Definition: ipv6.c:89
uint64_t address
Base address.
Definition: ena.h:24
FILE_SECBOOT(PERMITTED)
uint32_t type
Operating system type.
Definition: ena.h:12
#define sprintf(buf, fmt,...)
Write a formatted string to a buffer.
Definition: stdio.h:37
Link-local address scope.
Definition: ipv6.h:167
static int ipv6_rx(struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, const void *ll_source __unused, unsigned int flags __unused)
Process incoming IPv6 packets.
Definition: ipv6.c:650
#define IN6_IS_ADDR_SITELOCAL(addr)
Definition: in.h:75
#define EPIPE
Broken pipe.
Definition: errno.h:620
uint8_t tcpip_proto
Transport-layer protocol number.
Definition: tcpip.h:135
#define IPV6_CAN_IGNORE_OPT(type)
Test if IPv6 option can be safely ignored.
Definition: ipv6.h:78
#define DBGC(...)
Definition: compiler.h:505
static uint32_t ipv6col(struct in6_addr *in)
Determine debugging colour for IPv6 debug messages.
Definition: ipv6.c:79
struct sockaddr_in6 sin6
Definition: syslog.c:60
static uint16_t ipv6_pshdr_chksum(struct ipv6_header *iphdr, size_t len, int next_header, uint16_t csum)
Calculate IPv6 pseudo-header checksum.
Definition: ipv6.c:497
IPv6 type-length-value options.
Definition: ipv6.h:60
#define ENOENT
No such file or directory.
Definition: errno.h:515
int ipv6_add_miniroute(struct net_device *netdev, struct in6_addr *address, unsigned int prefix_len, struct in6_addr *router)
Add IPv6 routing table entry.
Definition: ipv6.c:218
int parse_ipv6_setting(const struct setting_type *type __unused, const char *value, void *buf, size_t len)
Parse IPv6 address setting value.
Definition: ipv6.c:1083
static int ipv6_register_settings(struct net_device *netdev, void *priv)
Register IPv6 link-local address settings.
Definition: ipv6.c:1223
IPv6 destination options header type.
Definition: ipv6.h:145
uint32_t string
Definition: multiboot.h:14
#define ntohl(value)
Definition: byteswap.h:135
const struct setting ip6_setting
A settings applicator.
Definition: settings.h:252
uint16_t sin6_scope_id
Scope ID (part of struct sockaddr_tcpip)
Definition: in.h:133
Pad1.
Definition: ipv6.h:72
#define ntohs(value)
Definition: byteswap.h:137
struct sockaddr_converter ipv6_sockaddr_converter __sockaddr_converter
IPv6 socket address converter.
Definition: ipv6.c:1068
IPv6 fragment header.
Definition: ipv6.h:101
static const char * ipv6_ntoa(const void *net_addr)
Transcribe IPv6 address.
Definition: ipv6.c:941
u32 pad[9]
Padding.
Definition: ar9003_mac.h:47
unsigned int flags
Flags.
Definition: ipv6.h:199
A fragment reassembler.
Definition: fragment.h:36
#define IP_STATISTICS_IPV6
Definition: ipstat.h:186
An IPv4 packet header.
Definition: ip.h:36
REQUIRING_SYMBOL(ipv6_protocol)
__be32 out[4]
Definition: CIB_PRM.h:36
#define NETDEV_NAME_LEN
Maximum length of a network device name.
Definition: netdevice.h:341
#define htonl(value)
Definition: byteswap.h:134
unsigned int scope_id
Scope ID.
Definition: netdevice.h:361
A network upper-layer driver.
Definition: netdevice.h:477
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:587
int inet6_aton(const char *string, struct in6_addr *in)
Parse IPv6 address.
Definition: ipv6.c:825
Organisation-local address scope.
Definition: ipv6.h:173
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
A doubly-linked list entry (or list head)
Definition: list.h:19
uint32_t len
Upper-layer packet length.
Definition: ipv6.h:155
An IPv6 address/routing table entry.
Definition: ipv6.h:181
static int ipv6_fetch(struct settings *settings, struct setting *setting, void *data, size_t len)
Fetch IPv6 link-local address setting.
Definition: ipv6.c:1169
const char * name
Name.
Definition: settings.h:29
u32 crc32_le(u32 seed, const void *data, size_t len)
Calculate 32-bit little-endian CRC checksum.
Definition: crc32.c:40
struct sockaddr_tcpip st
Definition: syslog.c:58
uint32_t start
Starting offset.
Definition: netvsc.h:12
struct in6_addr router
Router address.
Definition: ipv6.h:195
unsigned long tmp
Definition: linux_pci.h:65
static int ipv6_is_fragment(struct fragment *fragment, struct io_buffer *iobuf, size_t hdrlen)
Check if fragment matches fragment reassembly buffer.
Definition: ipv6.c:436
const struct setting ip6_setting __setting(SETTING_IP6, ip6)
IPv6 address setting.
#define list_del(list)
Delete an entry from a list.
Definition: list.h:120
void ipv6_del_miniroute(struct ipv6_miniroute *miniroute)
Delete IPv6 minirouting table entry.
Definition: ipv6.c:293
#define ENOMEM
Not enough space.
Definition: errno.h:535
void * memcpy(void *dest, const void *src, size_t len) __nonnull
const char * name
Name.
Definition: netdevice.h:479
IP statistics.
const struct setting gateway6_setting
unsigned long in_mcast_pkts
ipSystemStatsInMcastPkts
Definition: ipstat.h:151
static int netdev_is_open(struct net_device *netdev)
Check whether or not network device is open.
Definition: netdevice.h:662
const struct setting len6_setting
unsigned int version
IP version.
Definition: ipstat.h:172
unsigned int scope
Scope.
Definition: ipv6.h:197
#define MAX_LL_ADDR_LEN
Maximum length of a link-layer address.
Definition: netdevice.h:37
Assertions.
IPv6 fragment header type.
Definition: ipv6.h:141
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
struct io_buffer * fragment_reassemble(struct fragment_reassembler *fragments, struct io_buffer *iobuf, size_t *hdrlen)
Reassemble packet.
Definition: fragment.c:89
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
unsigned long out_no_routes
ipSystemStatsOutNoRoutes
Definition: ipstat.h:131
Socket address converter.
Definition: socket.h:116
IPv6 extension header.
Definition: ipv6.h:117
static const void * src
Definition: string.h:48
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
static struct fragment_reassembler ipv6_reassembler
Fragment reassembler.
Definition: ipv6.c:480
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
#define DBGC_HDA(...)
Definition: compiler.h:506
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
uint16_t len
Definition: ip.h:39
struct in6_addr dest
Destination address.
Definition: ipv6.h:153
static int ipv6_create_all_routes(void)
Create IPv6 routing table based on configured settings.
Definition: ipv6.c:1308
ring len
Length.
Definition: dwmac.h:231
#define IPV6_SETTINGS_NAME
IPv6 link-local address settings block name.
Definition: ipv6.h:293
#define list_for_each_entry_reverse(pos, head, member)
Iterate over entries in a list in reverse order.
Definition: list.h:445
IPv6 pseudo-header.
Definition: ipv6.h:149
static size_t ipv6_fragment_offset(struct io_buffer *iobuf, size_t hdrlen)
Get fragment offset.
Definition: ipv6.c:458
unsigned long in_truncated_pkts
ipSystemStatsInTruncatedPkts
Definition: ipstat.h:90
static struct net_device * netdev
Definition: gdbudp.c:53
struct net_device * last_opened_netdev(void)
Get most recently opened network device.
Definition: netdevice.c:1048
struct sockaddr sa
Definition: syslog.c:57
struct io_buffer * iobuf
Reassembled packet.
Definition: fragment.h:26
Transport-network layer interface.
char * strcpy(char *dest, const char *src)
Copy string.
Definition: string.c:347
#define IPV6_HOP_LIMIT
IPv6 maximum hop limit.
Definition: ipv6.h:27
struct list_head list
List of miniroutes.
Definition: ipv6.h:183
IP6 address structure.
Definition: in.h:51
IPv6 routing header type.
Definition: ipv6.h:139
#define IN6_IS_ADDR_LINKLOCAL(addr)
Definition: in.h:71
#define IN6_IS_ADDR_UNSPECIFIED(addr)
Definition: in.h:62
IP system statistics.
Definition: ipstat.h:45
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition: list.h:459
static size_t raw_len
Definition: base16.h:54
Generalized socket address structure.
Definition: socket.h:97
#define iob_unput(iobuf, len)
Definition: iobuf.h:140
int fetch_setting(struct settings *settings, const struct setting *setting, struct settings **origin, struct setting *fetched, void *data, size_t len)
Fetch setting.
Definition: settings.c:667
uint8_t flags
Flags.
Definition: ena.h:18
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
struct refcnt refcnt
Reference counter.
Definition: netdevice.h:355
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
#define for_each_netdev(netdev)
Iterate over all network devices.
Definition: netdevice.h:547
char * strchr(const char *src, int character)
Find character within a string.
Definition: string.c:272
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
#define IPV6_MASK_VER
IPv6 version mask.
Definition: ipv6.h:24
uint32_t addr
Buffer address.
Definition: dwmac.h:20
char * strdup(const char *src)
Duplicate string.
Definition: string.c:394
A network device.
Definition: netdevice.h:353
static struct settings_operations ipv6_settings_operations
IPv6 link-local address settings operations.
Definition: ipv6.c:1211
struct list_head ipv6_miniroutes
List of IPv6 miniroutes.
Definition: ipv6.c:61
#define ENODEV
No such device.
Definition: errno.h:510
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
struct net_driver ipv6_driver __net_driver
IPv6 network device driver.
Definition: ipv6.c:1240
Settings block operations.
Definition: settings.h:86
A settings block.
Definition: settings.h:133
unsigned char uint8_t
Definition: stdint.h:10
sa_family_t family
Socket address family.
Definition: socket.h:121
unsigned long out_mcast_pkts
ipSystemStatsOutMcastPkts
Definition: ipstat.h:156
A setting scope.
Definition: settings.h:177
struct net_device * netdev
Network device.
Definition: ipv6.h:186
static struct net_device * netdev_get(struct net_device *netdev)
Get reference to network device.
Definition: netdevice.h:565
struct in_addr dest
Definition: ip.h:46
static const char * ipv6_sock_ntoa(struct sockaddr *sa)
Transcribe IPv6 socket address.
Definition: ipv6.c:951
static int ndp_tx(struct io_buffer *iobuf, struct net_device *netdev, const void *net_dest, const void *net_source)
Transmit packet, determining link-layer address via NDP.
Definition: ndp.h:195
static void ipv6_dump_miniroute(struct ipv6_miniroute *miniroute)
Dump IPv6 routing table entry.
Definition: ipv6.c:123
#define EINVAL_LEN
Definition: ipv6.c:47
unsigned int uint32_t
Definition: stdint.h:12
Site-local address scope.
Definition: ipv6.h:171
IPv6 protocol.
struct net_device * find_netdev_by_scope_id(unsigned int scope_id)
Get network device by scope ID.
Definition: netdevice.c:1011
int(* mc_hash)(unsigned int af, const void *net_addr, void *ll_addr)
Hash multicast address.
Definition: netdevice.h:173
struct settings_applicator ipv6_settings_applicator __settings_applicator
IPv6 settings applicator.
Definition: ipv6.c:1330
void * memmove(void *dest, const void *src, size_t len) __nonnull
A setting.
Definition: settings.h:24
static int ipv6_more_fragments(struct io_buffer *iobuf, size_t hdrlen)
Check if more fragments exist.
Definition: ipv6.c:472
static int ipv6_check_options(struct ipv6_header *iphdr, struct ipv6_options_header *options, size_t len)
Check that received options can be safely ignored.
Definition: ipv6.c:405
uint16_t ext
Extended status.
Definition: ena.h:20
#define LL_BROADCAST
Packet is a broadcast packet.
Definition: netdevice.h:109
A network-layer protocol.
Definition: netdevice.h:65
static unsigned int ipv6_match_len(struct ipv6_miniroute *miniroute, struct in6_addr *address)
Count matching bits of an IPv6 routing table entry prefix.
Definition: ipv6.c:164
A transport-layer protocol of the TCP/IP stack (eg.
Definition: tcpip.h:105
static int ipv6_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 IPv6 packet.
Definition: ipv6.c:526
long pad_len
Definition: bigint.h:31
uint16_t zero_csum
Preferred zero checksum value.
Definition: tcpip.h:129
static int ipv6_create_routes(struct net_device *netdev, struct settings *settings)
Create IPv6 routing table based on configured settings.
Definition: ipv6.c:1253
#define IPV6_VER
IPv6 version.
Definition: ipv6.h:21
int order
Sibling ordering.
Definition: settings.h:149
int format_ipv6_setting(const struct setting_type *type __unused, const void *raw, size_t raw_len, char *buf, size_t len)
Format IPv6 address setting value.
Definition: ipv6.c:1110
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:363
int net_tx(struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest, const void *ll_source)
Transmit network-layer packet.
Definition: netdevice.c:1074
#define DBGC2(...)
Definition: compiler.h:522
static struct tlan_private * priv
Definition: tlan.c:225
struct net_device * find_netdev(const char *name)
Get network device by name.
Definition: netdevice.c:989
unsigned long out_requests
ipSystemStatsOutRequests
Definition: ipstat.h:124
void * data
Start of data.
Definition: iobuf.h:53
#define IPV6_MASK_MOREFRAGS
More fragments.
Definition: ipv6.h:114
u8 rx[WPA_TKIP_MIC_KEY_LEN]
MIC key for packets from the AP.
Definition: wpa.h:234
struct in6_addr src
Source address.
Definition: ipv6.h:46
Routing table entry address is valid.
Definition: ipv6.h:205
unsigned short word
Definition: smc9000.h:39
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" return dest
Definition: string.h:151
uint32_t end
Ending offset.
Definition: netvsc.h:18
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
#define IN6_IS_ADDR_MULTICAST(addr)
Definition: in.h:68
Neighbour discovery protocol.
static int ipv6_link_local(struct in6_addr *addr, struct net_device *netdev)
Construct link-local address via EUI-64.
Definition: ipv6.h:236
__be32 raw[7]
Definition: CIB_PRM.h:28
Routing table entry router address is valid.
Definition: ipv6.h:207
Maximum scope.
Definition: ipv6.h:177
IPv6 socket address.
Definition: in.h:118
int(* apply)(void)
Apply updated settings.
Definition: settings.h:257
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:383
int(* applies)(struct settings *settings, const struct setting *setting)
Check applicability of setting.
Definition: settings.h:99
struct list_head children
Child settings blocks.
Definition: settings.h:143
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition: settings.c:476
#define IPV6_MASK_OFFSET
Fragment offset mask.
Definition: ipv6.h:111
#define IN6_IS_ADDR_ULA(addr)
Definition: in.h:79
A network-layer protocol of the TCP/IP stack (eg.
Definition: tcpip.h:141
#define ETH_P_IPV6
Definition: if_ether.h:23
#define flsl(x)
Find last (i.e.
Definition: strings.h:158
FILE_LICENCE(GPL2_OR_LATER)
unsigned int prefix_len
Prefix length.
Definition: ipv6.h:191
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
#define SETTING_IP6
IPv6 settings.
Definition: settings.h:68
uint8_t zero[3]
Zero padding.
Definition: ipv6.h:157
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define LIST_HEAD_INIT(list)
Initialise a static list head.
Definition: list.h:31
const struct settings_scope * scope
Setting scope (or NULL)
Definition: settings.h:50
uint32_t ident
Identification.
Definition: ipv6.h:107
uint16_t offset_more
Fragment offset (13 bits), reserved, more fragments (1 bit)
Definition: ipv6.h:105
Fragment reassembly.
uint8_t next_header
Next header.
Definition: ipv6.h:159
#define ENETUNREACH
Network unreachable.
Definition: errno.h:489
unsigned long in_hdr_errors
ipSystemStatsInHdrErrors
Definition: ipstat.h:66
struct ip_statistics_family ipv6_statistics_family __ip_statistics_family(IP_STATISTICS_IPV6)
IPv6 statistics family.
int setting_cmp(const struct setting *a, const struct setting *b)
Compare two settings.
Definition: settings.c:1121
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:115
const char * name
Protocol name.
Definition: tcpip.h:143
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
struct in6_addr address
IPv6 address (or prefix if no address is defined)
Definition: ipv6.h:189
unsigned long in_bcast_pkts
ipSystemStatsInBcastPkts
Definition: ipstat.h:161
#define htons(value)
Definition: byteswap.h:136
static struct ipv6_miniroute * ipv6_miniroute(struct net_device *netdev, struct in6_addr *address)
Find IPv6 routing table entry for a given address.
Definition: ipv6.c:193
struct in6_addr prefix_mask
IPv6 prefix mask (derived from prefix length)
Definition: ipv6.h:193
A setting type.
Definition: settings.h:192
unsigned long out_octets
ipSystemStatsOutOctets
Definition: ipstat.h:146
uint16_t tcpip_continue_chksum(uint16_t partial, const void *data, size_t len)
Calculate continued TCP/IP checkum.
Definition: x86_tcpip.c:46
struct in6_addr sin6_addr
IPv6 address.
Definition: in.h:135
struct ll_protocol * ll_protocol
Link-layer protocol.
Definition: netdevice.h:373
unsigned long out_transmits
ipSystemStatsOutTransmits
Definition: ipstat.h:139
REQUIRE_OBJECT(icmpv6)
static unsigned int ipv6_multicast_scope(const struct in6_addr *addr)
Get multicast address scope.
Definition: ipv6.h:275
String functions.
unsigned long in_octets
ipSystemStatsInOctets
Definition: ipstat.h:58
struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol
IPv6 TCPIP net protocol.
Definition: ipv6.c:1058
struct list_head list
List of fragment reassembly buffers.
Definition: fragment.h:38
void * memset(void *dest, int character, size_t len) __nonnull
A persistent I/O buffer.
Definition: iobuf.h:38
size_t hdrlen
Length of non-fragmentable portion of reassembled packet.
Definition: fragment.h:28